diff options
Diffstat (limited to 'tools/build/src/tools/types/cpp.py')
-rw-r--r-- | tools/build/src/tools/types/cpp.py | 85 |
1 files changed, 78 insertions, 7 deletions
diff --git a/tools/build/src/tools/types/cpp.py b/tools/build/src/tools/types/cpp.py index a6703255c..22f4dece4 100644 --- a/tools/build/src/tools/types/cpp.py +++ b/tools/build/src/tools/types/cpp.py @@ -1,13 +1,84 @@ # Copyright David Abrahams 2004. Distributed under the Boost # Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +import os +import re -from b2.build import type +import bjam -def register (): - type.register_type('CPP', ['cpp', 'cxx', 'cc']) - type.register_type('H', ['h']) - type.register_type('HPP', ['hpp'], 'H') - type.register_type('C', ['c']) +from b2.build import type as type_, scanner +from b2.manager import get_manager +from b2.util.utility import replace_grist -register () + +MANAGER = get_manager() +ENGINE = MANAGER.engine() +SCANNERS = MANAGER.scanners() + + +class CScanner(scanner.Scanner): + def __init__(self, includes): + scanner.Scanner.__init__(self) + self.includes = [] + for include in includes: + self.includes.extend(replace_grist(include, '').split('&&')) + + def pattern(self): + return '#\s*include\s*(<(.*)>|"(.*)")' + + def process(self, target, matches, binding): + # create a single string so that findall + # can be used since it returns a list of + # all grouped matches + match_str = ' '.join(matches) + # the question mark makes the regexes non-greedy + angles = re.findall(r'<(.*?)>', match_str) + quoted = re.findall(r'"(.*?)"', match_str) + + # CONSIDER: the new scoping rules seem to defeat "on target" variables. + g = ENGINE.get_target_variable(target, 'HDRGRIST') + b = os.path.normpath(os.path.dirname(binding)) + + # Attach binding of including file to included targets. When a target is + # directly created from a virtual target this extra information is + # unnecessary. But in other cases, it allows us to distinguish between + # two headers of the same name included from different places. We do not + # need this extra information for angle includes, since they should not + # depend on the including file (we can not get literal "." in the + # include path). + # local g2 = $(g)"#"$(b) ; + g2 = g + '#' + b + + angles = [replace_grist(angle, g) for angle in angles] + quoted = [replace_grist(quote, g2) for quote in quoted] + + includes = angles + quoted + + bjam.call('INCLUDES', target, includes) + bjam.call('NOCARE', includes) + ENGINE.set_target_variable(angles, 'SEARCH', self.includes) + ENGINE.set_target_variable(quoted, 'SEARCH', [b] + self.includes) + + # Just propagate the current scanner to includes, in hope that includes + # do not change scanners. + SCANNERS.propagate(self, includes) + + bjam.call('ISFILE', includes) + + +scanner.register(CScanner, 'include') + +type_.register_type('CPP', ['cpp', 'cxx', 'cc']) +type_.register_type('H', ['h']) +type_.register_type('HPP', ['hpp'], 'H') +type_.register_type('C', ['c']) +# It most cases where a CPP file or a H file is a source of some action, we +# should rebuild the result if any of files included by CPP/H are changed. One +# case when this is not needed is installation, which is handled specifically. +type_.set_scanner('CPP', CScanner) +type_.set_scanner('C', CScanner) +# One case where scanning of H/HPP files is necessary is PCH generation -- if +# any header included by HPP being precompiled changes, we need to recompile the +# header. +type_.set_scanner('H', CScanner) +type_.set_scanner('HPP', CScanner) |