Package SCons :: Module cpp
[hide private]
[frames] | no frames]

Source Code for Module SCons.cpp

  1  # 
  2  # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation 
  3  # 
  4  # Permission is hereby granted, free of charge, to any person obtaining 
  5  # a copy of this software and associated documentation files (the 
  6  # "Software"), to deal in the Software without restriction, including 
  7  # without limitation the rights to use, copy, modify, merge, publish, 
  8  # distribute, sublicense, and/or sell copies of the Software, and to 
  9  # permit persons to whom the Software is furnished to do so, subject to 
 10  # the following conditions: 
 11  # 
 12  # The above copyright notice and this permission notice shall be included 
 13  # in all copies or substantial portions of the Software. 
 14  # 
 15  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY 
 16  # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 
 17  # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 18  # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
 19  # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
 20  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
 21  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
 22  # 
 23   
 24  __revision__ = "src/engine/SCons/cpp.py 2928 2008/04/29 22:44:09 knight" 
 25   
 26  __doc__ = """ 
 27  SCons C Pre-Processor module 
 28  """ 
 29   
 30  import SCons.compat 
 31   
 32  import os 
 33  import re 
 34  import string 
 35   
 36  # 
 37  # First "subsystem" of regular expressions that we set up: 
 38  # 
 39  # Stuff to turn the C preprocessor directives in a file's contents into 
 40  # a list of tuples that we can process easily. 
 41  # 
 42   
 43  # A table of regular expressions that fetch the arguments from the rest of 
 44  # a C preprocessor line.  Different directives have different arguments 
 45  # that we want to fetch, using the regular expressions to which the lists 
 46  # of preprocessor directives map. 
 47  cpp_lines_dict = { 
 48      # Fetch the rest of a #if/#elif/#ifdef/#ifndef as one argument, 
 49      # separated from the keyword by white space. 
 50      ('if', 'elif', 'ifdef', 'ifndef',) 
 51                          : '\s+(.+)', 
 52   
 53      # Fetch the rest of a #import/#include/#include_next line as one 
 54      # argument, with white space optional. 
 55      ('import', 'include', 'include_next',) 
 56                          : '\s*(.+)', 
 57   
 58      # We don't care what comes after a #else or #endif line. 
 59      ('else', 'endif',)  : '', 
 60   
 61      # Fetch three arguments from a #define line: 
 62      #   1) The #defined keyword. 
 63      #   2) The optional parentheses and arguments (if it's a function-like 
 64      #      macro, '' if it's not). 
 65      #   3) The expansion value. 
 66      ('define',)         : '\s+([_A-Za-z][_A-Za-z0-9_]+)(\([^)]*\))?\s*(.*)', 
 67   
 68      # Fetch the #undefed keyword from a #undef line. 
 69      ('undef',)          : '\s+([_A-Za-z][A-Za-z0-9_]+)', 
 70  } 
 71   
 72  # Create a table that maps each individual C preprocessor directive to 
 73  # the corresponding compiled regular expression that fetches the arguments 
 74  # we care about. 
 75  Table = {} 
 76  for op_list, expr in cpp_lines_dict.items(): 
 77      e = re.compile(expr) 
 78      for op in op_list: 
 79          Table[op] = e 
 80  del e 
 81  del op 
 82  del op_list 
 83   
 84  # Create a list of the expressions we'll use to match all of the 
 85  # preprocessor directives.  These are the same as the directives 
 86  # themselves *except* that we must use a negative lookahead assertion 
 87  # when matching "if" so it doesn't match the "if" in "ifdef." 
 88  override = { 
 89      'if'                        : 'if(?!def)', 
 90  } 
 91  l = map(lambda x, o=override: o.get(x, x), Table.keys()) 
 92   
 93   
 94  # Turn the list of expressions into one big honkin' regular expression 
 95  # that will match all the preprocessor lines at once.  This will return 
 96  # a list of tuples, one for each preprocessor line.  The preprocessor 
 97  # directive will be the first element in each tuple, and the rest of 
 98  # the line will be the second element. 
 99  e = '^\s*#\s*(' + string.join(l, '|') + ')(.*)$' 
