~chaffra/+junk/trilinos

« back to all changes in this revision

Viewing changes to packages/Sundance/commonTools/buildTools/MakefileVariables.py

  • Committer: Bazaar Package Importer
  • Author(s): Christophe Prud'homme, Christophe Prud'homme, Johannes Ring
  • Date: 2009-12-13 12:53:22 UTC
  • mfrom: (5.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20091213125322-in0nrdjc55deqsw9
Tags: 10.0.3.dfsg-1
[Christophe Prud'homme]
* New upstream release

[Johannes Ring]
* debian/patches/libname.patch: Add prefix 'libtrilinos_' to all
  libraries. 
* debian/patches/soname.patch: Add soversion to libraries.
* debian/watch: Update download URL.
* debian/control:
  - Remove python-numeric from Build-Depends (virtual package).
  - Remove automake and autotools from Build-Depends and add cmake to
    reflect switch to CMake.
  - Add python-support to Build-Depends.
* debian/rules: 
  - Cleanup and updates for switch to CMake.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#! /usr/bin/env python
 
2
 
 
3
"""
 
4
MakefileVariables.py - This script can be run as a shell command or imported as
 
5
a module into a python script.  Its purpose is to read a Makefile and obtain a
 
6
map of make variables and their values.
 
7
 
 
8
Shell usage: MakefileVariables.py [options] [filename]
 
9
 
 
10
options:
 
11
    -h | --help       Print this message and exit
 
12
    -m | --make       Output in Makefile format
 
13
    -p | --python     Output as a python dictionary (default)
 
14
    -v | --version    Print the version number and exit
 
15
 
 
16
Python usage: import MakefileVariables
 
17
 
 
18
Available functions:
 
19
 
 
20
    processMakefile(string) -> dict
 
21
        Given the name of a Makefile, parse the file for make variable names and
 
22
        values, make substitutions wherever '$(...)' is found in the values, and 
 
23
        then uniquify the resulting values.
 
24
 
 
25
    parseMakefile(string) -> dict
 
26
        Open filename and obtain make variable names and their raw (unevaluated)
 
27
        values.
 
28
 
 
29
    evaluate(string,dict) -> string
 
30
        Substitute variable values in dict for $(...) in string.
 
31
 
 
32
    makeSubstitutions(dict) -> None
 
33
        Interpret dict as varName/value pairs; wherever '$(...)' appears in
 
34
        values, make appropriate substitutions.
 
35
 
 
36
    uniqiufyList([string1, string2, ...], bool=False) -> None
 
37
        Remove duplicate strings from the list.
 
38
 
 
39
    uniquifyString(string, bool=False) -> string
 
40
        Remove duplicate substrings from the string.
 
41
 
 
42
    uniquifyDict(dict, bool=False) -> None
 
43
        Uniquify each value of the given dictionary.
 
44
 
 
45
    findBlock(string,int=0) -> (int,int)
 
46
        Search string to find an open delimeter and return its index as the
 
47
        first int.  Search for the corresponding closing delimeter and return
 
48
        its index as the second int.  Be smart about nested blocks.  Start
 
49
        search from optional int argument.
 
50
 
 
51
    joinContinuationLines([string, string, ...]) -> None
 
52
        Combine any strings that end with '\' with its following string.
 
53
 
 
54
    isNotBlankLine(string) -> bool
 
55
        Return True if string is not blank.
 
56
 
 
57
    specialNormPath(string) -> string
 
58
        Normalize a path, even if it starts with -I, -L, etc.
 
59
"""
 
60
 
 
61
__version__ = "1.2"
 
62
__author__  = "Bill Spotz"
 
63
__date__    = "Sep 10 2005"
 
64
 
 
65
# Import python modules for command-line options, the operating system, regular
 
66
# expressions, and system functions
 
67
import commands
 
68
from   getopt import *
 
69
import os
 
70
import re
 
71
import sys
 
72
 
 
73
# Define regular expressions for Makefile assignments, blank line, continuation
 
74
# lines, include statements and variable references
 
75
assignRE   = re.compile(r"^\s*([A-Za-z_][A-Za-z_0-9]*)\s*=\s*(.*)$")
 
76
blankRE    = re.compile(r"^\s*$"                                   )
 
77
continueRE = re.compile(r"(.*)\\\s*$"                              )
 
78
includeRE  = re.compile(r"\s*include\s+(.+)"                       )
 
79
makeVarRE  = re.compile(r"\$\(([A-Za-z_][A-Za-z0-9_]*)\)"          )
 
80
shellRE    = re.compile(r"\$\(shell"                               )
 
81
 
 
82
#############################################################################
 
83
 
 
84
def findBlock(text, pos=0):
 
85
    """Given the input text (potentially multiline) and an optional pos marking
 
86
    the starting position, find an opening delimeter -- either (, [, {, single
 
87
    quote, or double quote -- and return a tuple of integers indicating the
 
88
    character indexes of the text block -- closed with ), ], }, single quote, or
 
89
    double quote, respectively -- while correctly handling nested blocks."""
 
90
 
 
91
    # Define delimeter strings
 
92
    quote1Delimeter = "'"
 
93
    quote2Delimeter = '"'
 
94
    openDelimeters  = "\(\[\{"
 
95
    closeDelimeters = "\)\]\}"
 
96
 
 
97
    # Define delimeter regular expressions
 
98
    quote1RE = re.compile("([" + quote1Delimeter + "])", re.M)
 
99
    quote2RE = re.compile("([" + quote2Delimeter + "])", re.M)
 
100
    openRE   = re.compile("([" + openDelimeters  +
 
101
                                 quote1Delimeter +
 
102
                                 quote2Delimeter + "])", re.M)
 
103
    anyRE    = re.compile("([" + openDelimeters  +
 
104
                                 quote1Delimeter +
 
105
                                 quote2Delimeter +
 
106
                                 closeDelimeters + "])", re.M)
 
107
 
 
108
    # Find the first opening delimeter
 
109
    matchObject = openRE.search(text, pos)
 
110
    if not matchObject: return (None, None)
 
111
 
 
112
    # Initialize the loop
 
113
    stack = [ matchObject.group() ]
 
114
    start = matchObject.start()
 
115
    pos   = start + 1
 
116
 
 
117
    # Find the end of the block
 
118
    while matchObject:
 
119
 
 
120
        # Determine the active delimeter regular expression
 
121
        if   stack[-1] == quote1Delimeter:
 
122
            activeRE = quote1RE
 
123
        elif stack[-1] == quote2Delimeter:
 
124
            activeRE = quote2RE
 
125
        else:
 
126
            activeRE = anyRE
 
127
 
 
128
        # Search for the next delimeter
 
129
        matchObject = activeRE.search(text, pos)
 
130
        if matchObject:
 
131
            delimeter = matchObject.group()
 
132
            pos       = matchObject.end()
 
133
 
 
134
            # Check for matched delimeters
 
135
            if (((stack[-1] == quote1Delimeter) and
 
136
                 (delimeter == quote1Delimeter)) or
 
137
                ((stack[-1] == quote2Delimeter) and
 
138
                 (delimeter == quote2Delimeter)) or
 
139
                ((stack[-1] == "("            ) and
 
140
                 (delimeter == ")"            )) or
 
141
                ((stack[-1] == "["            ) and
 
142
                 (delimeter == "]"            )) or
 
143
                ((stack[-1] == "{"            ) and
 
144
                 (delimeter == "}"            ))   ):
 
145
                stack.pop()                  # Remove the last element from the list
 
146
                if len(stack) == 0:
 
147
                    return (start, pos)
 
148
 
 
149
            # Process unmatched delimeter
 
150
            else:
 
151
                if (delimeter in openDelimeters  or
 
152
                    delimeter == quote1Delimeter or
 
153
                    delimeter == quote2Delimeter   ):
 
154
                    stack.append(delimeter)  # Add the delimeter to the stack
 
155
                else:
 
156
                    raise RuntimeError, "findBlock: mismatched delimeters: " + \
 
157
                          stack[-1] + " " + delimeter
 
158
 
 
159
    # We made it through all of text without finding the end of the block
 
160
    raise RuntimeError, "findBlock: open block: " + join(stack)
 
161
 
 
162
#############################################################################
 
163
 
 
164
def joinContinuationLines(lines):
 
165
    """Given lines, a list of strings, check for the continuation character
 
166
    ('\') at the end of each line.  If found, combine the appropriate strings
 
167
    into one, leaving blank lines in the list to avoid duplication."""
 
168
    for i in range(len(lines)-1):
 
169
        line = lines[i]
 
170
        match = continueRE.search(line)
 
171
        if match:
 
172
            lines[i+1] = match.group(1) + lines[i+1]
 
173
            lines[i  ] = ""
 
174
 
 
175
#############################################################################
 
176
 
 
177
def isNotBlankLine(s):
 
178
    """Return True if a string is not a blank line"""
 
179
    if blankRE.match(s):
 
180
        return False
 
181
    return True
 
182
 
 
183
#############################################################################
 
184
 
 
185
def parseMakefile(filename):
 
186
    """Open filename, read in the text and return a dictionary of make variable
 
187
    names and values.  If an include statement is found, this routine will be
 
188
    called recursively."""
 
189
    lines = open(filename,"r").readlines()     # Read in the lines of the Makefile
 
190
    lines = [s.split("#")[0] for s in lines]   # Remove all comments
 
191
    joinContinuationLines(lines)               # Remove continuation lines
 
192
    lines = filter(isNotBlankLine, lines)      # Remove all blank lines
 
193
    dict = { }
 
194
    for line in lines:
 
195
        # Process include statements
 
196
        match = includeRE.match(line)
 
197
        if match:
 
198
            files = evaluate(match.group(1),dict).split()
 
199
            for file in files:
 
200
                try:
 
201
                    dict.update(parseMakefile(file))
 
202
                except IOError:
 
203
                    pass
 
204
            continue
 
205
        # Process assignment statements
 
206
        match = assignRE.match(line)
 
207
        if match:
 
208
            dict[match.group(1).strip()] = match.group(2).strip()
 
209
    return dict
 
210
 
 
211
#############################################################################
 
212
 
 
213
def evaluate(value, dict):
 
214
    """Evaluate the string 'value' by applying the following algorithm: if value
 
215
    contains substring '$(VARNAME)' and dict has key VARNAME, substitute
 
216
    dict[VARNAME] for the variable reference.  If VARNAME is not a key for the
 
217
    dictionary, substitute the null string.  If value contains substring
 
218
    '$(shell ...)', then call this routine recursively on the obtained command
 
219
    string.  If the resulting command string is unchanged, execute it as a shell
 
220
    command and substitutue the results.  Return the evaluated string."""
 
221
 
 
222
    # Initialize
 
223
    originalValue = value
 
224
    pos           = len(value)
 
225
    debug = "shell perl" in value
 
226
 
 
227
    # Evaluate $(VARNAME)
 
228
    match = makeVarRE.search(value)
 
229
    if match:
 
230
        subVarName = match.group(1)
 
231
        start      = match.start(1)-2
 
232
        end        = match.end(1)  +1
 
233
        if subVarName in dict.keys():
 
234
            subValue = dict[subVarName]
 
235
        else:
 
236
            subValue = ""
 
237
        value = value[:start] + subValue + value[end:]
 
238
    else:
 
239
 
 
240
        # Evaluate $(shell ...)
 
241
        match = shellRE.search(value)
 
242
        if match:
 
243
            # The shellRE only matches the opening '$(shell'.  We need to find
 
244
            # the closing ')', accounting for internal parenthetical or quoted
 
245
            # blocks.
 
246
            (start,end) = findBlock(value,match.start())
 
247
            start      -= 1
 
248
            shellCmd    = value[start+8:end-1]
 
249
            newShellCmd = evaluate(shellCmd,dict)
 
250
            while newShellCmd != shellCmd:
 
251
                shellCmd    = newShellCmd
 
252
                newShellCmd = evaluate(shellCmd,dict)
 
253
            (status,subValue) = commands.getstatusoutput(shellCmd)
 
254
            if status:
 
255
                print >>sys.stderr, "WARNING: %s gives\n%s" % (shellCmd,
 
256
                                                               subValue)
 
257
                subValue = ""
 
258
            value = value[:start] + subValue + value[end:]
 
259
 
 
260
    # Are we done?
 
261
    if value == originalValue:
 
262
        return value
 
263
    else:
 
264
        return evaluate(value,dict)
 
265
 
 
266
#############################################################################
 
267
 
 
268
def makeSubstitutions(dict):
 
269
    """Loop over the items of a dictionary of variable names and string values.
 
270
    If the value contains the substring(s) '$(VARNAME)' and VARNAME is a key in
 
271
    the dictionary, then substitute the appropriate value.  If VARNAME is not a
 
272
    key in the dictionary, then substitute the null string.  For circular
 
273
    substitutions, substitute the null string."""
 
274
    for varName in dict:
 
275
        dict[varName] = evaluate(dict[varName],dict)
 
276
 
 
277
#############################################################################
 
278
 
 
279
def specialNormPath(path):
 
280
    """Apply os.path.normpath to argument path, but remove a leading option
 
281
    such as '-I' or '-L' before the call and add it back before the result is
 
282
    returned."""
 
283
    if len(path) <= 2: return path
 
284
    start = 0
 
285
    if path[0] == "-": start = 2
 
286
    return path[:start] + os.path.normpath(path[start:])
 
287
 
 
288
#############################################################################
 
289
 
 
290
def uniquifyList(list,reverse=False):
 
291
    """Remove duplicate items from a list, preserving the forward order
 
292
    (default) or reverse order if the reverse flag is set."""
 
293
    if reverse: list.reverse()
 
294
    i = 1
 
295
    while i < len(list):
 
296
        if list[i] in list[:i]:
 
297
            del list[i]
 
298
        else:
 
299
            i += 1
 
300
    if reverse: list.reverse()
 
301
 
 
302
#############################################################################
 
303
 
 
304
def uniquifyString(s, delim=' ', reverse=False):
 
305
    """Split a string using the specified delimeter, apply specialNormPath to
 
306
    each string, uniquify the resulting list (passing along the optional reverse
 
307
    flag), and return a string that joins the unique list with the same
 
308
    delimeter."""
 
309
    list = s.split(delim)
 
310
    list = [specialNormPath(path.strip()) for path in list]
 
311
    uniquifyList(list,reverse)
 
312
    return delim.join(list)
 
313
 
 
314
#############################################################################
 
315
 
 
316
def uniquifyDict(dict,reverse=False):
 
317
    """Loop over each item in a dictionary of variable names and string values
 
318
    and uniquify the string, passing along the optional reverse flag."""
 
319
    for key in dict:
 
320
        dict[key] = uniquifyString(dict[key],reverse=reverse)
 
321
 
 
322
#############################################################################
 
323
 
 
324
def processMakefile(filename):
 
325
    """Open filename, read its contents and parse it for Makefile assignments,
 
326
    creating a dictionary of variable names and string values.  Substitute
 
327
    variable values when '$(...)' appears in a string value."""
 
328
    # We want to change directories to the directory that contains the
 
329
    # Makefile.  Then, when we make substitutions, any $(shell ...) expansions
 
330
    # will be done from the assumed directory.
 
331
    cwd = os.getcwd()
 
332
    (path,name) = os.path.split(filename)
 
333
    if path: os.chdir(path)
 
334
 
 
335
    # Parse and substitute
 
336
    dict = parseMakefile(name)
 
337
    makeSubstitutions(dict)
 
338
 
 
339
    # Change directory back to prevent confusion
 
340
    os.chdir(cwd)
 
341
 
 
342
    # Remove duplicates from the dictionary values and return the dictionary
 
343
    uniquifyDict(dict)
 
344
    return dict
 
345
 
 
346
#############################################################################
 
347
 
 
348
def main():
 
349
    """This is the routine that gets called if MakefileVariable.py is invoked
 
350
    from the shell.  Process any command-line options that may be given, take
 
351
    the first argument as a filename, process it to obtain a dictionary of
 
352
    variable name/value pairs, and output the results."""
 
353
 
 
354
    # Initialization
 
355
    (progDir,progName) = os.path.split(sys.argv[0])
 
356
    options      = "hmpv"
 
357
    long_options = ["help", "make", "python", "version"]
 
358
    outStyle     = "python"
 
359
 
 
360
    # Get the options and arguemnts from the command line
 
361
    (opts,args) = getopt(sys.argv[1:], options, long_options)
 
362
 
 
363
    # Loop over options and implement
 
364
    for flag in opts:
 
365
        if flag[0] in ("-h","--help"):
 
366
            print __doc__
 
367
            sys.exit()
 
368
        elif flag[0] in ("-m", "--make"):
 
369
            outStyle = "make"
 
370
        elif flag[0] in ("-p", "--python"):
 
371
            outStyle = "python"
 
372
        elif flag[0] in ("-v", "--version"):
 
373
            print progName, __version__, __date__
 
374
            sys.exit()
 
375
        else:
 
376
            print "Unrecognized flag:", flag[0]
 
377
            print __doc__
 
378
            sys.exit()
 
379
 
 
380
    # Process the filename
 
381
    dict = processMakefile(args[0])
 
382
 
 
383
    # Output the variable names and values
 
384
    if outStyle == "make":
 
385
        keys = dict.keys()
 
386
        keys.sort()
 
387
        for key in keys:
 
388
            print key, "=", dict[key]
 
389
    elif outStyle == "python":
 
390
        print dict
 
391
 
 
392
#############################################################################
 
393
# If called from the command line, call main()
 
394
#############################################################################
 
395
 
 
396
if __name__ == "__main__":
 
397
    main()