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

Source Code for Module SCons.cpp

  1  # 
  2  # Copyright (c) 2001 - 2019 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 3a41ed6b288cee8d085373ad7fa02894e1903864 2019-01-23 17:30:35 bdeegan" 
 25   
 26  __doc__ = """ 
 27  SCons C Pre-Processor module 
 28  """ 
 29  import SCons.compat 
 30   
 31  import os 
 32  import re 
 33   
 34  # 
 35  # First "subsystem" of regular expressions that we set up: 
 36  # 
 37  # Stuff to turn the C preprocessor directives in a file's contents into 
 38  # a list of tuples that we can process easily. 
 39  # 
 40   
 41  # A table of regular expressions that fetch the arguments from the rest of 
 42  # a C preprocessor line.  Different directives have different arguments 
 43  # that we want to fetch, using the regular expressions to which the lists 
 44  # of preprocessor directives map. 
 45  cpp_lines_dict = { 
 46      # Fetch the rest of a #if/#elif as one argument, 
 47      # with white space optional. 
 48      ('if', 'elif')      : '\s*(.+)', 
 49   
 50      # Fetch the rest of a #ifdef/#ifndef as one argument, 
 51      # separated from the keyword by white space. 
 52      ('ifdef', 'ifndef',): '\s+(.+)', 
 53   
 54      # Fetch the rest of a #import/#include/#include_next line as one 
 55      # argument, with white space optional. 
 56      ('import', 'include', 'include_next',) 
 57                          : '\s*(.+)', 
 58   
 59      # We don't care what comes after a #else or #endif line. 
 60      ('else', 'endif',)  : '', 
 61   
 62      # Fetch three arguments from a #define line: 
 63      #   1) The #defined keyword. 
 64      #   2) The optional parentheses and arguments (if it's a function-like 
 65      #      macro, '' if it's not). 
 66      #   3) The expansion value. 
 67      ('define',)         : '\s+([_A-Za-z][_A-Za-z0-9_]*)(\([^)]*\))?\s*(.*)', 
 68   
 69      # Fetch the #undefed keyword from a #undef line. 
 70      ('undef',)          : '\s+([_A-Za-z][A-Za-z0-9_]*)', 
 71  } 
 72   
 73  # Create a table that maps each individual C preprocessor directive to 
 74  # the corresponding compiled regular expression that fetches the arguments 
 75  # we care about. 
 76  Table = {} 
 77  for op_list, expr in cpp_lines_dict.items(): 
 78      e = re.compile(expr) 
 79      for op in op_list: 
 80          Table[op] = e 
 81  del e 
 82  del op 
 83  del op_list 
 84   
 85  # Create a list of the expressions we'll use to match all of the 
 86  # preprocessor directives.  These are the same as the directives 
 87  # themselves *except* that we must use a negative lookahead assertion 
 88  # when matching "if" so it doesn't match the "if" in "ifdef" or "ifndef". 
 89  override = { 
 90      'if'                        : 'if(?!n?def)', 
 91  } 
 92  l = [override.get(x, x) for x in list(Table.keys())] 
 93   
 94   
 95  # Turn the list of expressions into one big honkin' regular expression 
 96  # that will match all the preprocessor lines at once.  This will return 
 97  # a list of tuples, one for each preprocessor line.  The preprocessor 
 98  # directive will be the first element in each tuple, and the rest of 
 99  # the line will be the second element. 