100   
101  # And last but not least, compile the expression. 
102  CPP_Expression = re.compile(e, re.M) 
103   
104   
105   
106   
107  # 
108  # Second "subsystem" of regular expressions that we set up: 
109  # 
110  # Stuff to translate a C preprocessor expression (as found on a #if or 
111  # #elif line) into an equivalent Python expression that we can eval(). 
112  # 
113   
114  # A dictionary that maps the C representation of Boolean operators 
115  # to their Python equivalents. 
116  CPP_to_Python_Ops_Dict = { 
117      '!'         : ' not ', 
118      '!='        : ' != ', 
119      '&&'        : ' and ', 
120      '||'        : ' or ', 
121      '?'         : ' and ', 
122      ':'         : ' or ', 
123      '\r'        : '', 
124  } 
125   
126  CPP_to_Python_Ops_Sub = lambda m, d=CPP_to_Python_Ops_Dict: d[m.group(0)] 
127   
128  # We have to sort the keys by length so that longer expressions 
129  # come *before* shorter expressions--in particular, "!=" must 
130  # come before "!" in the alternation.  Without this, the Python 
131  # re module, as late as version 2.2.2, empirically matches the 
132  # "!" in "!=" first, instead of finding the longest match. 
133  # What's up with that? 
134  l = CPP_to_Python_Ops_Dict.keys() 
135  l.sort(lambda a, b: cmp(len(b), len(a))) 
136   
137  # Turn the list of keys into one regular expression that will allow us 
138  # to substitute all of the operators at once. 
139  expr = string.join(map(re.escape, l), '|') 
140   
141  # ...and compile the expression. 
142  CPP_to_Python_Ops_Expression = re.compile(expr) 
143   
144  # A separate list of expressions to be evaluated and substituted 
145  # sequentially, not all at once. 
146  CPP_to_Python_Eval_List = [ 
147      ['defined\s+(\w+)',         '__dict__.has_key("\\1")'], 
148      ['defined\s*\((\w+)\)',     '__dict__.has_key("\\1")'], 
149      ['/\*.*\*/',                ''], 
150      ['/\*.*',                   ''], 
151      ['//.*',                    ''], 
152      ['(0x[0-9A-Fa-f]*)[UL]+',   '\\1L'], 
153  ] 
154   
155  # Replace the string representations of the regular expressions in the 
156  # list with compiled versions. 
157  for l in CPP_to_Python_Eval_List: 
158      l[0] = re.compile(l[0]) 
159   
160  # Wrap up all of the above into a handy function. 
161 -def CPP_to_Python(s):
162 """ 163 Converts a C pre-processor expression into an equivalent 164 Python expression that can be evaluated. 165 """ 166 s = CPP_to_Python_Ops_Expression.sub(CPP_to_Python_Ops_Sub, s) 167 for expr, repl in CPP_to_Python_Eval_List: 168 s = expr.sub(repl, s) 169 return s
170 171 172 173 del expr 174 del l 175 del override 176 177 178
179 -class FunctionEvaluator:
180 """ 181 Handles delayed evaluation of a #define function call. 182 """
183 - def __init__(self, name, args, expansion):
184 """ 185 Squirrels away the arguments and expansion value of a #define 186 macro function for later evaluation when we must actually expand 187 a value that uses it. 188 """ 189 self.name = name 190 self.args = function_arg_separator.split(args) 191 try: 192 expansion = string.split(expansion, '##') 193 except (AttributeError, TypeError): 194 # Python 1.5 throws TypeError if "expansion" isn't a string, 195 # later versions throw AttributeError. 196 pass 197 self.expansion = expansion
198 - def __call__(self, *values):
199 """ 200 Evaluates the expansion of a #define macro function called 201 with the specified values. 202 """ 203 if len(self.args) != len(values): 204 raise ValueError, "Incorrect number of arguments to `%s'" % self.name 205 # Create a dictionary that maps the macro arguments to the 206 # corresponding values in this "call." We'll use this when we 207 # eval() the expansion so that arguments will get expanded to 208 # the right values. 209 locals = {} 210 for k, v in zip(self.args, values): 211 locals[k] = v 212 213 parts = [] 214 for s in self.expansion: 215 if not s in self.args: 216 s = repr(s) 217 parts.append(s) 218 statement = string.join(parts, ' + ') 219 220 return eval(statement, globals(), locals)
221 222 223 224 # Find line continuations. 225 line_continuations = re.compile('\\\\\r?\n') 226 227 # Search for a "function call" macro on an expansion. Returns the 228 # two-tuple of the "function" name itself, and a string containing the 229 # arguments within the call parentheses. 230 function_name = re.compile('(\S+)\(([^)]*)\)') 231 232 # Split a string containing comma-separated function call arguments into 233 # the separate arguments. 234 function_arg_separator = re.compile(',\s*') 235 236 237
238 -class PreProcessor:
239 """ 240 The main workhorse class for handling C pre-processing. 241 """
242 - def __init__(self, current=os.curdir, cpppath=(), dict={}, all=0):
243 global Table 244 245 cpppath = tuple(cpppath) 246 247 self.searchpath = { 248 '"' : (current,) + cpppath, 249 '<' : cpppath + (current,), 250 } 251 252 # Initialize our C preprocessor namespace for tracking the 253 # values of #defined keywords. We use this namespace to look 254 # for keywords on #ifdef/#ifndef lines, and to eval() the 255 # expressions on #if/#elif lines (after massaging them from C to 256 # Python). 257 self.cpp_namespace = dict.copy() 258 self.cpp_namespace['__dict__'] = self.cpp_namespace 259 260 if all: 261 self.do_include = self.all_include 262 263 # For efficiency, a dispatch table maps each C preprocessor 264 # directive (#if, #define, etc.) to the method that should be 265 # called when we see it. We accomodate state changes (#if, 266 # #ifdef, #ifndef) by pushing the current dispatch table on a 267 # stack and changing what method gets called for each relevant 268 # directive we might see next at this level (#else, #elif). 269 # #endif will simply pop the stack. 270 d = { 271 'scons_current_file' : self.scons_current_file 272 } 273 for op in Table.keys(): 274 d[op] = getattr(self, 'do_' + op) 275 self.default_table = d
276 277 # Controlling methods. 278
279 - def tupleize(self, contents):
280 """ 281 Turns the contents of a file into a list of easily-processed 282 tuples describing the CPP lines in the file. 283 284 The first element of each tuple is the line's preprocessor 285 directive (#if, #include, #define, etc., minus the initial '#'). 286 The remaining elements are specific to the type of directive, as 287 pulled apart by the regular expression. 288 """ 289 global CPP_Expression, Table 290 contents = line_continuations.sub('', contents) 291 cpp_tuples = CPP_Expression.findall(contents) 292 return map(lambda m, t=Table: 293 (m[0],) + t[m[0]].match(m[1]).groups(), 294 cpp_tuples)
295
296 - def __call__(self, file):
297 """ 298 Pre-processes a file. 299 300 This is the main public entry point. 301 """ 302 self.current_file = file 303 return self.process_contents(self.read_file(file), file)
304
305 - def process_contents(self, contents, fname=None):
306 """ 307 Pre-processes a file contents. 308 309 This is the main internal entry point. 310 """ 311 self.stack = [] 312 self.dispatch_table = self.default_table.copy() 313 self.current_file = fname 314 self.tuples = self.tupleize(contents) 315 316 self.initialize_result(fname) 317 while self.tuples: 318 t = self.tuples.pop(0) 319 # Uncomment to see the list of tuples being processed (e.g., 320 # to validate the CPP lines are being translated correctly). 321 #print t 322 self.dispatch_table[t[0]](t) 323 return self.finalize_result(fname)
324 325 # Dispatch table stack manipulation methods. 326
327 - def save(self):
328 """ 329 Pushes the current dispatch table on the stack and re-initializes 330 the current dispatch table to the default. 331 """ 332 self.stack.append(self.dispatch_table) 333 self.dispatch_table = self.default_table.copy()
334
335 - def restore(self):
336 """ 337 Pops the previous dispatch table off the stack and makes it the 338 current one. 339 """ 340 try: self.dispatch_table = self.stack.pop() 341 except IndexError: pass
342 343 # Utility methods. 344
345 - def do_nothing(self, t):
346 """ 347 Null method for when we explicitly want the action for a 348 specific preprocessor directive to do nothing. 349 """ 350 pass
351
352 - def scons_current_file(self, t):
353 self.current_file = t[1]
354
355 - def eval_expression(self, t):
356 """ 357 Evaluates a C preprocessor expression. 358 359 This is done by converting it to a Python equivalent and 360 eval()ing it in the C preprocessor namespace we use to 361 track #define values. 362 """ 363 t = CPP_to_Python(string.join(t[1:])) 364 try: return eval(t, self.cpp_namespace) 365 except (NameError, TypeError): return 0
366
367 - def initialize_result(self, fname):
368 self.result = [fname]
369
370 - def finalize_result(self, fname):
371 return self.result[1:]
372
373 - def find_include_file(self, t):
374 """ 375 Finds the #include file for a given preprocessor tuple. 376 """ 377 fname = t[2] 378 for d in self.searchpath[t[1]]: 379 if d == os.curdir: 380 f = fname 381 else: 382 f = os.path.join(d, fname) 383 if os.path.isfile(f): 384 return f 385 return None
386
387 - def read_file(self, file):
388 return open(file).read()
389 390 # Start and stop processing include lines. 391
392 - def start_handling_includes(self, t=None):
393 """ 394 Causes the PreProcessor object to start processing #import, 395 #include and #include_next lines. 396 397 This method will be called when a #if, #ifdef, #ifndef or #elif 398 evaluates True, or when we reach the #else in a #if, #ifdef, 399 #ifndef or #elif block where a condition already evaluated 400 False. 401 402 """ 403 d = self.dispatch_table 404 d['import'] = self.do_import 405 d['include'] = self.do_include 406 d['include_next'] = self.do_include
407
408 - def stop_handling_includes(self, t=None):
409 """ 410 Causes the PreProcessor object to stop processing #import, 411 #include and #include_next lines. 412 413 This method will be called when a #if, #ifdef, #ifndef or #elif 414 evaluates False, or when we reach the #else in a #if, #ifdef, 415 #ifndef or #elif block where a condition already evaluated True. 416 """ 417 d = self.dispatch_table 418 d['import'] = self.do_nothing 419 d['include'] = self.do_nothing 420 d['include_next'] = self.do_nothing
421 422 # Default methods for handling all of the preprocessor directives. 423 # (Note that what actually gets called for a given directive at any 424 # point in time is really controlled by the dispatch_table.) 425
426 - def _do_if_else_condition(self, condition):
427 """ 428 Common logic for evaluating the conditions on #if, #ifdef and 429 #ifndef lines. 430 """ 431 self.save() 432 d = self.dispatch_table 433 if condition: 434 self.start_handling_includes() 435 d['elif'] = self.stop_handling_includes 436 d['else'] = self.stop_handling_includes 437 else: 438 self.stop_handling_includes() 439 d['elif'] = self.do_elif 440 d['else'] = self.start_handling_includes
441
442 - def do_ifdef(self, t):
443 """ 444 Default handling of a #ifdef line. 445 """ 446 self._do_if_else_condition(self.cpp_namespace.has_key(t[1]))
447
448 - def do_ifndef(self, t):
449 """ 450 Default handling of a #ifndef line. 451 """ 452 self._do_if_else_condition(not self.cpp_namespace.has_key(t[1]))
453
454 - def do_if(self, t):
455 """ 456 Default handling of a #if line. 457 """ 458 self._do_if_else_condition(self.eval_expression(t))
459
460 - def do_elif(self, t):
461 """ 462 Default handling of a #elif line. 463 """ 464 d = self.dispatch_table 465 if self.eval_expression(t): 466 self.start_handling_includes() 467 d['elif'] = self.stop_handling_includes 468 d['else'] = self.stop_handling_includes
469
470 - def do_else(self, t):
471 """ 472 Default handling of a #else line. 473 """ 474 pass
475
476 - def do_endif(self, t):
477 """ 478 Default handling of a #endif line. 479 """ 480 self.restore()
481
482 - def do_define(self, t):
483 """ 484 Default handling of a #define line. 485 """ 486 _, name, args, expansion = t 487 try: 488 expansion = int(expansion) 489 except (TypeError, ValueError): 490 pass 491 if args: 492 evaluator = FunctionEvaluator(name, args[1:-1], expansion) 493 self.cpp_namespace[name] = evaluator 494 else: 495 self.cpp_namespace[name] = expansion
496
497 - def do_undef(self, t):
498 """ 499 Default handling of a #undef line. 500 """ 501 try: del self.cpp_namespace[t[1]] 502 except KeyError: pass
503
504 - def do_import(self, t):
505 """ 506 Default handling of a #import line. 507 """ 508 # XXX finish this -- maybe borrow/share logic from do_include()...? 509 pass
510
511 - def do_include(self, t):
512 """ 513 Default handling of a #include line. 514 """ 515 t = self.resolve_include(t) 516 include_file = self.find_include_file(t) 517 if include_file: 518 #print "include_file =", include_file 519 self.result.append(include_file) 520 contents = self.read_file(include_file) 521 new_tuples = [('scons_current_file', include_file)] + \ 522 self.tupleize(contents) + \ 523 [('scons_current_file', self.current_file)] 524 self.tuples[:] = new_tuples + self.tuples
525 526 # Date: Tue, 22 Nov 2005 20:26:09 -0500 527 # From: Stefan Seefeld <seefeld@sympatico.ca> 528 # 529 # By the way, #include_next is not the same as #include. The difference 530 # being that #include_next starts its search in the path following the 531 # path that let to the including file. In other words, if your system 532 # include paths are ['/foo', '/bar'], and you are looking at a header 533 # '/foo/baz.h', it might issue an '#include_next <baz.h>' which would 534 # correctly resolve to '/bar/baz.h' (if that exists), but *not* see 535 # '/foo/baz.h' again. See http://www.delorie.com/gnu/docs/gcc/cpp_11.html 536 # for more reasoning. 537 # 538 # I have no idea in what context 'import' might be used. 539 540 # XXX is #include_next really the same as #include ? 541 do_include_next = do_include 542 543 # Utility methods for handling resolution of include files. 544
545 - def resolve_include(self, t):
546 """Resolve a tuple-ized #include line. 547 548 This handles recursive expansion of values without "" or <> 549 surrounding the name until an initial " or < is found, to handle 550 #include FILE 551 where FILE is a #define somewhere else. 552 """ 553 s = t[1] 554 while not s[0] in '<"': 555 #print "s =", s 556 try: 557 s = self.cpp_namespace[s] 558 except KeyError: 559 m = function_name.search(s) 560 s = self.cpp_namespace[m.group(1)] 561 if callable(s): 562 args = function_arg_separator.split(m.group(2)) 563 s = apply(s, args) 564 if not s: 565 return None 566 return (t[0], s[0], s[1:-1])
567
568 - def all_include(self, t):
569 """ 570 """ 571 self.result.append(self.resolve_include(t))
572
573 -class DumbPreProcessor(PreProcessor):
574 """A preprocessor that ignores all #if/#elif/#else/#endif directives 575 and just reports back *all* of the #include files (like the classic 576 SCons scanner did). 577 578 This is functionally equivalent to using a regular expression to 579 find all of the #include lines, only slower. It exists mainly as 580 an example of how the main PreProcessor class can be sub-classed 581 to tailor its behavior. 582 """
583 - def __init__(self, *args, **kw):
584 apply(PreProcessor.__init__, (self,)+args, kw) 585 d = self.default_table 586 for func in ['if', 'elif', 'else', 'endif', 'ifdef', 'ifndef']: 587 d[func] = d[func] = self.do_nothing
588 589 del __revision__ 590