C.py (scons-4.2.0) | : | C.py (SCons-4.3.0) | ||
---|---|---|---|---|
skipping to change at line 27 | skipping to change at line 27 | |||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE | # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE | |||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | |||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | |||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||
"""Dependency scanner for C/C++ code.""" | """Dependency scanner for C/C++ code.""" | |||
import SCons.Node.FS | import SCons.Node.FS | |||
import SCons.Scanner | ||||
import SCons.Util | ||||
import SCons.cpp | import SCons.cpp | |||
import SCons.Util | ||||
from . import ClassicCPP, FindPathDirs | ||||
class SConsCPPScanner(SCons.cpp.PreProcessor): | class SConsCPPScanner(SCons.cpp.PreProcessor): | |||
"""SCons-specific subclass of the cpp.py module's processing. | """SCons-specific subclass of the cpp.py module's processing. | |||
We subclass this so that: 1) we can deal with files represented | 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 | by Nodes, not strings; 2) we can keep track of the files that are | |||
missing. | missing. | |||
""" | """ | |||
def __init__(self, *args, **kw): | def __init__(self, *args, **kwargs): | |||
SCons.cpp.PreProcessor.__init__(self, *args, **kw) | super().__init__(*args, **kwargs) | |||
self.missing = [] | self.missing = [] | |||
def initialize_result(self, fname): | def initialize_result(self, fname): | |||
self.result = SCons.Util.UniqueList([fname]) | self.result = SCons.Util.UniqueList([fname]) | |||
def finalize_result(self, fname): | def finalize_result(self, fname): | |||
return self.result[1:] | return self.result[1:] | |||
def find_include_file(self, t): | def find_include_file(self, t): | |||
keyword, quote, fname = t | keyword, quote, fname = t | |||
result = SCons.Node.FS.find_file(fname, self.searchpath[quote]) | result = SCons.Node.FS.find_file(fname, self.searchpath[quote]) | |||
if not result: | if not result: | |||
self.missing.append((fname, self.current_file)) | self.missing.append((fname, self.current_file)) | |||
return result | return result | |||
def read_file(self, file): | def read_file(self, file): | |||
try: | try: | |||
with open(str(file.rfile())) as fp: | with open(str(file.rfile())) as fp: | |||
return fp.read() | return fp.read() | |||
except EnvironmentError as e: | except EnvironmentError as e: | |||
self.missing.append((file, self.current_file)) | self.missing.append((file, self.current_file)) | |||
return '' | return '' | |||
def dictify_CPPDEFINES(env): | def dictify_CPPDEFINES(env): | |||
cppdefines = env.get('CPPDEFINES', {}) | cppdefines = env.get('CPPDEFINES', {}) | |||
skipping to change at line 84 | skipping to change at line 87 | |||
return cppdefines | return cppdefines | |||
class SConsCPPScannerWrapper: | class SConsCPPScannerWrapper: | |||
"""The SCons wrapper around a cpp.py scanner. | """The SCons wrapper around a cpp.py scanner. | |||
This is the actual glue between the calling conventions of generic | This is the actual glue between the calling conventions of generic | |||
SCons scanners, and the (subclass of) cpp.py class that knows how | SCons scanners, and the (subclass of) cpp.py class that knows how | |||
to look for #include lines with reasonably real C-preprocessor-like | to look for #include lines with reasonably real C-preprocessor-like | |||
evaluation of #if/#ifdef/#else/#elif lines. | evaluation of #if/#ifdef/#else/#elif lines. | |||
""" | """ | |||
def __init__(self, name, variable): | def __init__(self, name, variable): | |||
self.name = name | self.name = name | |||
self.path = SCons.Scanner.FindPathDirs(variable) | self.path = FindPathDirs(variable) | |||
def __call__(self, node, env, path = ()): | ||||
cpp = SConsCPPScanner(current = node.get_dir(), | def __call__(self, node, env, path=()): | |||
cpppath = path, | cpp = SConsCPPScanner( | |||
dict = dictify_CPPDEFINES(env)) | current=node.get_dir(), cpppath=path, dict=dictify_CPPDEFINES(env) | |||
) | ||||
result = cpp(node) | result = cpp(node) | |||
for included, includer in cpp.missing: | for included, includer in cpp.missing: | |||
fmt = "No dependency generated for file: %s (included from: %s) -- f | SCons.Warnings.warn( | |||
ile not found" | SCons.Warnings.DependencyWarning, | |||
SCons.Warnings.warn(SCons.Warnings.DependencyWarning, | "No dependency generated for file: %s (included from: %s) " | |||
fmt % (included, includer)) | "-- file not found" % (included, includer), | |||
) | ||||
return result | return result | |||
def recurse_nodes(self, nodes): | def recurse_nodes(self, nodes): | |||
return nodes | return nodes | |||
def select(self, node): | def select(self, node): | |||
return self | return self | |||
def CScanner(): | def CScanner(): | |||
"""Return a prototype Scanner instance for scanning source files | """Return a prototype Scanner instance for scanning source files | |||
that use the C pre-processor""" | that use the C pre-processor""" | |||
# Here's how we would (or might) use the CPP scanner code above that | # 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 | # knows how to evaluate #if/#ifdef/#else/#elif lines when searching | |||
# for #includes. This is commented out for now until we add the | # for #includes. This is commented out for now until we add the | |||
# right configurability to let users pick between the scanners. | # right configurability to let users pick between the scanners. | |||
# return SConsCPPScannerWrapper("CScanner", "CPPPATH") | # return SConsCPPScannerWrapper("CScanner", "CPPPATH") | |||
cs = SCons.Scanner.ClassicCPP( | cs = ClassicCPP( | |||
"CScanner", | "CScanner", | |||
"$CPPSUFFIXES", | "$CPPSUFFIXES", | |||
"CPPPATH", | "CPPPATH", | |||
r'^[ \t]*#[ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")', | r'^[ \t]*#[ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")', | |||
) | ) | |||
return cs | return cs | |||
# | # | |||
# ConditionalScanner | # ConditionalScanner | |||
# | # | |||
class SConsCPPConditionalScanner(SCons.cpp.PreProcessor): | class SConsCPPConditionalScanner(SCons.cpp.PreProcessor): | |||
"""SCons-specific subclass of the cpp.py module's processing. | """SCons-specific subclass of the cpp.py module's processing. | |||
We subclass this so that: 1) we can deal with files represented | 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 | by Nodes, not strings; 2) we can keep track of the files that are | |||
missing. | missing. | |||
""" | """ | |||
def __init__(self, *args, **kw): | def __init__(self, *args, **kwargs): | |||
SCons.cpp.PreProcessor.__init__(self, *args, **kw) | super().__init__(*args, **kwargs) | |||
self.missing = [] | self.missing = [] | |||
self._known_paths = [] | self._known_paths = [] | |||
def initialize_result(self, fname): | def initialize_result(self, fname): | |||
self.result = SCons.Util.UniqueList([fname]) | self.result = SCons.Util.UniqueList([fname]) | |||
def find_include_file(self, t): | def find_include_file(self, t): | |||
keyword, quote, fname = t | keyword, quote, fname = t | |||
paths = tuple(self._known_paths) + self.searchpath[quote] | paths = tuple(self._known_paths) + self.searchpath[quote] | |||
if quote == '"': | if quote == '"': | |||
skipping to change at line 177 | skipping to change at line 184 | |||
The SCons wrapper around a cpp.py scanner. | The SCons wrapper around a cpp.py scanner. | |||
This is the actual glue between the calling conventions of generic | This is the actual glue between the calling conventions of generic | |||
SCons scanners, and the (subclass of) cpp.py class that knows how | SCons scanners, and the (subclass of) cpp.py class that knows how | |||
to look for #include lines with reasonably real C-preprocessor-like | to look for #include lines with reasonably real C-preprocessor-like | |||
evaluation of #if/#ifdef/#else/#elif lines. | evaluation of #if/#ifdef/#else/#elif lines. | |||
""" | """ | |||
def __init__(self, name, variable): | def __init__(self, name, variable): | |||
self.name = name | self.name = name | |||
self.path = SCons.Scanner.FindPathDirs(variable) | self.path = FindPathDirs(variable) | |||
def __call__(self, node, env, path=(), depth=-1): | def __call__(self, node, env, path=(), depth=-1): | |||
cpp = SConsCPPConditionalScanner( | cpp = SConsCPPConditionalScanner( | |||
current=node.get_dir(), | current=node.get_dir(), | |||
cpppath=path, | cpppath=path, | |||
dict=dictify_CPPDEFINES(env), | dict=dictify_CPPDEFINES(env), | |||
depth=depth, | depth=depth, | |||
) | ) | |||
result = cpp(node) | result = cpp(node) | |||
for included, includer in cpp.missing: | for included, includer in cpp.missing: | |||
End of changes. 13 change blocks. | ||||
18 lines changed or deleted | 24 lines changed or added |