diff options
author | Ivan Kravets <me@ikravets.com> | 2020-02-13 15:33:47 (GMT) |
---|---|---|
committer | Ivan Kravets <me@ikravets.com> | 2020-02-13 15:33:47 (GMT) |
commit | fe2680ddd07a4bc7c6064e7193f4979060e178ba (patch) | |
tree | 3719de5a3e9657881f1f2b8ef730a45fc4a00750 | |
parent | 8bc187941d5ea8a11200432c099802eefa7a2356 (diff) | |
download | SCons-fe2680ddd07a4bc7c6064e7193f4979060e178ba.zip SCons-fe2680ddd07a4bc7c6064e7193f4979060e178ba.tar.gz SCons-fe2680ddd07a4bc7c6064e7193f4979060e178ba.tar.bz2 |
Isolate CConditionalScanner from CScanner
-rw-r--r-- | src/engine/SCons/Scanner/C.py | 142 |
1 files changed, 107 insertions, 35 deletions
diff --git a/src/engine/SCons/Scanner/C.py b/src/engine/SCons/Scanner/C.py index 37bf244..29cc396 100644 --- a/src/engine/SCons/Scanner/C.py +++ b/src/engine/SCons/Scanner/C.py @@ -46,27 +46,16 @@ class SConsCPPScanner(SCons.cpp.PreProcessor): def __init__(self, *args, **kw): SCons.cpp.PreProcessor.__init__(self, *args, **kw) self.missing = [] - self._known_paths = [] - def initialize_result(self, fname): self.result = SCons.Util.UniqueList([fname]) - + def finalize_result(self, fname): + return self.result[1:] def find_include_file(self, t): keyword, quote, fname = t - paths = tuple(self._known_paths) + self.searchpath[quote] - if quote == '"': - paths = (self.current_file.dir, ) + paths - result = SCons.Node.FS.find_file(fname, paths) - if result: - result_path = result.get_abspath() - for p in self.searchpath[quote]: - if result_path.startswith(p.get_abspath()): - self._known_paths.append(p) - break - else: + result = SCons.Node.FS.find_file(fname, self.searchpath[quote]) + if not result: self.missing.append((fname, self.current_file)) return result - def read_file(self, file): try: with open(str(file.rfile())) as fp: @@ -83,11 +72,7 @@ def dictify_CPPDEFINES(env): result = {} for c in cppdefines: if SCons.Util.is_Sequence(c): - # handle tuple with 1 item (e.g. tuple("DEFINE", )) - if len(c) > 1: - result[c[0]] = c[1] - else: - result[c[0]] = None + result[c[0]] = c[1] else: result[c] = None return result @@ -107,11 +92,10 @@ class SConsCPPScannerWrapper(object): def __init__(self, name, variable): self.name = name self.path = SCons.Scanner.FindPathDirs(variable) - def __call__(self, node, env, path = (), depth=-1): + def __call__(self, node, env, path = ()): cpp = SConsCPPScanner(current = node.get_dir(), cpppath = path, - dict = dictify_CPPDEFINES(env), - depth = depth) + dict = dictify_CPPDEFINES(env)) result = cpp(node) for included, includer in cpp.missing: fmt = "No dependency generated for file: %s (included from: %s) -- file not found" @@ -124,26 +108,114 @@ class SConsCPPScannerWrapper(object): def select(self, node): return self +def CScanner(): + """Return a prototype Scanner instance for scanning source files + that use the C pre-processor""" + + # Here's how we would (or might) use the CPP scanner code above that + # knows how to evaluate #if/#ifdef/#else/#elif lines when searching + # for #includes. This is commented out for now until we add the + # right configurability to let users pick between the scanners. + #return SConsCPPScannerWrapper("CScanner", "CPPPATH") -def CConditionalScanner(): + cs = SCons.Scanner.ClassicCPP("CScanner", + "$CPPSUFFIXES", + "CPPPATH", + '^[ \t]*#[ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")') + return cs + + +# +# ConditionalScanner +# + + +class SConsCPPConditionalScanner(SCons.cpp.PreProcessor): """ - Return an advanced conditional Scanner instance for scanning source files + SCons-specific subclass of the cpp.py module's processing. - Interprets C/C++ Preprocessor conditional syntax - (#ifdef, #if, defined, #else, #elif, etc.). + We subclass this so that: 1) we can deal with files represented + by Nodes, not strings; 2) we can keep track of the files that are + missing. """ - return SConsCPPScannerWrapper("CScanner", "CPPPATH") + def __init__(self, *args, **kw): + SCons.cpp.PreProcessor.__init__(self, *args, **kw) + self.missing = [] + self._known_paths = [] + + def initialize_result(self, fname): + self.result = SCons.Util.UniqueList([fname]) -def CScanner(): - """Return a simplified classic Scanner instance for scanning source files + def find_include_file(self, t): + keyword, quote, fname = t + paths = tuple(self._known_paths) + self.searchpath[quote] + if quote == '"': + paths = (self.current_file.dir,) + paths + result = SCons.Node.FS.find_file(fname, paths) + if result: + result_path = result.get_abspath() + for p in self.searchpath[quote]: + if result_path.startswith(p.get_abspath()): + self._known_paths.append(p) + break + else: + self.missing.append((fname, self.current_file)) + return result + + def read_file(self, file): + try: + with open(str(file.rfile())) as fp: + return fp.read() + except EnvironmentError: + self.missing.append((file, self.current_file)) + return "" + + +class SConsCPPConditionalScannerWrapper(object): + """ + The SCons wrapper around a cpp.py scanner. + + This is the actual glue between the calling conventions of generic + SCons scanners, and the (subclass of) cpp.py class that knows how + to look for #include lines with reasonably real C-preprocessor-like + evaluation of #if/#ifdef/#else/#elif lines. + """ - Takes into account the type of bracketing used to include the file, and - uses classic CPP rules for searching for the files based on the bracketing. + def __init__(self, name, variable): + self.name = name + self.path = SCons.Scanner.FindPathDirs(variable) + + def __call__(self, node, env, path=(), depth=-1): + cpp = SConsCPPConditionalScanner( + current=node.get_dir(), + cpppath=path, + dict=dictify_CPPDEFINES(env), + depth=depth, + ) + result = cpp(node) + for included, includer in cpp.missing: + fmt = "No dependency generated for file: %s (included from: %s) -- file not found" + SCons.Warnings.warn( + SCons.Warnings.DependencyWarning, fmt % (included, includer) + ) + return result + + def recurse_nodes(self, nodes): + return nodes + + def select(self, node): + return self + + +def CConditionalScanner(): + """ + Return an advanced conditional Scanner instance for scanning source files + + Interprets C/C++ Preprocessor conditional syntax + (#ifdef, #if, defined, #else, #elif, etc.). """ - return SCons.Scanner.ClassicCPP( - "CScanner", "$CPPSUFFIXES", "CPPPATH", - '^[ \t]*#[ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")') + return SConsCPPConditionalScannerWrapper("CConditionalScanner", "CPPPATH") # Local Variables: |