100  e = '^\s*#\s*(' + '|'.join(l) + ')(.*)$' 
101   
102  # And last but not least, compile the expression. 
103  CPP_Expression = re.compile(e, re.M) 
104   
105   
106   
107   
108  # 
109  # Second "subsystem" of regular expressions that we set up: 
110  # 
111  # Stuff to translate a C preprocessor expression (as found on a #if or 
112  # #elif line) into an equivalent Python expression that we can eval(). 
113  # 
114   
115  # A dictionary that maps the C representation of Boolean operators 
116  # to their Python equivalents. 
117  CPP_to_Python_Ops_Dict = { 
118      '!'         : ' not ', 
119      '!='        : ' != ', 
120      '&&'        : ' and ', 
121      '||'        : ' or ', 
122      '?'         : ' and ', 
123      ':'         : ' or ', 
124      '\r'        : '', 
125  } 
126   
127  CPP_to_Python_Ops_Sub = lambda m: CPP_to_Python_Ops_Dict[m.group(0)] 
128   
129  # We have to sort the keys by length so that longer expressions 
130  # come *before* shorter expressions--in particular, "!=" must 
131  # come before "!" in the alternation.  Without this, the Python 
132  # re module, as late as version 2.2.2, empirically matches the 
133  # "!" in "!=" first, instead of finding the longest match. 
134  # What's up with that? 
135  l = sorted(list(CPP_to_Python_Ops_Dict.keys()), key=lambda a: len(a), reverse=True) 
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 = '|'.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+)',         '"\\1" in __dict__'], 
148      ['defined\s*\((\w+)\)',     '"\\1" in __dict__'], 
149      ['/\*.*\*/',                ''], 
150      ['/\*.*',                   ''], 
151      ['//.*',                    ''], 
152      ['(0x[0-9A-Fa-f]*)[UL]+',   '\\1'], 
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(object):
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 = expansion.split('##') 193 except AttributeError: 194 pass 195 self.expansion = expansion
196 - def __call__(self, *values):
197 """ 198 Evaluates the expansion of a #define macro function called 199 with the specified values. 200 """ 201 if len(self.args) != len(values): 202 raise ValueError("Incorrect number of arguments to `%s'" % self.name) 203 # Create a dictionary that maps the macro arguments to the 204 # corresponding values in this "call." We'll use this when we 205 # eval() the expansion so that arguments will get expanded to 206 # the right values. 207 locals = {} 208 for k, v in zip(self.args, values): 209 locals[k] = v 210 211 parts = [] 212 for s in self.expansion: 213 if not s in self.args: 214 s = repr(s) 215 parts.append(s) 216 statement = ' + '.join(parts) 217 218 return eval(statement, globals(), locals)
219 220 221 222 # Find line continuations. 223 line_continuations = re.compile('\\\\\r?\n') 224 225 # Search for a "function call" macro on an expansion. Returns the 226 # two-tuple of the "function" name itself, and a string containing the 227 # arguments within the call parentheses. 228 function_name = re.compile('(\S+)\(([^)]*)\)') 229 230 # Split a string containing comma-separated function call arguments into 231 # the separate arguments. 232 function_arg_separator = re.compile(',\s*') 233 234 235
236 -class PreProcessor(object):
237 """ 238 The main workhorse class for handling C pre-processing. 239 """
240 - def __init__(self, current=os.curdir, cpppath=(), dict={}, all=0):
241 global Table 242 243 cpppath = tuple(cpppath) 244 245 self.searchpath = { 246 '"' : (current,) + cpppath, 247 '<' : cpppath + (current,), 248 } 249 250 # Initialize our C preprocessor namespace for tracking the 251 # values of #defined keywords. We use this namespace to look 252 # for keywords on #ifdef/#ifndef lines, and to eval() the 253 # expressions on #if/#elif lines (after massaging them from C to 254 # Python). 255 self.cpp_namespace = dict.copy() 256 self.cpp_namespace['__dict__'] = self.cpp_namespace 257 258 if all: 259 self.do_include = self.all_include 260 261 # For efficiency, a dispatch table maps each C preprocessor 262 # directive (#if, #define, etc.) to the method that should be 263 # called when we see it. We accomodate state changes (#if, 264 # #ifdef, #ifndef) by pushing the current dispatch table on a 265 # stack and changing what method gets called for each relevant 266 # directive we might see next at this level (#else, #elif). 267 # #endif will simply pop the stack. 268 d = { 269 'scons_current_file' : self.scons_current_file 270 } 271 for op in list(Table.keys()): 272 d[op] = getattr(self, 'do_' + op) 273 self.default_table = d
274 275 # Controlling methods. 276
277 - def tupleize(self, contents):
278 """ 279 Turns the contents of a file into a list of easily-processed 280 tuples describing the CPP lines in the file. 281 282 The first element of each tuple is the line's preprocessor 283 directive (#if, #include, #define, etc., minus the initial '#'). 284 The remaining elements are specific to the type of directive, as 285 pulled apart by the regular expression. 286 """ 287 global CPP_Expression, Table 288 contents = line_continuations.sub('', contents) 289 cpp_tuples = CPP_Expression.findall(contents) 290 return [(m[0],) + Table[m[0]].match(m[1]).groups() for m in cpp_tuples]
291
292 - def __call__(self, file):
293 """ 294 Pre-processes a file. 295 296 This is the main public entry point. 297 """ 298 self.current_file = file 299 return self.process_contents(self.read_file(file), file)
300
301 - def process_contents(self, contents, fname=None):
302 """ 303 Pre-processes a file contents. 304 305 This is the main internal entry point. 306 """ 307 self.stack = [] 308 self.dispatch_table = self.default_table.copy() 309 self.current_file = fname 310 self.tuples = self.tupleize(contents) 311 312 self.initialize_result(fname) 313 while self.tuples: 314 t = self.tuples.pop(0) 315 # Uncomment to see the list of tuples being processed (e.g., 316 # to validate the CPP lines are being translated correctly). 317 #print(t) 318 self.dispatch_table[t[0]](t) 319 return self.finalize_result(fname)
320 321 # Dispatch table stack manipulation methods. 322
323 - def save(self):
324 """ 325 Pushes the current dispatch table on the stack and re-initializes 326 the current dispatch table to the default. 327 """ 328 self.stack.append(self.dispatch_table) 329 self.dispatch_table = self.default_table.copy()
330
331 - def restore(self):
332 """ 333 Pops the previous dispatch table off the stack and makes it the 334 current one. 335 """ 336 try: self.dispatch_table = self.stack.pop() 337 except IndexError: pass
338 339 # Utility methods. 340
341 - def do_nothing(self, t):
342 """ 343 Null method for when we explicitly want the action for a 344 specific preprocessor directive to do nothing. 345 """ 346 pass
347
348 - def scons_current_file(self, t):
349 self.current_file = t[1]
350
351 - def eval_expression(self, t):
352 """ 353 Evaluates a C preprocessor expression. 354 355 This is done by converting it to a Python equivalent and 356 eval()ing it in the C preprocessor namespace we use to 357 track #define values. 358 """ 359 t = CPP_to_Python(' '.join(t[1:])) 360 try: return eval(t, self.cpp_namespace) 361 except (NameError, TypeError): return 0
362
363 - def initialize_result(self, fname):
364 self.result = [fname]
365
366 - def finalize_result(self, fname):
367 return self.result[1:]
368
369 - def find_include_file(self, t):
370 """ 371 Finds the #include file for a given preprocessor tuple. 372 """ 373 fname = t[2] 374 for d in self.searchpath[t[1]]: 375 if d == os.curdir: 376 f = fname 377 else: 378 f = os.path.join(d, fname) 379 if os.path.isfile(f): 380 return f 381 return None
382
383 - def read_file(self, file):
384 with open(file) as f: 385 return f.read()
386 387 # Start and stop processing include lines. 388
389 - def start_handling_includes(self, t=None):
390 """ 391 Causes the PreProcessor object to start processing #import, 392 #include and #include_next lines. 393 394 This method will be called when a #if, #ifdef, #ifndef or #elif 395 evaluates True, or when we reach the #else in a #if, #ifdef, 396 #ifndef or #elif block where a condition already evaluated 397 False. 398 399 """ 400 d = self.dispatch_table 401 p = self.stack[-1] if self.stack else self.default_table 402 403 for k in ('import', 'include', 'include_next'): 404 d[k] = p[k]
405
406 - def stop_handling_includes(self, t=None):
407 """ 408 Causes the PreProcessor object to stop processing #import, 409 #include and #include_next lines. 410 411 This method will be called when a #if, #ifdef, #ifndef or #elif 412 evaluates False, or when we reach the #else in a #if, #ifdef, 413 #ifndef or #elif block where a condition already evaluated True. 414 """ 415 d = self.dispatch_table 416 d['import'] = self.do_nothing 417 d['include'] = self.do_nothing 418 d['include_next'] = self.do_nothing
419 420 # Default methods for handling all of the preprocessor directives. 421 # (Note that what actually gets called for a given directive at any 422 # point in time is really controlled by the dispatch_table.) 423
424 - def _do_if_else_condition(self, condition):
425 """ 426 Common logic for evaluating the conditions on #if, #ifdef and 427 #ifndef lines. 428 """ 429 self.save() 430 d = self.dispatch_table 431 if condition: 432 self.start_handling_includes() 433 d['elif'] = self.stop_handling_includes 434 d['else'] = self.stop_handling_includes 435 else: 436 self.stop_handling_includes() 437 d['elif'] = self.do_elif 438 d['else'] = self.start_handling_includes
439
440 - def do_ifdef(self, t):
441 """ 442 Default handling of a #ifdef line. 443 """ 444 self._do_if_else_condition(t[1] in self.cpp_namespace)
445
446 - def do_ifndef(self, t):
447 """ 448 Default handling of a #ifndef line. 449 """ 450 self._do_if_else_condition(t[1] not in self.cpp_namespace)
451
452 - def do_if(self, t):
453 """ 454 Default handling of a #if line. 455 """ 456 self._do_if_else_condition(self.eval_expression(t))
457
458 - def do_elif(self, t):
459 """ 460 Default handling of a #elif line. 461 """ 462 d = self.dispatch_table 463 if self.eval_expression(t): 464 self.start_handling_includes() 465 d['elif'] = self.stop_handling_includes 466 d['else'] = self.stop_handling_includes
467
468 - def do_else(self, t):
469 """ 470 Default handling of a #else line. 471 """ 472 pass
473
474 - def do_endif(self, t):
475 """ 476 Default handling of a #endif line. 477 """ 478 self.restore()
479
480 - def do_define(self, t):
481 """ 482 Default handling of a #define line. 483 """ 484 _, name, args, expansion = t 485 try: 486 expansion = int(expansion) 487 except (TypeError, ValueError): 488 pass 489 if args: 490 evaluator = FunctionEvaluator(name, args[1:-1], expansion) 491 self.cpp_namespace[name] = evaluator 492 else: 493 self.cpp_namespace[name] = expansion
494
495 - def do_undef(self, t):
496 """ 497 Default handling of a #undef line. 498 """ 499 try: del self.cpp_namespace[t[1]] 500 except KeyError: pass
501
502 - def do_import(self, t):
503 """ 504 Default handling of a #import line. 505 """ 506 # XXX finish this -- maybe borrow/share logic from do_include()...? 507 pass
508
509 - def do_include(self, t):
510 """ 511 Default handling of a #include line. 512 """ 513 t = self.resolve_include(t) 514 include_file = self.find_include_file(t) 515 if include_file: 516 #print("include_file =", include_file) 517 self.result.append(include_file) 518 contents = self.read_file(include_file) 519 new_tuples = [('scons_current_file', include_file)] + \ 520 self.tupleize(contents) + \ 521 [('scons_current_file', self.current_file)] 522 self.tuples[:] = new_tuples + self.tuples
523 524 # Date: Tue, 22 Nov 2005 20:26:09 -0500 525 # From: Stefan Seefeld <seefeld@sympatico.ca> 526 # 527 # By the way, #include_next is not the same as #include. The difference 528 # being that #include_next starts its search in the path following the 529 # path that let to the including file. In other words, if your system 530 # include paths are ['/foo', '/bar'], and you are looking at a header 531 # '/foo/baz.h', it might issue an '#include_next <baz.h>' which would 532 # correctly resolve to '/bar/baz.h' (if that exists), but *not* see 533 # '/foo/baz.h' again. See http://www.delorie.com/gnu/docs/gcc/cpp_11.html 534 # for more reasoning. 535 # 536 # I have no idea in what context 'import' might be used. 537 538 # XXX is #include_next really the same as #include ? 539 do_include_next = do_include 540 541 # Utility methods for handling resolution of include files. 542
543 - def resolve_include(self, t):
544 """Resolve a tuple-ized #include line. 545 546 This handles recursive expansion of values without "" or <> 547 surrounding the name until an initial " or < is found, to handle 548 549 #include FILE 550 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 = 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 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 591 # Local Variables: 592 # tab-width:4 593 # indent-tabs-mode:nil 594 # End: 595 # vim: set expandtab tabstop=4 shiftwidth=4: 596