forked from Tom/SconsLocal
init
This commit is contained in:
131
scons-local-3.0.0/SCons/Scanner/C.py
Normal file
131
scons-local-3.0.0/SCons/Scanner/C.py
Normal file
@@ -0,0 +1,131 @@
|
||||
"""SCons.Scanner.C
|
||||
|
||||
This module implements the dependency scanner for C/C++ code.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Scanner/C.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
|
||||
|
||||
import SCons.Node.FS
|
||||
import SCons.Scanner
|
||||
import SCons.Util
|
||||
|
||||
import SCons.cpp
|
||||
|
||||
class SConsCPPScanner(SCons.cpp.PreProcessor):
|
||||
"""
|
||||
SCons-specific subclass of the cpp.py module's processing.
|
||||
|
||||
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.
|
||||
"""
|
||||
def __init__(self, *args, **kw):
|
||||
SCons.cpp.PreProcessor.__init__(self, *args, **kw)
|
||||
self.missing = []
|
||||
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
|
||||
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:
|
||||
return fp.read()
|
||||
except EnvironmentError as e:
|
||||
self.missing.append((file, self.current_file))
|
||||
return ''
|
||||
|
||||
def dictify_CPPDEFINES(env):
|
||||
cppdefines = env.get('CPPDEFINES', {})
|
||||
if cppdefines is None:
|
||||
return {}
|
||||
if SCons.Util.is_Sequence(cppdefines):
|
||||
result = {}
|
||||
for c in cppdefines:
|
||||
if SCons.Util.is_Sequence(c):
|
||||
result[c[0]] = c[1]
|
||||
else:
|
||||
result[c] = None
|
||||
return result
|
||||
if not SCons.Util.is_Dict(cppdefines):
|
||||
return {cppdefines : None}
|
||||
return cppdefines
|
||||
|
||||
class SConsCPPScannerWrapper(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.
|
||||
"""
|
||||
def __init__(self, name, variable):
|
||||
self.name = name
|
||||
self.path = SCons.Scanner.FindPathDirs(variable)
|
||||
def __call__(self, node, env, path = ()):
|
||||
cpp = SConsCPPScanner(current = node.get_dir(),
|
||||
cpppath = path,
|
||||
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"
|
||||
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 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")
|
||||
|
||||
cs = SCons.Scanner.ClassicCPP("CScanner",
|
||||
"$CPPSUFFIXES",
|
||||
"CPPPATH",
|
||||
'^[ \t]*#[ \t]*(?:include|import)[ \t]*(<|")([^>"]+)(>|")')
|
||||
return cs
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
73
scons-local-3.0.0/SCons/Scanner/D.py
Normal file
73
scons-local-3.0.0/SCons/Scanner/D.py
Normal file
@@ -0,0 +1,73 @@
|
||||
"""SCons.Scanner.D
|
||||
|
||||
Scanner for the Digital Mars "D" programming language.
|
||||
|
||||
Coded by Andy Friesen
|
||||
17 Nov 2003
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Scanner/D.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
|
||||
|
||||
import SCons.Scanner
|
||||
|
||||
def DScanner():
|
||||
"""Return a prototype Scanner instance for scanning D source files"""
|
||||
ds = D()
|
||||
return ds
|
||||
|
||||
class D(SCons.Scanner.Classic):
|
||||
def __init__ (self):
|
||||
SCons.Scanner.Classic.__init__ (
|
||||
self,
|
||||
name = "DScanner",
|
||||
suffixes = '$DSUFFIXES',
|
||||
path_variable = 'DPATH',
|
||||
regex = '(?:import\s+)([\w\s=,.]+)(?:\s*:[\s\w,=]+)?(?:;)'
|
||||
)
|
||||
|
||||
def find_include(self, include, source_dir, path):
|
||||
# translate dots (package separators) to slashes
|
||||
inc = include.replace('.', '/')
|
||||
|
||||
i = SCons.Node.FS.find_file(inc + '.d', (source_dir,) + path)
|
||||
if i is None:
|
||||
i = SCons.Node.FS.find_file (inc + '.di', (source_dir,) + path)
|
||||
return i, include
|
||||
|
||||
def find_include_names(self, node):
|
||||
includes = []
|
||||
for iii in self.cre.findall(node.get_text_contents()):
|
||||
for jjj in iii.split(','):
|
||||
kkk = jjj.split('=')[-1]
|
||||
includes.append(kkk.strip())
|
||||
return includes
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
109
scons-local-3.0.0/SCons/Scanner/Dir.py
Normal file
109
scons-local-3.0.0/SCons/Scanner/Dir.py
Normal file
@@ -0,0 +1,109 @@
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
__revision__ = "src/engine/SCons/Scanner/Dir.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
|
||||
|
||||
import SCons.Node.FS
|
||||
import SCons.Scanner
|
||||
|
||||
def only_dirs(nodes):
|
||||
is_Dir = lambda n: isinstance(n.disambiguate(), SCons.Node.FS.Dir)
|
||||
return [node for node in nodes if is_Dir(node)]
|
||||
|
||||
def DirScanner(**kw):
|
||||
"""Return a prototype Scanner instance for scanning
|
||||
directories for on-disk files"""
|
||||
kw['node_factory'] = SCons.Node.FS.Entry
|
||||
kw['recursive'] = only_dirs
|
||||
return SCons.Scanner.Base(scan_on_disk, "DirScanner", **kw)
|
||||
|
||||
def DirEntryScanner(**kw):
|
||||
"""Return a prototype Scanner instance for "scanning"
|
||||
directory Nodes for their in-memory entries"""
|
||||
kw['node_factory'] = SCons.Node.FS.Entry
|
||||
kw['recursive'] = None
|
||||
return SCons.Scanner.Base(scan_in_memory, "DirEntryScanner", **kw)
|
||||
|
||||
skip_entry = {}
|
||||
|
||||
skip_entry_list = [
|
||||
'.',
|
||||
'..',
|
||||
'.sconsign',
|
||||
# Used by the native dblite.py module.
|
||||
'.sconsign.dblite',
|
||||
# Used by dbm and dumbdbm.
|
||||
'.sconsign.dir',
|
||||
# Used by dbm.
|
||||
'.sconsign.pag',
|
||||
# Used by dumbdbm.
|
||||
'.sconsign.dat',
|
||||
'.sconsign.bak',
|
||||
# Used by some dbm emulations using Berkeley DB.
|
||||
'.sconsign.db',
|
||||
]
|
||||
|
||||
for skip in skip_entry_list:
|
||||
skip_entry[skip] = 1
|
||||
skip_entry[SCons.Node.FS._my_normcase(skip)] = 1
|
||||
|
||||
do_not_scan = lambda k: k not in skip_entry
|
||||
|
||||
def scan_on_disk(node, env, path=()):
|
||||
"""
|
||||
Scans a directory for on-disk files and directories therein.
|
||||
|
||||
Looking up the entries will add these to the in-memory Node tree
|
||||
representation of the file system, so all we have to do is just
|
||||
that and then call the in-memory scanning function.
|
||||
"""
|
||||
try:
|
||||
flist = node.fs.listdir(node.get_abspath())
|
||||
except (IOError, OSError):
|
||||
return []
|
||||
e = node.Entry
|
||||
for f in filter(do_not_scan, flist):
|
||||
# Add ./ to the beginning of the file name so if it begins with a
|
||||
# '#' we don't look it up relative to the top-level directory.
|
||||
e('./' + f)
|
||||
return scan_in_memory(node, env, path)
|
||||
|
||||
def scan_in_memory(node, env, path=()):
|
||||
"""
|
||||
"Scans" a Node.FS.Dir for its in-memory entries.
|
||||
"""
|
||||
try:
|
||||
entries = node.entries
|
||||
except AttributeError:
|
||||
# It's not a Node.FS.Dir (or doesn't look enough like one for
|
||||
# our purposes), which can happen if a target list containing
|
||||
# mixed Node types (Dirs and Files, for example) has a Dir as
|
||||
# the first entry.
|
||||
return []
|
||||
entry_list = sorted(filter(do_not_scan, list(entries.keys())))
|
||||
return [entries[n] for n in entry_list]
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
316
scons-local-3.0.0/SCons/Scanner/Fortran.py
Normal file
316
scons-local-3.0.0/SCons/Scanner/Fortran.py
Normal file
@@ -0,0 +1,316 @@
|
||||
"""SCons.Scanner.Fortran
|
||||
|
||||
This module implements the dependency scanner for Fortran code.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
__revision__ = "src/engine/SCons/Scanner/Fortran.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
|
||||
|
||||
import re
|
||||
|
||||
import SCons.Node
|
||||
import SCons.Node.FS
|
||||
import SCons.Scanner
|
||||
import SCons.Util
|
||||
import SCons.Warnings
|
||||
|
||||
class F90Scanner(SCons.Scanner.Classic):
|
||||
"""
|
||||
A Classic Scanner subclass for Fortran source files which takes
|
||||
into account both USE and INCLUDE statements. This scanner will
|
||||
work for both F77 and F90 (and beyond) compilers.
|
||||
|
||||
Currently, this scanner assumes that the include files do not contain
|
||||
USE statements. To enable the ability to deal with USE statements
|
||||
in include files, add logic right after the module names are found
|
||||
to loop over each include file, search for and locate each USE
|
||||
statement, and append each module name to the list of dependencies.
|
||||
Caching the search results in a common dictionary somewhere so that
|
||||
the same include file is not searched multiple times would be a
|
||||
smart thing to do.
|
||||
"""
|
||||
|
||||
def __init__(self, name, suffixes, path_variable,
|
||||
use_regex, incl_regex, def_regex, *args, **kw):
|
||||
|
||||
self.cre_use = re.compile(use_regex, re.M)
|
||||
self.cre_incl = re.compile(incl_regex, re.M)
|
||||
self.cre_def = re.compile(def_regex, re.M)
|
||||
|
||||
def _scan(node, env, path, self=self):
|
||||
node = node.rfile()
|
||||
|
||||
if not node.exists():
|
||||
return []
|
||||
|
||||
return self.scan(node, env, path)
|
||||
|
||||
kw['function'] = _scan
|
||||
kw['path_function'] = SCons.Scanner.FindPathDirs(path_variable)
|
||||
kw['recursive'] = 1
|
||||
kw['skeys'] = suffixes
|
||||
kw['name'] = name
|
||||
|
||||
SCons.Scanner.Current.__init__(self, *args, **kw)
|
||||
|
||||
def scan(self, node, env, path=()):
|
||||
|
||||
# cache the includes list in node so we only scan it once:
|
||||
if node.includes != None:
|
||||
mods_and_includes = node.includes
|
||||
else:
|
||||
# retrieve all included filenames
|
||||
includes = self.cre_incl.findall(node.get_text_contents())
|
||||
# retrieve all USE'd module names
|
||||
modules = self.cre_use.findall(node.get_text_contents())
|
||||
# retrieve all defined module names
|
||||
defmodules = self.cre_def.findall(node.get_text_contents())
|
||||
|
||||
# Remove all USE'd module names that are defined in the same file
|
||||
# (case-insensitively)
|
||||
d = {}
|
||||
for m in defmodules:
|
||||
d[m.lower()] = 1
|
||||
modules = [m for m in modules if m.lower() not in d]
|
||||
|
||||
# Convert module name to a .mod filename
|
||||
suffix = env.subst('$FORTRANMODSUFFIX')
|
||||
modules = [x.lower() + suffix for x in modules]
|
||||
# Remove unique items from the list
|
||||
mods_and_includes = SCons.Util.unique(includes+modules)
|
||||
node.includes = mods_and_includes
|
||||
|
||||
# This is a hand-coded DSU (decorate-sort-undecorate, or
|
||||
# Schwartzian transform) pattern. The sort key is the raw name
|
||||
# of the file as specifed on the USE or INCLUDE line, which lets
|
||||
# us keep the sort order constant regardless of whether the file
|
||||
# is actually found in a Repository or locally.
|
||||
nodes = []
|
||||
source_dir = node.get_dir()
|
||||
if callable(path):
|
||||
path = path()
|
||||
for dep in mods_and_includes:
|
||||
n, i = self.find_include(dep, source_dir, path)
|
||||
|
||||
if n is None:
|
||||
SCons.Warnings.warn(SCons.Warnings.DependencyWarning,
|
||||
"No dependency generated for file: %s (referenced by: %s) -- file not found" % (i, node))
|
||||
else:
|
||||
sortkey = self.sort_key(dep)
|
||||
nodes.append((sortkey, n))
|
||||
|
||||
return [pair[1] for pair in sorted(nodes)]
|
||||
|
||||
def FortranScan(path_variable="FORTRANPATH"):
|
||||
"""Return a prototype Scanner instance for scanning source files
|
||||
for Fortran USE & INCLUDE statements"""
|
||||
|
||||
# The USE statement regex matches the following:
|
||||
#
|
||||
# USE module_name
|
||||
# USE :: module_name
|
||||
# USE, INTRINSIC :: module_name
|
||||
# USE, NON_INTRINSIC :: module_name
|
||||
#
|
||||
# Limitations
|
||||
#
|
||||
# -- While the regex can handle multiple USE statements on one line,
|
||||
# it cannot properly handle them if they are commented out.
|
||||
# In either of the following cases:
|
||||
#
|
||||
# ! USE mod_a ; USE mod_b [entire line is commented out]
|
||||
# USE mod_a ! ; USE mod_b [in-line comment of second USE statement]
|
||||
#
|
||||
# the second module name (mod_b) will be picked up as a dependency
|
||||
# even though it should be ignored. The only way I can see
|
||||
# to rectify this would be to modify the scanner to eliminate
|
||||
# the call to re.findall, read in the contents of the file,
|
||||
# treating the comment character as an end-of-line character
|
||||
# in addition to the normal linefeed, loop over each line,
|
||||
# weeding out the comments, and looking for the USE statements.
|
||||
# One advantage to this is that the regex passed to the scanner
|
||||
# would no longer need to match a semicolon.
|
||||
#
|
||||
# -- I question whether or not we need to detect dependencies to
|
||||
# INTRINSIC modules because these are built-in to the compiler.
|
||||
# If we consider them a dependency, will SCons look for them, not
|
||||
# find them, and kill the build? Or will we there be standard
|
||||
# compiler-specific directories we will need to point to so the
|
||||
# compiler and SCons can locate the proper object and mod files?
|
||||
|
||||
# Here is a breakdown of the regex:
|
||||
#
|
||||
# (?i) : regex is case insensitive
|
||||
# ^ : start of line
|
||||
# (?: : group a collection of regex symbols without saving the match as a "group"
|
||||
# ^|; : matches either the start of the line or a semicolon - semicolon
|
||||
# ) : end the unsaved grouping
|
||||
# \s* : any amount of white space
|
||||
# USE : match the string USE, case insensitive
|
||||
# (?: : group a collection of regex symbols without saving the match as a "group"
|
||||
# \s+| : match one or more whitespace OR .... (the next entire grouped set of regex symbols)
|
||||
# (?: : group a collection of regex symbols without saving the match as a "group"
|
||||
# (?: : establish another unsaved grouping of regex symbols
|
||||
# \s* : any amount of white space
|
||||
# , : match a comma
|
||||
# \s* : any amount of white space
|
||||
# (?:NON_)? : optionally match the prefix NON_, case insensitive
|
||||
# INTRINSIC : match the string INTRINSIC, case insensitive
|
||||
# )? : optionally match the ", INTRINSIC/NON_INTRINSIC" grouped expression
|
||||
# \s* : any amount of white space
|
||||
# :: : match a double colon that must appear after the INTRINSIC/NON_INTRINSIC attribute
|
||||
# ) : end the unsaved grouping
|
||||
# ) : end the unsaved grouping
|
||||
# \s* : match any amount of white space
|
||||
# (\w+) : match the module name that is being USE'd
|
||||
#
|
||||
#
|
||||
use_regex = "(?i)(?:^|;)\s*USE(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(\w+)"
|
||||
|
||||
|
||||
# The INCLUDE statement regex matches the following:
|
||||
#
|
||||
# INCLUDE 'some_Text'
|
||||
# INCLUDE "some_Text"
|
||||
# INCLUDE "some_Text" ; INCLUDE "some_Text"
|
||||
# INCLUDE kind_"some_Text"
|
||||
# INCLUDE kind_'some_Text"
|
||||
#
|
||||
# where some_Text can include any alphanumeric and/or special character
|
||||
# as defined by the Fortran 2003 standard.
|
||||
#
|
||||
# Limitations:
|
||||
#
|
||||
# -- The Fortran standard dictates that a " or ' in the INCLUDE'd
|
||||
# string must be represented as a "" or '', if the quotes that wrap
|
||||
# the entire string are either a ' or ", respectively. While the
|
||||
# regular expression below can detect the ' or " characters just fine,
|
||||
# the scanning logic, presently is unable to detect them and reduce
|
||||
# them to a single instance. This probably isn't an issue since,
|
||||
# in practice, ' or " are not generally used in filenames.
|
||||
#
|
||||
# -- This regex will not properly deal with multiple INCLUDE statements
|
||||
# when the entire line has been commented out, ala
|
||||
#
|
||||
# ! INCLUDE 'some_file' ; INCLUDE 'some_file'
|
||||
#
|
||||
# In such cases, it will properly ignore the first INCLUDE file,
|
||||
# but will actually still pick up the second. Interestingly enough,
|
||||
# the regex will properly deal with these cases:
|
||||
#
|
||||
# INCLUDE 'some_file'
|
||||
# INCLUDE 'some_file' !; INCLUDE 'some_file'
|
||||
#
|
||||
# To get around the above limitation, the FORTRAN programmer could
|
||||
# simply comment each INCLUDE statement separately, like this
|
||||
#
|
||||
# ! INCLUDE 'some_file' !; INCLUDE 'some_file'
|
||||
#
|
||||
# The way I see it, the only way to get around this limitation would
|
||||
# be to modify the scanning logic to replace the calls to re.findall
|
||||
# with a custom loop that processes each line separately, throwing
|
||||
# away fully commented out lines before attempting to match against
|
||||
# the INCLUDE syntax.
|
||||
#
|
||||
# Here is a breakdown of the regex:
|
||||
#
|
||||
# (?i) : regex is case insensitive
|
||||
# (?: : begin a non-saving group that matches the following:
|
||||
# ^ : either the start of the line
|
||||
# | : or
|
||||
# ['">]\s*; : a semicolon that follows a single quote,
|
||||
# double quote or greater than symbol (with any
|
||||
# amount of whitespace in between). This will
|
||||
# allow the regex to match multiple INCLUDE
|
||||
# statements per line (although it also requires
|
||||
# the positive lookahead assertion that is
|
||||
# used below). It will even properly deal with
|
||||
# (i.e. ignore) cases in which the additional
|
||||
# INCLUDES are part of an in-line comment, ala
|
||||
# " INCLUDE 'someFile' ! ; INCLUDE 'someFile2' "
|
||||
# ) : end of non-saving group
|
||||
# \s* : any amount of white space
|
||||
# INCLUDE : match the string INCLUDE, case insensitive
|
||||
# \s+ : match one or more white space characters
|
||||
# (?\w+_)? : match the optional "kind-param _" prefix allowed by the standard
|
||||
# [<"'] : match the include delimiter - an apostrophe, double quote, or less than symbol
|
||||
# (.+?) : match one or more characters that make up
|
||||
# the included path and file name and save it
|
||||
# in a group. The Fortran standard allows for
|
||||
# any non-control character to be used. The dot
|
||||
# operator will pick up any character, including
|
||||
# control codes, but I can't conceive of anyone
|
||||
# putting control codes in their file names.
|
||||
# The question mark indicates it is non-greedy so
|
||||
# that regex will match only up to the next quote,
|
||||
# double quote, or greater than symbol
|
||||
# (?=["'>]) : positive lookahead assertion to match the include
|
||||
# delimiter - an apostrophe, double quote, or
|
||||
# greater than symbol. This level of complexity
|
||||
# is required so that the include delimiter is
|
||||
# not consumed by the match, thus allowing the
|
||||
# sub-regex discussed above to uniquely match a
|
||||
# set of semicolon-separated INCLUDE statements
|
||||
# (as allowed by the F2003 standard)
|
||||
|
||||
include_regex = """(?i)(?:^|['">]\s*;)\s*INCLUDE\s+(?:\w+_)?[<"'](.+?)(?=["'>])"""
|
||||
|
||||
# The MODULE statement regex finds module definitions by matching
|
||||
# the following:
|
||||
#
|
||||
# MODULE module_name
|
||||
#
|
||||
# but *not* the following:
|
||||
#
|
||||
# MODULE PROCEDURE procedure_name
|
||||
#
|
||||
# Here is a breakdown of the regex:
|
||||
#
|
||||
# (?i) : regex is case insensitive
|
||||
# ^\s* : any amount of white space
|
||||
# MODULE : match the string MODULE, case insensitive
|
||||
# \s+ : match one or more white space characters
|
||||
# (?!PROCEDURE) : but *don't* match if the next word matches
|
||||
# PROCEDURE (negative lookahead assertion),
|
||||
# case insensitive
|
||||
# (\w+) : match one or more alphanumeric characters
|
||||
# that make up the defined module name and
|
||||
# save it in a group
|
||||
|
||||
def_regex = """(?i)^\s*MODULE\s+(?!PROCEDURE)(\w+)"""
|
||||
|
||||
scanner = F90Scanner("FortranScan",
|
||||
"$FORTRANSUFFIXES",
|
||||
path_variable,
|
||||
use_regex,
|
||||
include_regex,
|
||||
def_regex)
|
||||
return scanner
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
48
scons-local-3.0.0/SCons/Scanner/IDL.py
Normal file
48
scons-local-3.0.0/SCons/Scanner/IDL.py
Normal file
@@ -0,0 +1,48 @@
|
||||
"""SCons.Scanner.IDL
|
||||
|
||||
This module implements the dependency scanner for IDL (Interface
|
||||
Definition Language) files.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Scanner/IDL.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
|
||||
|
||||
import SCons.Node.FS
|
||||
import SCons.Scanner
|
||||
|
||||
def IDLScan():
|
||||
"""Return a prototype Scanner instance for scanning IDL source files"""
|
||||
cs = SCons.Scanner.ClassicCPP("IDLScan",
|
||||
"$IDLSUFFIXES",
|
||||
"CPPPATH",
|
||||
'^[ \t]*(?:#[ \t]*include|[ \t]*import)[ \t]+(<|")([^>"]+)(>|")')
|
||||
return cs
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
437
scons-local-3.0.0/SCons/Scanner/LaTeX.py
Normal file
437
scons-local-3.0.0/SCons/Scanner/LaTeX.py
Normal file
@@ -0,0 +1,437 @@
|
||||
"""SCons.Scanner.LaTeX
|
||||
|
||||
This module implements the dependency scanner for LaTeX code.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Scanner/LaTeX.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
|
||||
|
||||
import os.path
|
||||
import re
|
||||
|
||||
import SCons.Scanner
|
||||
import SCons.Util
|
||||
|
||||
# list of graphics file extensions for TeX and LaTeX
|
||||
TexGraphics = ['.eps', '.ps']
|
||||
#LatexGraphics = ['.pdf', '.png', '.jpg', '.gif', '.tif']
|
||||
LatexGraphics = [ '.png', '.jpg', '.gif', '.tif']
|
||||
|
||||
|
||||
# Used as a return value of modify_env_var if the variable is not set.
|
||||
class _Null(object):
|
||||
pass
|
||||
_null = _Null
|
||||
|
||||
# The user specifies the paths in env[variable], similar to other builders.
|
||||
# They may be relative and must be converted to absolute, as expected
|
||||
# by LaTeX and Co. The environment may already have some paths in
|
||||
# env['ENV'][var]. These paths are honored, but the env[var] paths have
|
||||
# higher precedence. All changes are un-done on exit.
|
||||
def modify_env_var(env, var, abspath):
|
||||
try:
|
||||
save = env['ENV'][var]
|
||||
except KeyError:
|
||||
save = _null
|
||||
env.PrependENVPath(var, abspath)
|
||||
try:
|
||||
if SCons.Util.is_List(env[var]):
|
||||
env.PrependENVPath(var, [os.path.abspath(str(p)) for p in env[var]])
|
||||
else:
|
||||
# Split at os.pathsep to convert into absolute path
|
||||
env.PrependENVPath(var, [os.path.abspath(p) for p in str(env[var]).split(os.pathsep)])
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
# Convert into a string explicitly to append ":" (without which it won't search system
|
||||
# paths as well). The problem is that env.AppendENVPath(var, ":")
|
||||
# does not work, refuses to append ":" (os.pathsep).
|
||||
|
||||
if SCons.Util.is_List(env['ENV'][var]):
|
||||
env['ENV'][var] = os.pathsep.join(env['ENV'][var])
|
||||
# Append the trailing os.pathsep character here to catch the case with no env[var]
|
||||
env['ENV'][var] = env['ENV'][var] + os.pathsep
|
||||
|
||||
return save
|
||||
|
||||
class FindENVPathDirs(object):
|
||||
"""
|
||||
A class to bind a specific E{*}PATH variable name to a function that
|
||||
will return all of the E{*}path directories.
|
||||
"""
|
||||
def __init__(self, variable):
|
||||
self.variable = variable
|
||||
def __call__(self, env, dir=None, target=None, source=None, argument=None):
|
||||
import SCons.PathList
|
||||
try:
|
||||
path = env['ENV'][self.variable]
|
||||
except KeyError:
|
||||
return ()
|
||||
|
||||
dir = dir or env.fs._cwd
|
||||
path = SCons.PathList.PathList(path).subst_path(env, target, source)
|
||||
return tuple(dir.Rfindalldirs(path))
|
||||
|
||||
|
||||
|
||||
def LaTeXScanner():
|
||||
"""
|
||||
Return a prototype Scanner instance for scanning LaTeX source files
|
||||
when built with latex.
|
||||
"""
|
||||
ds = LaTeX(name = "LaTeXScanner",
|
||||
suffixes = '$LATEXSUFFIXES',
|
||||
# in the search order, see below in LaTeX class docstring
|
||||
graphics_extensions = TexGraphics,
|
||||
recursive = 0)
|
||||
return ds
|
||||
|
||||
def PDFLaTeXScanner():
|
||||
"""
|
||||
Return a prototype Scanner instance for scanning LaTeX source files
|
||||
when built with pdflatex.
|
||||
"""
|
||||
ds = LaTeX(name = "PDFLaTeXScanner",
|
||||
suffixes = '$LATEXSUFFIXES',
|
||||
# in the search order, see below in LaTeX class docstring
|
||||
graphics_extensions = LatexGraphics,
|
||||
recursive = 0)
|
||||
return ds
|
||||
|
||||
class LaTeX(SCons.Scanner.Base):
|
||||
"""
|
||||
Class for scanning LaTeX files for included files.
|
||||
|
||||
Unlike most scanners, which use regular expressions that just
|
||||
return the included file name, this returns a tuple consisting
|
||||
of the keyword for the inclusion ("include", "includegraphics",
|
||||
"input", or "bibliography"), and then the file name itself.
|
||||
Based on a quick look at LaTeX documentation, it seems that we
|
||||
should append .tex suffix for the "include" keywords, append .tex if
|
||||
there is no extension for the "input" keyword, and need to add .bib
|
||||
for the "bibliography" keyword that does not accept extensions by itself.
|
||||
|
||||
Finally, if there is no extension for an "includegraphics" keyword
|
||||
latex will append .ps or .eps to find the file, while pdftex may use .pdf,
|
||||
.jpg, .tif, .mps, or .png.
|
||||
|
||||
The actual subset and search order may be altered by
|
||||
DeclareGraphicsExtensions command. This complication is ignored.
|
||||
The default order corresponds to experimentation with teTeX::
|
||||
|
||||
$ latex --version
|
||||
pdfeTeX 3.141592-1.21a-2.2 (Web2C 7.5.4)
|
||||
kpathsea version 3.5.4
|
||||
|
||||
The order is:
|
||||
['.eps', '.ps'] for latex
|
||||
['.png', '.pdf', '.jpg', '.tif'].
|
||||
|
||||
Another difference is that the search path is determined by the type
|
||||
of the file being searched:
|
||||
env['TEXINPUTS'] for "input" and "include" keywords
|
||||
env['TEXINPUTS'] for "includegraphics" keyword
|
||||
env['TEXINPUTS'] for "lstinputlisting" keyword
|
||||
env['BIBINPUTS'] for "bibliography" keyword
|
||||
env['BSTINPUTS'] for "bibliographystyle" keyword
|
||||
env['INDEXSTYLE'] for "makeindex" keyword, no scanning support needed just allows user to set it if needed.
|
||||
|
||||
FIXME: also look for the class or style in document[class|style]{}
|
||||
FIXME: also look for the argument of bibliographystyle{}
|
||||
"""
|
||||
keyword_paths = {'include': 'TEXINPUTS',
|
||||
'input': 'TEXINPUTS',
|
||||
'includegraphics': 'TEXINPUTS',
|
||||
'bibliography': 'BIBINPUTS',
|
||||
'bibliographystyle': 'BSTINPUTS',
|
||||
'addbibresource': 'BIBINPUTS',
|
||||
'addglobalbib': 'BIBINPUTS',
|
||||
'addsectionbib': 'BIBINPUTS',
|
||||
'makeindex': 'INDEXSTYLE',
|
||||
'usepackage': 'TEXINPUTS',
|
||||
'lstinputlisting': 'TEXINPUTS'}
|
||||
env_variables = SCons.Util.unique(list(keyword_paths.values()))
|
||||
two_arg_commands = ['import', 'subimport',
|
||||
'includefrom', 'subincludefrom',
|
||||
'inputfrom', 'subinputfrom']
|
||||
|
||||
def __init__(self, name, suffixes, graphics_extensions, *args, **kw):
|
||||
|
||||
# We have to include \n with the % we exclude from the first part
|
||||
# part of the regex because the expression is compiled with re.M.
|
||||
# Without the \n, the ^ could match the beginning of a *previous*
|
||||
# line followed by one or more newline characters (i.e. blank
|
||||
# lines), interfering with a match on the next line.
|
||||
# add option for whitespace before the '[options]' or the '{filename}'
|
||||
regex = r'''
|
||||
^[^%\n]*
|
||||
\\(
|
||||
include
|
||||
| includegraphics(?:\s*\[[^\]]+\])?
|
||||
| lstinputlisting(?:\[[^\]]+\])?
|
||||
| input
|
||||
| import
|
||||
| subimport
|
||||
| includefrom
|
||||
| subincludefrom
|
||||
| inputfrom
|
||||
| subinputfrom
|
||||
| bibliography
|
||||
| addbibresource
|
||||
| addglobalbib
|
||||
| addsectionbib
|
||||
| usepackage
|
||||
)
|
||||
\s*{([^}]*)} # first arg
|
||||
(?: \s*{([^}]*)} )? # maybe another arg
|
||||
'''
|
||||
self.cre = re.compile(regex, re.M | re.X)
|
||||
self.comment_re = re.compile(r'^((?:(?:\\%)|[^%\n])*)(.*)$', re.M)
|
||||
|
||||
self.graphics_extensions = graphics_extensions
|
||||
|
||||
def _scan(node, env, path=(), self=self):
|
||||
node = node.rfile()
|
||||
if not node.exists():
|
||||
return []
|
||||
return self.scan_recurse(node, path)
|
||||
|
||||
class FindMultiPathDirs(object):
|
||||
"""The stock FindPathDirs function has the wrong granularity:
|
||||
it is called once per target, while we need the path that depends
|
||||
on what kind of included files is being searched. This wrapper
|
||||
hides multiple instances of FindPathDirs, one per the LaTeX path
|
||||
variable in the environment. When invoked, the function calculates
|
||||
and returns all the required paths as a dictionary (converted into
|
||||
a tuple to become hashable). Then the scan function converts it
|
||||
back and uses a dictionary of tuples rather than a single tuple
|
||||
of paths.
|
||||
"""
|
||||
def __init__(self, dictionary):
|
||||
self.dictionary = {}
|
||||
for k,n in dictionary.items():
|
||||
self.dictionary[k] = ( SCons.Scanner.FindPathDirs(n),
|
||||
FindENVPathDirs(n) )
|
||||
|
||||
def __call__(self, env, dir=None, target=None, source=None,
|
||||
argument=None):
|
||||
di = {}
|
||||
for k,(c,cENV) in self.dictionary.items():
|
||||
di[k] = ( c(env, dir=None, target=None, source=None,
|
||||
argument=None) ,
|
||||
cENV(env, dir=None, target=None, source=None,
|
||||
argument=None) )
|
||||
# To prevent "dict is not hashable error"
|
||||
return tuple(di.items())
|
||||
|
||||
class LaTeXScanCheck(object):
|
||||
"""Skip all but LaTeX source files, i.e., do not scan *.eps,
|
||||
*.pdf, *.jpg, etc.
|
||||
"""
|
||||
def __init__(self, suffixes):
|
||||
self.suffixes = suffixes
|
||||
def __call__(self, node, env):
|
||||
current = not node.has_builder() or node.is_up_to_date()
|
||||
scannable = node.get_suffix() in env.subst_list(self.suffixes)[0]
|
||||
# Returning false means that the file is not scanned.
|
||||
return scannable and current
|
||||
|
||||
kw['function'] = _scan
|
||||
kw['path_function'] = FindMultiPathDirs(LaTeX.keyword_paths)
|
||||
kw['recursive'] = 0
|
||||
kw['skeys'] = suffixes
|
||||
kw['scan_check'] = LaTeXScanCheck(suffixes)
|
||||
kw['name'] = name
|
||||
|
||||
SCons.Scanner.Base.__init__(self, *args, **kw)
|
||||
|
||||
def _latex_names(self, include_type, filename):
|
||||
if include_type == 'input':
|
||||
base, ext = os.path.splitext( filename )
|
||||
if ext == "":
|
||||
return [filename + '.tex']
|
||||
if include_type in ('include', 'import', 'subimport',
|
||||
'includefrom', 'subincludefrom',
|
||||
'inputfrom', 'subinputfrom'):
|
||||
base, ext = os.path.splitext( filename )
|
||||
if ext == "":
|
||||
return [filename + '.tex']
|
||||
if include_type == 'bibliography':
|
||||
base, ext = os.path.splitext( filename )
|
||||
if ext == "":
|
||||
return [filename + '.bib']
|
||||
if include_type == 'usepackage':
|
||||
base, ext = os.path.splitext( filename )
|
||||
if ext == "":
|
||||
return [filename + '.sty']
|
||||
if include_type == 'includegraphics':
|
||||
base, ext = os.path.splitext( filename )
|
||||
if ext == "":
|
||||
#return [filename+e for e in self.graphics_extensions + TexGraphics]
|
||||
# use the line above to find dependencies for the PDF builder
|
||||
# when only an .eps figure is present. Since it will be found
|
||||
# if the user tells scons how to make the pdf figure, leave
|
||||
# it out for now.
|
||||
return [filename+e for e in self.graphics_extensions]
|
||||
return [filename]
|
||||
|
||||
def sort_key(self, include):
|
||||
return SCons.Node.FS._my_normcase(str(include))
|
||||
|
||||
def find_include(self, include, source_dir, path):
|
||||
inc_type, inc_subdir, inc_filename = include
|
||||
try:
|
||||
sub_paths = path[inc_type]
|
||||
except (IndexError, KeyError):
|
||||
sub_paths = ((), ())
|
||||
try_names = self._latex_names(inc_type, inc_filename)
|
||||
|
||||
# There are three search paths to try:
|
||||
# 1. current directory "source_dir"
|
||||
# 2. env[var]
|
||||
# 3. env['ENV'][var]
|
||||
search_paths = [(source_dir,)] + list(sub_paths)
|
||||
|
||||
for n in try_names:
|
||||
for search_path in search_paths:
|
||||
paths = tuple([d.Dir(inc_subdir) for d in search_path])
|
||||
i = SCons.Node.FS.find_file(n, paths)
|
||||
if i:
|
||||
return i, include
|
||||
return None, include
|
||||
|
||||
def canonical_text(self, text):
|
||||
"""Standardize an input TeX-file contents.
|
||||
|
||||
Currently:
|
||||
* removes comments, unwrapping comment-wrapped lines.
|
||||
"""
|
||||
out = []
|
||||
line_continues_a_comment = False
|
||||
for line in text.splitlines():
|
||||
line,comment = self.comment_re.findall(line)[0]
|
||||
if line_continues_a_comment == True:
|
||||
out[-1] = out[-1] + line.lstrip()
|
||||
else:
|
||||
out.append(line)
|
||||
line_continues_a_comment = len(comment) > 0
|
||||
return '\n'.join(out).rstrip()+'\n'
|
||||
|
||||
def scan(self, node, subdir='.'):
|
||||
# Modify the default scan function to allow for the regular
|
||||
# expression to return a comma separated list of file names
|
||||
# as can be the case with the bibliography keyword.
|
||||
|
||||
# Cache the includes list in node so we only scan it once:
|
||||
# path_dict = dict(list(path))
|
||||
# add option for whitespace (\s) before the '['
|
||||
noopt_cre = re.compile('\s*\[.*$')
|
||||
if node.includes != None:
|
||||
includes = node.includes
|
||||
else:
|
||||
text = self.canonical_text(node.get_text_contents())
|
||||
includes = self.cre.findall(text)
|
||||
# 1. Split comma-separated lines, e.g.
|
||||
# ('bibliography', 'phys,comp')
|
||||
# should become two entries
|
||||
# ('bibliography', 'phys')
|
||||
# ('bibliography', 'comp')
|
||||
# 2. Remove the options, e.g., such as
|
||||
# ('includegraphics[clip,width=0.7\\linewidth]', 'picture.eps')
|
||||
# should become
|
||||
# ('includegraphics', 'picture.eps')
|
||||
split_includes = []
|
||||
for include in includes:
|
||||
inc_type = noopt_cre.sub('', include[0])
|
||||
inc_subdir = subdir
|
||||
if inc_type in self.two_arg_commands:
|
||||
inc_subdir = os.path.join(subdir, include[1])
|
||||
inc_list = include[2].split(',')
|
||||
else:
|
||||
inc_list = include[1].split(',')
|
||||
for j in range(len(inc_list)):
|
||||
split_includes.append( (inc_type, inc_subdir, inc_list[j]) )
|
||||
#
|
||||
includes = split_includes
|
||||
node.includes = includes
|
||||
|
||||
return includes
|
||||
|
||||
def scan_recurse(self, node, path=()):
|
||||
""" do a recursive scan of the top level target file
|
||||
This lets us search for included files based on the
|
||||
directory of the main file just as latex does"""
|
||||
|
||||
path_dict = dict(list(path))
|
||||
|
||||
queue = []
|
||||
queue.extend( self.scan(node) )
|
||||
seen = {}
|
||||
|
||||
# This is a hand-coded DSU (decorate-sort-undecorate, or
|
||||
# Schwartzian transform) pattern. The sort key is the raw name
|
||||
# of the file as specifed on the \include, \input, etc. line.
|
||||
# TODO: what about the comment in the original Classic scanner:
|
||||
# """which lets
|
||||
# us keep the sort order constant regardless of whether the file
|
||||
# is actually found in a Repository or locally."""
|
||||
nodes = []
|
||||
source_dir = node.get_dir()
|
||||
#for include in includes:
|
||||
while queue:
|
||||
|
||||
include = queue.pop()
|
||||
inc_type, inc_subdir, inc_filename = include
|
||||
|
||||
try:
|
||||
if seen[inc_filename] == 1:
|
||||
continue
|
||||
except KeyError:
|
||||
seen[inc_filename] = 1
|
||||
|
||||
#
|
||||
# Handle multiple filenames in include[1]
|
||||
#
|
||||
n, i = self.find_include(include, source_dir, path_dict)
|
||||
if n is None:
|
||||
# Do not bother with 'usepackage' warnings, as they most
|
||||
# likely refer to system-level files
|
||||
if inc_type != 'usepackage':
|
||||
SCons.Warnings.warn(SCons.Warnings.DependencyWarning,
|
||||
"No dependency generated for file: %s (included from: %s) -- file not found" % (i, node))
|
||||
else:
|
||||
sortkey = self.sort_key(n)
|
||||
nodes.append((sortkey, n))
|
||||
# recurse down
|
||||
queue.extend( self.scan(n, inc_subdir) )
|
||||
|
||||
return [pair[1] for pair in sorted(nodes)]
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
116
scons-local-3.0.0/SCons/Scanner/Prog.py
Normal file
116
scons-local-3.0.0/SCons/Scanner/Prog.py
Normal file
@@ -0,0 +1,116 @@
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Scanner/Prog.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
|
||||
|
||||
import SCons.Node
|
||||
import SCons.Node.FS
|
||||
import SCons.Scanner
|
||||
import SCons.Util
|
||||
|
||||
# global, set by --debug=findlibs
|
||||
print_find_libs = None
|
||||
|
||||
def ProgramScanner(**kw):
|
||||
"""Return a prototype Scanner instance for scanning executable
|
||||
files for static-lib dependencies"""
|
||||
kw['path_function'] = SCons.Scanner.FindPathDirs('LIBPATH')
|
||||
ps = SCons.Scanner.Base(scan, "ProgramScanner", **kw)
|
||||
return ps
|
||||
|
||||
def _subst_libs(env, libs):
|
||||
"""
|
||||
Substitute environment variables and split into list.
|
||||
"""
|
||||
if SCons.Util.is_String(libs):
|
||||
libs = env.subst(libs)
|
||||
if SCons.Util.is_String(libs):
|
||||
libs = libs.split()
|
||||
elif SCons.Util.is_Sequence(libs):
|
||||
_libs = []
|
||||
for l in libs:
|
||||
_libs += _subst_libs(env, l)
|
||||
libs = _libs
|
||||
else:
|
||||
# libs is an object (Node, for example)
|
||||
libs = [libs]
|
||||
return libs
|
||||
|
||||
def scan(node, env, libpath = ()):
|
||||
"""
|
||||
This scanner scans program files for static-library
|
||||
dependencies. It will search the LIBPATH environment variable
|
||||
for libraries specified in the LIBS variable, returning any
|
||||
files it finds as dependencies.
|
||||
"""
|
||||
try:
|
||||
libs = env['LIBS']
|
||||
except KeyError:
|
||||
# There are no LIBS in this environment, so just return a null list:
|
||||
return []
|
||||
|
||||
libs = _subst_libs(env, libs)
|
||||
|
||||
try:
|
||||
prefix = env['LIBPREFIXES']
|
||||
if not SCons.Util.is_List(prefix):
|
||||
prefix = [ prefix ]
|
||||
except KeyError:
|
||||
prefix = [ '' ]
|
||||
|
||||
try:
|
||||
suffix = env['LIBSUFFIXES']
|
||||
if not SCons.Util.is_List(suffix):
|
||||
suffix = [ suffix ]
|
||||
except KeyError:
|
||||
suffix = [ '' ]
|
||||
|
||||
pairs = []
|
||||
for suf in map(env.subst, suffix):
|
||||
for pref in map(env.subst, prefix):
|
||||
pairs.append((pref, suf))
|
||||
|
||||
result = []
|
||||
|
||||
if callable(libpath):
|
||||
libpath = libpath()
|
||||
|
||||
find_file = SCons.Node.FS.find_file
|
||||
adjustixes = SCons.Util.adjustixes
|
||||
for lib in libs:
|
||||
if SCons.Util.is_String(lib):
|
||||
for pref, suf in pairs:
|
||||
l = adjustixes(lib, pref, suf)
|
||||
l = find_file(l, libpath, verbose=print_find_libs)
|
||||
if l:
|
||||
result.append(l)
|
||||
else:
|
||||
result.append(lib)
|
||||
|
||||
return result
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
66
scons-local-3.0.0/SCons/Scanner/RC.py
Normal file
66
scons-local-3.0.0/SCons/Scanner/RC.py
Normal file
@@ -0,0 +1,66 @@
|
||||
"""SCons.Scanner.RC
|
||||
|
||||
This module implements the dependency scanner for RC (Interface
|
||||
Definition Language) files.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Scanner/RC.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
|
||||
|
||||
import re
|
||||
|
||||
import SCons.Node.FS
|
||||
import SCons.Scanner
|
||||
|
||||
|
||||
def no_tlb(nodes):
|
||||
"""
|
||||
Filter out .tlb files as they are binary and shouldn't be scanned
|
||||
"""
|
||||
# print("Nodes:%s"%[str(n) for n in nodes])
|
||||
return [n for n in nodes if str(n)[-4:] != '.tlb']
|
||||
|
||||
|
||||
def RCScan():
|
||||
"""Return a prototype Scanner instance for scanning RC source files"""
|
||||
|
||||
res_re= r'^(?:\s*#\s*(?:include)|' \
|
||||
'.*?\s+(?:ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)' \
|
||||
'\s*.*?)' \
|
||||
'\s*(<|"| )([^>"\s]+)(?:[>"\s])*$'
|
||||
resScanner = SCons.Scanner.ClassicCPP("ResourceScanner",
|
||||
"$RCSUFFIXES",
|
||||
"CPPPATH",
|
||||
res_re,
|
||||
recursive=no_tlb)
|
||||
|
||||
return resScanner
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
45
scons-local-3.0.0/SCons/Scanner/SWIG.py
Normal file
45
scons-local-3.0.0/SCons/Scanner/SWIG.py
Normal file
@@ -0,0 +1,45 @@
|
||||
"""SCons.Scanner.SWIG
|
||||
|
||||
This module implements the dependency scanner for SWIG code.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Scanner/SWIG.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
|
||||
|
||||
import SCons.Scanner
|
||||
|
||||
SWIGSuffixes = [ '.i' ]
|
||||
|
||||
def SWIGScanner():
|
||||
expr = '^[ \t]*%[ \t]*(?:include|import|extern)[ \t]*(<|"?)([^>\s"]+)(?:>|"?)'
|
||||
scanner = SCons.Scanner.ClassicCPP("SWIGScanner", ".i", "SWIGPATH", expr)
|
||||
return scanner
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
421
scons-local-3.0.0/SCons/Scanner/__init__.py
Normal file
421
scons-local-3.0.0/SCons/Scanner/__init__.py
Normal file
@@ -0,0 +1,421 @@
|
||||
"""SCons.Scanner
|
||||
|
||||
The Scanner package for the SCons software construction utility.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2001 - 2017 The SCons Foundation
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included
|
||||
# in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
|
||||
__revision__ = "src/engine/SCons/Scanner/__init__.py rel_3.0.0:4395:8972f6a2f699 2017/09/18 12:59:24 bdbaddog"
|
||||
|
||||
import re
|
||||
|
||||
import SCons.Node.FS
|
||||
import SCons.Util
|
||||
|
||||
|
||||
class _Null(object):
|
||||
pass
|
||||
|
||||
# This is used instead of None as a default argument value so None can be
|
||||
# used as an actual argument value.
|
||||
_null = _Null
|
||||
|
||||
def Scanner(function, *args, **kw):
|
||||
"""
|
||||
Public interface factory function for creating different types
|
||||
of Scanners based on the different types of "functions" that may
|
||||
be supplied.
|
||||
|
||||
TODO: Deprecate this some day. We've moved the functionality
|
||||
inside the Base class and really don't need this factory function
|
||||
any more. It was, however, used by some of our Tool modules, so
|
||||
the call probably ended up in various people's custom modules
|
||||
patterned on SCons code.
|
||||
"""
|
||||
if SCons.Util.is_Dict(function):
|
||||
return Selector(function, *args, **kw)
|
||||
else:
|
||||
return Base(function, *args, **kw)
|
||||
|
||||
|
||||
|
||||
class FindPathDirs(object):
|
||||
"""
|
||||
A class to bind a specific E{*}PATH variable name to a function that
|
||||
will return all of the E{*}path directories.
|
||||
"""
|
||||
def __init__(self, variable):
|
||||
self.variable = variable
|
||||
def __call__(self, env, dir=None, target=None, source=None, argument=None):
|
||||
import SCons.PathList
|
||||
try:
|
||||
path = env[self.variable]
|
||||
except KeyError:
|
||||
return ()
|
||||
|
||||
dir = dir or env.fs._cwd
|
||||
path = SCons.PathList.PathList(path).subst_path(env, target, source)
|
||||
return tuple(dir.Rfindalldirs(path))
|
||||
|
||||
|
||||
|
||||
class Base(object):
|
||||
"""
|
||||
The base class for dependency scanners. This implements
|
||||
straightforward, single-pass scanning of a single file.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
function,
|
||||
name = "NONE",
|
||||
argument = _null,
|
||||
skeys = _null,
|
||||
path_function = None,
|
||||
# Node.FS.Base so that, by default, it's okay for a
|
||||
# scanner to return a Dir, File or Entry.
|
||||
node_class = SCons.Node.FS.Base,
|
||||
node_factory = None,
|
||||
scan_check = None,
|
||||
recursive = None):
|
||||
"""
|
||||
Construct a new scanner object given a scanner function.
|
||||
|
||||
'function' - a scanner function taking two or three
|
||||
arguments and returning a list of strings.
|
||||
|
||||
'name' - a name for identifying this scanner object.
|
||||
|
||||
'argument' - an optional argument that, if specified, will be
|
||||
passed to both the scanner function and the path_function.
|
||||
|
||||
'skeys' - an optional list argument that can be used to determine
|
||||
which scanner should be used for a given Node. In the case of File
|
||||
nodes, for example, the 'skeys' would be file suffixes.
|
||||
|
||||
'path_function' - a function that takes four or five arguments
|
||||
(a construction environment, Node for the directory containing
|
||||
the SConscript file that defined the primary target, list of
|
||||
target nodes, list of source nodes, and optional argument for
|
||||
this instance) and returns a tuple of the directories that can
|
||||
be searched for implicit dependency files. May also return a
|
||||
callable() which is called with no args and returns the tuple
|
||||
(supporting Bindable class).
|
||||
|
||||
'node_class' - the class of Nodes which this scan will return.
|
||||
If node_class is None, then this scanner will not enforce any
|
||||
Node conversion and will return the raw results from the
|
||||
underlying scanner function.
|
||||
|
||||
'node_factory' - the factory function to be called to translate
|
||||
the raw results returned by the scanner function into the
|
||||
expected node_class objects.
|
||||
|
||||
'scan_check' - a function to be called to first check whether
|
||||
this node really needs to be scanned.
|
||||
|
||||
'recursive' - specifies that this scanner should be invoked
|
||||
recursively on all of the implicit dependencies it returns
|
||||
(the canonical example being #include lines in C source files).
|
||||
May be a callable, which will be called to filter the list
|
||||
of nodes found to select a subset for recursive scanning
|
||||
(the canonical example being only recursively scanning
|
||||
subdirectories within a directory).
|
||||
|
||||
The scanner function's first argument will be a Node that should
|
||||
be scanned for dependencies, the second argument will be an
|
||||
Environment object, the third argument will be the tuple of paths
|
||||
returned by the path_function, and the fourth argument will be
|
||||
the value passed into 'argument', and the returned list should
|
||||
contain the Nodes for all the direct dependencies of the file.
|
||||
|
||||
Examples:
|
||||
|
||||
s = Scanner(my_scanner_function)
|
||||
|
||||
s = Scanner(function = my_scanner_function)
|
||||
|
||||
s = Scanner(function = my_scanner_function, argument = 'foo')
|
||||
|
||||
"""
|
||||
|
||||
# Note: this class could easily work with scanner functions that take
|
||||
# something other than a filename as an argument (e.g. a database
|
||||
# node) and a dependencies list that aren't file names. All that
|
||||
# would need to be changed is the documentation.
|
||||
|
||||
self.function = function
|
||||
self.path_function = path_function
|
||||
self.name = name
|
||||
self.argument = argument
|
||||
|
||||
if skeys is _null:
|
||||
if SCons.Util.is_Dict(function):
|
||||
skeys = list(function.keys())
|
||||
else:
|
||||
skeys = []
|
||||
self.skeys = skeys
|
||||
|
||||
self.node_class = node_class
|
||||
self.node_factory = node_factory
|
||||
self.scan_check = scan_check
|
||||
if callable(recursive):
|
||||
self.recurse_nodes = recursive
|
||||
elif recursive:
|
||||
self.recurse_nodes = self._recurse_all_nodes
|
||||
else:
|
||||
self.recurse_nodes = self._recurse_no_nodes
|
||||
|
||||
def path(self, env, dir=None, target=None, source=None):
|
||||
if not self.path_function:
|
||||
return ()
|
||||
if self.argument is not _null:
|
||||
return self.path_function(env, dir, target, source, self.argument)
|
||||
else:
|
||||
return self.path_function(env, dir, target, source)
|
||||
|
||||
def __call__(self, node, env, path=()):
|
||||
"""
|
||||
This method scans a single object. 'node' is the node
|
||||
that will be passed to the scanner function, and 'env' is the
|
||||
environment that will be passed to the scanner function. A list of
|
||||
direct dependency nodes for the specified node will be returned.
|
||||
"""
|
||||
if self.scan_check and not self.scan_check(node, env):
|
||||
return []
|
||||
|
||||
self = self.select(node)
|
||||
|
||||
if not self.argument is _null:
|
||||
node_list = self.function(node, env, path, self.argument)
|
||||
else:
|
||||
node_list = self.function(node, env, path)
|
||||
|
||||
kw = {}
|
||||
if hasattr(node, 'dir'):
|
||||
kw['directory'] = node.dir
|
||||
node_factory = env.get_factory(self.node_factory)
|
||||
nodes = []
|
||||
for l in node_list:
|
||||
if self.node_class and not isinstance(l, self.node_class):
|
||||
l = node_factory(l, **kw)
|
||||
nodes.append(l)
|
||||
return nodes
|
||||
|
||||
def __eq__(self, other):
|
||||
try:
|
||||
return self.__dict__ == other.__dict__
|
||||
except AttributeError:
|
||||
# other probably doesn't have a __dict__
|
||||
return self.__dict__ == other
|
||||
|
||||
def __hash__(self):
|
||||
return id(self)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def add_skey(self, skey):
|
||||
"""Add a skey to the list of skeys"""
|
||||
self.skeys.append(skey)
|
||||
|
||||
def get_skeys(self, env=None):
|
||||
if env and SCons.Util.is_String(self.skeys):
|
||||
return env.subst_list(self.skeys)[0]
|
||||
return self.skeys
|
||||
|
||||
def select(self, node):
|
||||
if SCons.Util.is_Dict(self.function):
|
||||
key = node.scanner_key()
|
||||
try:
|
||||
return self.function[key]
|
||||
except KeyError:
|
||||
return None
|
||||
else:
|
||||
return self
|
||||
|
||||
def _recurse_all_nodes(self, nodes):
|
||||
return nodes
|
||||
|
||||
def _recurse_no_nodes(self, nodes):
|
||||
return []
|
||||
|
||||
# recurse_nodes = _recurse_no_nodes
|
||||
|
||||
def add_scanner(self, skey, scanner):
|
||||
self.function[skey] = scanner
|
||||
self.add_skey(skey)
|
||||
|
||||
|
||||
class Selector(Base):
|
||||
"""
|
||||
A class for selecting a more specific scanner based on the
|
||||
scanner_key() (suffix) for a specific Node.
|
||||
|
||||
TODO: This functionality has been moved into the inner workings of
|
||||
the Base class, and this class will be deprecated at some point.
|
||||
(It was never exposed directly as part of the public interface,
|
||||
although it is used by the Scanner() factory function that was
|
||||
used by various Tool modules and therefore was likely a template
|
||||
for custom modules that may be out there.)
|
||||
"""
|
||||
def __init__(self, dict, *args, **kw):
|
||||
Base.__init__(self, None, *args, **kw)
|
||||
self.dict = dict
|
||||
self.skeys = list(dict.keys())
|
||||
|
||||
def __call__(self, node, env, path=()):
|
||||
return self.select(node)(node, env, path)
|
||||
|
||||
def select(self, node):
|
||||
try:
|
||||
return self.dict[node.scanner_key()]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
def add_scanner(self, skey, scanner):
|
||||
self.dict[skey] = scanner
|
||||
self.add_skey(skey)
|
||||
|
||||
|
||||
class Current(Base):
|
||||
"""
|
||||
A class for scanning files that are source files (have no builder)
|
||||
or are derived files and are current (which implies that they exist,
|
||||
either locally or in a repository).
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kw):
|
||||
def current_check(node, env):
|
||||
return not node.has_builder() or node.is_up_to_date()
|
||||
kw['scan_check'] = current_check
|
||||
Base.__init__(self, *args, **kw)
|
||||
|
||||
class Classic(Current):
|
||||
"""
|
||||
A Scanner subclass to contain the common logic for classic CPP-style
|
||||
include scanning, but which can be customized to use different
|
||||
regular expressions to find the includes.
|
||||
|
||||
Note that in order for this to work "out of the box" (without
|
||||
overriding the find_include() and sort_key() methods), the regular
|
||||
expression passed to the constructor must return the name of the
|
||||
include file in group 0.
|
||||
"""
|
||||
|
||||
def __init__(self, name, suffixes, path_variable, regex, *args, **kw):
|
||||
|
||||
self.cre = re.compile(regex, re.M)
|
||||
|
||||
def _scan(node, _, path=(), self=self):
|
||||
node = node.rfile()
|
||||
if not node.exists():
|
||||
return []
|
||||
return self.scan(node, path)
|
||||
|
||||
kw['function'] = _scan
|
||||
kw['path_function'] = FindPathDirs(path_variable)
|
||||
|
||||
# Allow recursive to propagate if child class specifies.
|
||||
# In this case resource scanner needs to specify a filter on which files
|
||||
# get recursively processed. Previously was hardcoded to 1 instead of
|
||||
# defaulted to 1.
|
||||
kw['recursive'] = kw.get('recursive', 1)
|
||||
kw['skeys'] = suffixes
|
||||
kw['name'] = name
|
||||
|
||||
Current.__init__(self, *args, **kw)
|
||||
|
||||
def find_include(self, include, source_dir, path):
|
||||
n = SCons.Node.FS.find_file(include, (source_dir,) + tuple(path))
|
||||
return n, include
|
||||
|
||||
def sort_key(self, include):
|
||||
return SCons.Node.FS._my_normcase(include)
|
||||
|
||||
def find_include_names(self, node):
|
||||
return self.cre.findall(node.get_text_contents())
|
||||
|
||||
def scan(self, node, path=()):
|
||||
|
||||
# cache the includes list in node so we only scan it once:
|
||||
if node.includes is not None:
|
||||
includes = node.includes
|
||||
else:
|
||||
includes = self.find_include_names(node)
|
||||
# Intern the names of the include files. Saves some memory
|
||||
# if the same header is included many times.
|
||||
node.includes = list(map(SCons.Util.silent_intern, includes))
|
||||
|
||||
# This is a hand-coded DSU (decorate-sort-undecorate, or
|
||||
# Schwartzian transform) pattern. The sort key is the raw name
|
||||
# of the file as specifed on the #include line (including the
|
||||
# " or <, since that may affect what file is found), which lets
|
||||
# us keep the sort order constant regardless of whether the file
|
||||
# is actually found in a Repository or locally.
|
||||
nodes = []
|
||||
source_dir = node.get_dir()
|
||||
if callable(path):
|
||||
path = path()
|
||||
for include in includes:
|
||||
n, i = self.find_include(include, source_dir, path)
|
||||
|
||||
if n is None:
|
||||
SCons.Warnings.warn(SCons.Warnings.DependencyWarning,
|
||||
"No dependency generated for file: %s (included from: %s) -- file not found" % (i, node))
|
||||
else:
|
||||
nodes.append((self.sort_key(include), n))
|
||||
|
||||
return [pair[1] for pair in sorted(nodes)]
|
||||
|
||||
class ClassicCPP(Classic):
|
||||
"""
|
||||
A Classic Scanner subclass which 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.
|
||||
|
||||
Note that in order for this to work, the regular expression passed
|
||||
to the constructor must return the leading bracket in group 0, and
|
||||
the contained filename in group 1.
|
||||
"""
|
||||
def find_include(self, include, source_dir, path):
|
||||
include = list(map(SCons.Util.to_str, include))
|
||||
if include[0] == '"':
|
||||
paths = (source_dir,) + tuple(path)
|
||||
else:
|
||||
paths = tuple(path) + (source_dir,)
|
||||
|
||||
n = SCons.Node.FS.find_file(include[1], paths)
|
||||
|
||||
i = SCons.Util.silent_intern(include[1])
|
||||
return n, i
|
||||
|
||||
def sort_key(self, include):
|
||||
return SCons.Node.FS._my_normcase(' '.join(include))
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
Reference in New Issue
Block a user