Upgrade to Scons 4.0.1
- remove SourceCode (depricated in >= 4.x) - remove 'FAST' option as SetCacheMode('force') broken in >= 3.0.5
This commit is contained in:
parent
4227fd5d69
commit
e74be337b0
1499 changed files with 459614 additions and 15 deletions
15
SConstruct
15
SConstruct
|
@ -25,7 +25,6 @@ import platform
|
|||
from glob import glob
|
||||
from copy import copy
|
||||
from subprocess import Popen, PIPE
|
||||
from SCons.SConf import SetCacheMode
|
||||
import pickle
|
||||
|
||||
try:
|
||||
|
@ -142,7 +141,6 @@ PLUGINS = { # plugins with external dependencies
|
|||
|
||||
def init_environment(env):
|
||||
env.Decider('MD5-timestamp')
|
||||
env.SourceCode(".", None)
|
||||
env['ORIGIN'] = Literal('$ORIGIN')
|
||||
env['ENV']['ORIGIN'] = '$ORIGIN'
|
||||
if os.environ.get('RANLIB'):
|
||||
|
@ -380,7 +378,6 @@ opts.AddVariables(
|
|||
BoolVariable('ENABLE_GLIBC_WORKAROUND', "Workaround known GLIBC symbol exports to allow building against libstdc++-4.8 without binaries needing throw_out_of_range_fmt", 'False'),
|
||||
# http://www.scons.org/wiki/GoFastButton
|
||||
# http://stackoverflow.com/questions/1318863/how-to-optimize-an-scons-script
|
||||
BoolVariable('FAST', "Make SCons faster at the cost of less precise dependency tracking", 'False'),
|
||||
BoolVariable('PRIORITIZE_LINKING', 'Sort list of lib and inc directories to ensure preferential compiling and linking (useful when duplicate libs)', 'True'),
|
||||
('LINK_PRIORITY','Priority list in which to sort library and include paths (default order is internal, other, frameworks, user, then system - see source of `sort_paths` function for more detail)',','.join(DEFAULT_LINK_PRIORITY)),
|
||||
|
||||
|
@ -1291,12 +1288,7 @@ def GetMapnikLibVersion():
|
|||
return version_string
|
||||
|
||||
if not preconfigured:
|
||||
|
||||
color_print(4,'Configuring build environment...')
|
||||
|
||||
if not env['FAST']:
|
||||
SetCacheMode('force')
|
||||
|
||||
if env['USE_CONFIG']:
|
||||
if not env['CONFIG'].endswith('.py'):
|
||||
color_print(1,'SCons CONFIG file specified is not a python file, will not be read...')
|
||||
|
@ -2172,13 +2164,6 @@ if not HELP_REQUESTED:
|
|||
|
||||
Export('plugin_base')
|
||||
|
||||
if env['FAST']:
|
||||
# caching is 'auto' by default in SCons
|
||||
# But let's also cache implicit deps...
|
||||
EnsureSConsVersion(0,98)
|
||||
SetOption('implicit_cache', 1)
|
||||
SetOption('max_drift', 1)
|
||||
|
||||
# Build agg first, doesn't need anything special
|
||||
if env['RUNTIME_LINK'] == 'shared':
|
||||
SConscript('deps/agg/build.py')
|
||||
|
|
1476
scons/scons-local-4.0.1/SCons/Action.py
Normal file
1476
scons/scons-local-4.0.1/SCons/Action.py
Normal file
File diff suppressed because it is too large
Load diff
896
scons/scons-local-4.0.1/SCons/Builder.py
Normal file
896
scons/scons-local-4.0.1/SCons/Builder.py
Normal file
|
@ -0,0 +1,896 @@
|
|||
"""
|
||||
SCons.Builder
|
||||
|
||||
Builder object subsystem.
|
||||
|
||||
A Builder object is a callable that encapsulates information about how
|
||||
to execute actions to create a target Node (file) from source Nodes
|
||||
(files), and how to create those dependencies for tracking.
|
||||
|
||||
The main entry point here is the Builder() factory method. This provides
|
||||
a procedural interface that creates the right underlying Builder object
|
||||
based on the keyword arguments supplied and the types of the arguments.
|
||||
|
||||
The goal is for this external interface to be simple enough that the
|
||||
vast majority of users can create new Builders as necessary to support
|
||||
building new types of files in their configurations, without having to
|
||||
dive any deeper into this subsystem.
|
||||
|
||||
The base class here is BuilderBase. This is a concrete base class which
|
||||
does, in fact, represent the Builder objects that we (or users) create.
|
||||
|
||||
There is also a proxy that looks like a Builder:
|
||||
|
||||
CompositeBuilder
|
||||
|
||||
This proxies for a Builder with an action that is actually a
|
||||
dictionary that knows how to map file suffixes to a specific
|
||||
action. This is so that we can invoke different actions
|
||||
(compilers, compile options) for different flavors of source
|
||||
files.
|
||||
|
||||
Builders and their proxies have the following public interface methods
|
||||
used by other modules:
|
||||
|
||||
- __call__()
|
||||
THE public interface. Calling a Builder object (with the
|
||||
use of internal helper methods) sets up the target and source
|
||||
dependencies, appropriate mapping to a specific action, and the
|
||||
environment manipulation necessary for overridden construction
|
||||
variable. This also takes care of warning about possible mistakes
|
||||
in keyword arguments.
|
||||
|
||||
- add_emitter()
|
||||
Adds an emitter for a specific file suffix, used by some Tool
|
||||
modules to specify that (for example) a yacc invocation on a .y
|
||||
can create a .h *and* a .c file.
|
||||
|
||||
- add_action()
|
||||
Adds an action for a specific file suffix, heavily used by
|
||||
Tool modules to add their specific action(s) for turning
|
||||
a source file into an object file to the global static
|
||||
and shared object file Builders.
|
||||
|
||||
There are the following methods for internal use within this module:
|
||||
|
||||
- _execute()
|
||||
The internal method that handles the heavily lifting when a
|
||||
Builder is called. This is used so that the __call__() methods
|
||||
can set up warning about possible mistakes in keyword-argument
|
||||
overrides, and *then* execute all of the steps necessary so that
|
||||
the warnings only occur once.
|
||||
|
||||
- get_name()
|
||||
Returns the Builder's name within a specific Environment,
|
||||
primarily used to try to return helpful information in error
|
||||
messages.
|
||||
|
||||
- adjust_suffix()
|
||||
- get_prefix()
|
||||
- get_suffix()
|
||||
- get_src_suffix()
|
||||
- set_src_suffix()
|
||||
Miscellaneous stuff for handling the prefix and suffix
|
||||
manipulation we use in turning source file names into target
|
||||
file names.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
from collections import UserDict, UserList
|
||||
|
||||
import SCons.Action
|
||||
import SCons.Debug
|
||||
from SCons.Debug import logInstanceCreation
|
||||
from SCons.Errors import InternalError, UserError
|
||||
import SCons.Executor
|
||||
import SCons.Memoize
|
||||
import SCons.Util
|
||||
import SCons.Warnings
|
||||
|
||||
class _Null:
|
||||
pass
|
||||
|
||||
_null = _Null
|
||||
|
||||
def match_splitext(path, suffixes = []):
|
||||
if suffixes:
|
||||
matchsuf = [S for S in suffixes if path[-len(S):] == S]
|
||||
if matchsuf:
|
||||
suf = max([(len(_f),_f) for _f in matchsuf])[1]
|
||||
return [path[:-len(suf)], path[-len(suf):]]
|
||||
return SCons.Util.splitext(path)
|
||||
|
||||
class DictCmdGenerator(SCons.Util.Selector):
|
||||
"""This is a callable class that can be used as a
|
||||
command generator function. It holds on to a dictionary
|
||||
mapping file suffixes to Actions. It uses that dictionary
|
||||
to return the proper action based on the file suffix of
|
||||
the source file."""
|
||||
|
||||
def __init__(self, dict=None, source_ext_match=1):
|
||||
SCons.Util.Selector.__init__(self, dict)
|
||||
self.source_ext_match = source_ext_match
|
||||
|
||||
def src_suffixes(self):
|
||||
return list(self.keys())
|
||||
|
||||
def add_action(self, suffix, action):
|
||||
"""Add a suffix-action pair to the mapping.
|
||||
"""
|
||||
self[suffix] = action
|
||||
|
||||
def __call__(self, target, source, env, for_signature):
|
||||
if not source:
|
||||
return []
|
||||
|
||||
if self.source_ext_match:
|
||||
suffixes = self.src_suffixes()
|
||||
ext = None
|
||||
for src in map(str, source):
|
||||
my_ext = match_splitext(src, suffixes)[1]
|
||||
if ext and my_ext != ext:
|
||||
raise UserError("While building `%s' from `%s': Cannot build multiple sources with different extensions: %s, %s"
|
||||
% (repr(list(map(str, target))), src, ext, my_ext))
|
||||
ext = my_ext
|
||||
else:
|
||||
ext = match_splitext(str(source[0]), self.src_suffixes())[1]
|
||||
|
||||
if not ext:
|
||||
#return ext
|
||||
raise UserError("While building `%s': "
|
||||
"Cannot deduce file extension from source files: %s"
|
||||
% (repr(list(map(str, target))), repr(list(map(str, source)))))
|
||||
|
||||
try:
|
||||
ret = SCons.Util.Selector.__call__(self, env, source, ext)
|
||||
except KeyError as e:
|
||||
raise UserError("Ambiguous suffixes after environment substitution: %s == %s == %s" % (e.args[0], e.args[1], e.args[2]))
|
||||
if ret is None:
|
||||
raise UserError("While building `%s' from `%s': Don't know how to build from a source file with suffix `%s'. Expected a suffix in this list: %s." % \
|
||||
(repr(list(map(str, target))), repr(list(map(str, source))), ext, repr(list(self.keys()))))
|
||||
return ret
|
||||
|
||||
class CallableSelector(SCons.Util.Selector):
|
||||
"""A callable dictionary that will, in turn, call the value it
|
||||
finds if it can."""
|
||||
def __call__(self, env, source):
|
||||
value = SCons.Util.Selector.__call__(self, env, source)
|
||||
if callable(value):
|
||||
value = value(env, source)
|
||||
return value
|
||||
|
||||
class DictEmitter(SCons.Util.Selector):
|
||||
"""A callable dictionary that maps file suffixes to emitters.
|
||||
When called, it finds the right emitter in its dictionary for the
|
||||
suffix of the first source file, and calls that emitter to get the
|
||||
right lists of targets and sources to return. If there's no emitter
|
||||
for the suffix in its dictionary, the original target and source are
|
||||
returned.
|
||||
"""
|
||||
def __call__(self, target, source, env):
|
||||
emitter = SCons.Util.Selector.__call__(self, env, source)
|
||||
if emitter:
|
||||
target, source = emitter(target, source, env)
|
||||
return (target, source)
|
||||
|
||||
class ListEmitter(UserList):
|
||||
"""A callable list of emitters that calls each in sequence,
|
||||
returning the result.
|
||||
"""
|
||||
def __call__(self, target, source, env):
|
||||
for e in self.data:
|
||||
target, source = e(target, source, env)
|
||||
return (target, source)
|
||||
|
||||
# These are a common errors when calling a Builder;
|
||||
# they are similar to the 'target' and 'source' keyword args to builders,
|
||||
# so we issue warnings when we see them. The warnings can, of course,
|
||||
# be disabled.
|
||||
misleading_keywords = {
|
||||
'targets' : 'target',
|
||||
'sources' : 'source',
|
||||
}
|
||||
|
||||
class OverrideWarner(UserDict):
|
||||
"""A class for warning about keyword arguments that we use as
|
||||
overrides in a Builder call.
|
||||
|
||||
This class exists to handle the fact that a single Builder call
|
||||
can actually invoke multiple builders. This class only emits the
|
||||
warnings once, no matter how many Builders are invoked.
|
||||
"""
|
||||
def __init__(self, dict):
|
||||
UserDict.__init__(self, dict)
|
||||
if SCons.Debug.track_instances: logInstanceCreation(self, 'Builder.OverrideWarner')
|
||||
self.already_warned = None
|
||||
def warn(self):
|
||||
if self.already_warned:
|
||||
return
|
||||
for k in self.keys():
|
||||
if k in misleading_keywords:
|
||||
alt = misleading_keywords[k]
|
||||
msg = "Did you mean to use `%s' instead of `%s'?" % (alt, k)
|
||||
SCons.Warnings.warn(SCons.Warnings.MisleadingKeywordsWarning, msg)
|
||||
self.already_warned = 1
|
||||
|
||||
def Builder(**kw):
|
||||
"""A factory for builder objects."""
|
||||
composite = None
|
||||
if 'generator' in kw:
|
||||
if 'action' in kw:
|
||||
raise UserError("You must not specify both an action and a generator.")
|
||||
kw['action'] = SCons.Action.CommandGeneratorAction(kw['generator'], {})
|
||||
del kw['generator']
|
||||
elif 'action' in kw:
|
||||
source_ext_match = kw.get('source_ext_match', 1)
|
||||
if 'source_ext_match' in kw:
|
||||
del kw['source_ext_match']
|
||||
if SCons.Util.is_Dict(kw['action']):
|
||||
composite = DictCmdGenerator(kw['action'], source_ext_match)
|
||||
kw['action'] = SCons.Action.CommandGeneratorAction(composite, {})
|
||||
kw['src_suffix'] = composite.src_suffixes()
|
||||
else:
|
||||
kw['action'] = SCons.Action.Action(kw['action'])
|
||||
|
||||
if 'emitter' in kw:
|
||||
emitter = kw['emitter']
|
||||
if SCons.Util.is_String(emitter):
|
||||
# This allows users to pass in an Environment
|
||||
# variable reference (like "$FOO") as an emitter.
|
||||
# We will look in that Environment variable for
|
||||
# a callable to use as the actual emitter.
|
||||
var = SCons.Util.get_environment_var(emitter)
|
||||
if not var:
|
||||
raise UserError("Supplied emitter '%s' does not appear to refer to an Environment variable" % emitter)
|
||||
kw['emitter'] = EmitterProxy(var)
|
||||
elif SCons.Util.is_Dict(emitter):
|
||||
kw['emitter'] = DictEmitter(emitter)
|
||||
elif SCons.Util.is_List(emitter):
|
||||
kw['emitter'] = ListEmitter(emitter)
|
||||
|
||||
result = BuilderBase(**kw)
|
||||
|
||||
if composite is not None:
|
||||
result = CompositeBuilder(result, composite)
|
||||
|
||||
return result
|
||||
|
||||
def _node_errors(builder, env, tlist, slist):
|
||||
"""Validate that the lists of target and source nodes are
|
||||
legal for this builder and environment. Raise errors or
|
||||
issue warnings as appropriate.
|
||||
"""
|
||||
|
||||
# First, figure out if there are any errors in the way the targets
|
||||
# were specified.
|
||||
for t in tlist:
|
||||
if t.side_effect:
|
||||
raise UserError("Multiple ways to build the same target were specified for: %s" % t)
|
||||
if t.has_explicit_builder():
|
||||
# Check for errors when the environments are different
|
||||
# No error if environments are the same Environment instance
|
||||
if (t.env is not None and t.env is not env and
|
||||
# Check OverrideEnvironment case - no error if wrapped Environments
|
||||
# are the same instance, and overrides lists match
|
||||
not (getattr(t.env, '__subject', 0) is getattr(env, '__subject', 1) and
|
||||
getattr(t.env, 'overrides', 0) == getattr(env, 'overrides', 1) and
|
||||
not builder.multi)):
|
||||
action = t.builder.action
|
||||
t_contents = t.builder.action.get_contents(tlist, slist, t.env)
|
||||
contents = builder.action.get_contents(tlist, slist, env)
|
||||
|
||||
if t_contents == contents:
|
||||
msg = "Two different environments were specified for target %s,\n\tbut they appear to have the same action: %s" % (t, action.genstring(tlist, slist, t.env))
|
||||
SCons.Warnings.warn(SCons.Warnings.DuplicateEnvironmentWarning, msg)
|
||||
else:
|
||||
try:
|
||||
msg = "Two environments with different actions were specified for the same target: %s\n(action 1: %s)\n(action 2: %s)" % (t,t_contents.decode('utf-8'),contents.decode('utf-8'))
|
||||
except UnicodeDecodeError:
|
||||
msg = "Two environments with different actions were specified for the same target: %s"%t
|
||||
raise UserError(msg)
|
||||
if builder.multi:
|
||||
if t.builder != builder:
|
||||
msg = "Two different builders (%s and %s) were specified for the same target: %s" % (t.builder.get_name(env), builder.get_name(env), t)
|
||||
raise UserError(msg)
|
||||
# TODO(batch): list constructed each time!
|
||||
if t.get_executor().get_all_targets() != tlist:
|
||||
msg = "Two different target lists have a target in common: %s (from %s and from %s)" % (t, list(map(str, t.get_executor().get_all_targets())), list(map(str, tlist)))
|
||||
raise UserError(msg)
|
||||
elif t.sources != slist:
|
||||
msg = "Multiple ways to build the same target were specified for: %s (from %s and from %s)" % (t, list(map(str, t.sources)), list(map(str, slist)))
|
||||
raise UserError(msg)
|
||||
|
||||
if builder.single_source:
|
||||
if len(slist) > 1:
|
||||
raise UserError("More than one source given for single-source builder: targets=%s sources=%s" % (list(map(str,tlist)), list(map(str,slist))))
|
||||
|
||||
class EmitterProxy:
|
||||
"""This is a callable class that can act as a
|
||||
Builder emitter. It holds on to a string that
|
||||
is a key into an Environment dictionary, and will
|
||||
look there at actual build time to see if it holds
|
||||
a callable. If so, we will call that as the actual
|
||||
emitter."""
|
||||
def __init__(self, var):
|
||||
self.var = SCons.Util.to_String(var)
|
||||
|
||||
def __call__(self, target, source, env):
|
||||
emitter = self.var
|
||||
|
||||
# Recursively substitute the variable.
|
||||
# We can't use env.subst() because it deals only
|
||||
# in strings. Maybe we should change that?
|
||||
while SCons.Util.is_String(emitter) and emitter in env:
|
||||
emitter = env[emitter]
|
||||
if callable(emitter):
|
||||
target, source = emitter(target, source, env)
|
||||
elif SCons.Util.is_List(emitter):
|
||||
for e in emitter:
|
||||
target, source = e(target, source, env)
|
||||
|
||||
return (target, source)
|
||||
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.var == other.var
|
||||
|
||||
def __lt__(self, other):
|
||||
return self.var < other.var
|
||||
|
||||
class BuilderBase:
|
||||
"""Base class for Builders, objects that create output
|
||||
nodes (files) from input nodes (files).
|
||||
"""
|
||||
|
||||
def __init__(self, action = None,
|
||||
prefix = '',
|
||||
suffix = '',
|
||||
src_suffix = '',
|
||||
target_factory = None,
|
||||
source_factory = None,
|
||||
target_scanner = None,
|
||||
source_scanner = None,
|
||||
emitter = None,
|
||||
multi = 0,
|
||||
env = None,
|
||||
single_source = 0,
|
||||
name = None,
|
||||
chdir = _null,
|
||||
is_explicit = 1,
|
||||
src_builder = None,
|
||||
ensure_suffix = False,
|
||||
**overrides):
|
||||
if SCons.Debug.track_instances: logInstanceCreation(self, 'Builder.BuilderBase')
|
||||
self._memo = {}
|
||||
self.action = action
|
||||
self.multi = multi
|
||||
if SCons.Util.is_Dict(prefix):
|
||||
prefix = CallableSelector(prefix)
|
||||
self.prefix = prefix
|
||||
if SCons.Util.is_Dict(suffix):
|
||||
suffix = CallableSelector(suffix)
|
||||
self.env = env
|
||||
self.single_source = single_source
|
||||
if 'overrides' in overrides:
|
||||
msg = "The \"overrides\" keyword to Builder() creation has been removed;\n" +\
|
||||
"\tspecify the items as keyword arguments to the Builder() call instead."
|
||||
raise TypeError(msg)
|
||||
if 'scanner' in overrides:
|
||||
msg = "The \"scanner\" keyword to Builder() creation has been removed;\n" +\
|
||||
"\tuse: source_scanner or target_scanner as appropriate."
|
||||
raise TypeError(msg)
|
||||
self.overrides = overrides
|
||||
|
||||
self.set_suffix(suffix)
|
||||
self.set_src_suffix(src_suffix)
|
||||
self.ensure_suffix = ensure_suffix
|
||||
|
||||
self.target_factory = target_factory
|
||||
self.source_factory = source_factory
|
||||
self.target_scanner = target_scanner
|
||||
self.source_scanner = source_scanner
|
||||
|
||||
self.emitter = emitter
|
||||
|
||||
# Optional Builder name should only be used for Builders
|
||||
# that don't get attached to construction environments.
|
||||
if name:
|
||||
self.name = name
|
||||
self.executor_kw = {}
|
||||
if chdir is not _null:
|
||||
self.executor_kw['chdir'] = chdir
|
||||
self.is_explicit = is_explicit
|
||||
|
||||
if src_builder is None:
|
||||
src_builder = []
|
||||
elif not SCons.Util.is_List(src_builder):
|
||||
src_builder = [ src_builder ]
|
||||
self.src_builder = src_builder
|
||||
|
||||
def __nonzero__(self):
|
||||
raise InternalError("Do not test for the Node.builder attribute directly; use Node.has_builder() instead")
|
||||
|
||||
def __bool__(self):
|
||||
return self.__nonzero__()
|
||||
|
||||
def get_name(self, env):
|
||||
"""Attempts to get the name of the Builder.
|
||||
|
||||
Look at the BUILDERS variable of env, expecting it to be a
|
||||
dictionary containing this Builder, and return the key of the
|
||||
dictionary. If there's no key, then return a directly-configured
|
||||
name (if there is one) or the name of the class (by default)."""
|
||||
|
||||
try:
|
||||
index = list(env['BUILDERS'].values()).index(self)
|
||||
return list(env['BUILDERS'].keys())[index]
|
||||
except (AttributeError, KeyError, TypeError, ValueError):
|
||||
try:
|
||||
return self.name
|
||||
except AttributeError:
|
||||
return str(self.__class__)
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.__dict__ == other.__dict__
|
||||
|
||||
def splitext(self, path, env=None):
|
||||
if not env:
|
||||
env = self.env
|
||||
if env:
|
||||
suffixes = self.src_suffixes(env)
|
||||
else:
|
||||
suffixes = []
|
||||
return match_splitext(path, suffixes)
|
||||
|
||||
def _adjustixes(self, files, pre, suf, ensure_suffix=False):
|
||||
if not files:
|
||||
return []
|
||||
result = []
|
||||
if not SCons.Util.is_List(files):
|
||||
files = [files]
|
||||
|
||||
for f in files:
|
||||
if SCons.Util.is_String(f):
|
||||
f = SCons.Util.adjustixes(f, pre, suf, ensure_suffix)
|
||||
result.append(f)
|
||||
return result
|
||||
|
||||
def _create_nodes(self, env, target = None, source = None):
|
||||
"""Create and return lists of target and source nodes.
|
||||
"""
|
||||
src_suf = self.get_src_suffix(env)
|
||||
|
||||
target_factory = env.get_factory(self.target_factory)
|
||||
source_factory = env.get_factory(self.source_factory)
|
||||
|
||||
source = self._adjustixes(source, None, src_suf)
|
||||
slist = env.arg2nodes(source, source_factory)
|
||||
|
||||
pre = self.get_prefix(env, slist)
|
||||
suf = self.get_suffix(env, slist)
|
||||
|
||||
if target is None:
|
||||
try:
|
||||
t_from_s = slist[0].target_from_source
|
||||
except AttributeError:
|
||||
raise UserError("Do not know how to create a target from source `%s'" % slist[0])
|
||||
except IndexError:
|
||||
tlist = []
|
||||
else:
|
||||
splitext = lambda S: self.splitext(S,env)
|
||||
tlist = [ t_from_s(pre, suf, splitext) ]
|
||||
else:
|
||||
target = self._adjustixes(target, pre, suf, self.ensure_suffix)
|
||||
tlist = env.arg2nodes(target, target_factory, target=target, source=source)
|
||||
|
||||
if self.emitter:
|
||||
# The emitter is going to do str(node), but because we're
|
||||
# being called *from* a builder invocation, the new targets
|
||||
# don't yet have a builder set on them and will look like
|
||||
# source files. Fool the emitter's str() calls by setting
|
||||
# up a temporary builder on the new targets.
|
||||
new_targets = []
|
||||
for t in tlist:
|
||||
if not t.is_derived():
|
||||
t.builder_set(self)
|
||||
new_targets.append(t)
|
||||
|
||||
orig_tlist = tlist[:]
|
||||
orig_slist = slist[:]
|
||||
|
||||
target, source = self.emitter(target=tlist, source=slist, env=env)
|
||||
|
||||
# Now delete the temporary builders that we attached to any
|
||||
# new targets, so that _node_errors() doesn't do weird stuff
|
||||
# to them because it thinks they already have builders.
|
||||
for t in new_targets:
|
||||
if t.builder is self:
|
||||
# Only delete the temporary builder if the emitter
|
||||
# didn't change it on us.
|
||||
t.builder_set(None)
|
||||
|
||||
# Have to call arg2nodes yet again, since it is legal for
|
||||
# emitters to spit out strings as well as Node instances.
|
||||
tlist = env.arg2nodes(target, target_factory,
|
||||
target=orig_tlist, source=orig_slist)
|
||||
slist = env.arg2nodes(source, source_factory,
|
||||
target=orig_tlist, source=orig_slist)
|
||||
|
||||
return tlist, slist
|
||||
|
||||
def _execute(self, env, target, source, overwarn={}, executor_kw={}):
|
||||
# We now assume that target and source are lists or None.
|
||||
if self.src_builder:
|
||||
source = self.src_builder_sources(env, source, overwarn)
|
||||
|
||||
if self.single_source and len(source) > 1 and target is None:
|
||||
result = []
|
||||
if target is None: target = [None]*len(source)
|
||||
for tgt, src in zip(target, source):
|
||||
if tgt is not None:
|
||||
tgt = [tgt]
|
||||
if src is not None:
|
||||
src = [src]
|
||||
result.extend(self._execute(env, tgt, src, overwarn))
|
||||
return SCons.Node.NodeList(result)
|
||||
|
||||
overwarn.warn()
|
||||
|
||||
tlist, slist = self._create_nodes(env, target, source)
|
||||
|
||||
# If there is more than one target ensure that if we need to reset
|
||||
# the implicit list to new scan of dependency all targets implicit lists
|
||||
# are cleared. (SCons GH Issue #2811 and MongoDB SERVER-33111)
|
||||
if len(tlist) > 1:
|
||||
for t in tlist:
|
||||
t.target_peers = tlist
|
||||
|
||||
# Check for errors with the specified target/source lists.
|
||||
_node_errors(self, env, tlist, slist)
|
||||
|
||||
# The targets are fine, so find or make the appropriate Executor to
|
||||
# build this particular list of targets from this particular list of
|
||||
# sources.
|
||||
|
||||
executor = None
|
||||
key = None
|
||||
|
||||
if self.multi:
|
||||
try:
|
||||
executor = tlist[0].get_executor(create = 0)
|
||||
except (AttributeError, IndexError):
|
||||
pass
|
||||
else:
|
||||
executor.add_sources(slist)
|
||||
|
||||
if executor is None:
|
||||
if not self.action:
|
||||
fmt = "Builder %s must have an action to build %s."
|
||||
raise UserError(fmt % (self.get_name(env or self.env),
|
||||
list(map(str,tlist))))
|
||||
key = self.action.batch_key(env or self.env, tlist, slist)
|
||||
if key:
|
||||
try:
|
||||
executor = SCons.Executor.GetBatchExecutor(key)
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
executor.add_batch(tlist, slist)
|
||||
|
||||
if executor is None:
|
||||
executor = SCons.Executor.Executor(self.action, env, [],
|
||||
tlist, slist, executor_kw)
|
||||
if key:
|
||||
SCons.Executor.AddBatchExecutor(key, executor)
|
||||
|
||||
# Now set up the relevant information in the target Nodes themselves.
|
||||
for t in tlist:
|
||||
t.cwd = env.fs.getcwd()
|
||||
t.builder_set(self)
|
||||
t.env_set(env)
|
||||
t.add_source(slist)
|
||||
t.set_executor(executor)
|
||||
t.set_explicit(self.is_explicit)
|
||||
|
||||
return SCons.Node.NodeList(tlist)
|
||||
|
||||
def __call__(self, env, target=None, source=None, chdir=_null, **kw):
|
||||
# We now assume that target and source are lists or None.
|
||||
# The caller (typically Environment.BuilderWrapper) is
|
||||
# responsible for converting any scalar values to lists.
|
||||
if chdir is _null:
|
||||
ekw = self.executor_kw
|
||||
else:
|
||||
ekw = self.executor_kw.copy()
|
||||
ekw['chdir'] = chdir
|
||||
if 'chdir' in ekw and SCons.Util.is_String(ekw['chdir']):
|
||||
ekw['chdir'] = env.subst(ekw['chdir'])
|
||||
if kw:
|
||||
if 'srcdir' in kw:
|
||||
def prependDirIfRelative(f, srcdir=kw['srcdir']):
|
||||
import os.path
|
||||
if SCons.Util.is_String(f) and not os.path.isabs(f):
|
||||
f = os.path.join(srcdir, f)
|
||||
return f
|
||||
if not SCons.Util.is_List(source):
|
||||
source = [source]
|
||||
source = list(map(prependDirIfRelative, source))
|
||||
del kw['srcdir']
|
||||
if self.overrides:
|
||||
env_kw = self.overrides.copy()
|
||||
env_kw.update(kw)
|
||||
else:
|
||||
env_kw = kw
|
||||
else:
|
||||
env_kw = self.overrides
|
||||
|
||||
# TODO if env_kw: then the following line. there's no purpose in calling if no overrides.
|
||||
env = env.Override(env_kw)
|
||||
return self._execute(env, target, source, OverrideWarner(kw), ekw)
|
||||
|
||||
def adjust_suffix(self, suff):
|
||||
if suff and not suff[0] in [ '.', '_', '$' ]:
|
||||
return '.' + suff
|
||||
return suff
|
||||
|
||||
def get_prefix(self, env, sources=[]):
|
||||
prefix = self.prefix
|
||||
if callable(prefix):
|
||||
prefix = prefix(env, sources)
|
||||
return env.subst(prefix)
|
||||
|
||||
def set_suffix(self, suffix):
|
||||
if not callable(suffix):
|
||||
suffix = self.adjust_suffix(suffix)
|
||||
self.suffix = suffix
|
||||
|
||||
def get_suffix(self, env, sources=[]):
|
||||
suffix = self.suffix
|
||||
if callable(suffix):
|
||||
suffix = suffix(env, sources)
|
||||
return env.subst(suffix)
|
||||
|
||||
def set_src_suffix(self, src_suffix):
|
||||
if not src_suffix:
|
||||
src_suffix = []
|
||||
elif not SCons.Util.is_List(src_suffix):
|
||||
src_suffix = [ src_suffix ]
|
||||
self.src_suffix = [callable(suf) and suf or self.adjust_suffix(suf) for suf in src_suffix]
|
||||
|
||||
def get_src_suffix(self, env):
|
||||
"""Get the first src_suffix in the list of src_suffixes."""
|
||||
ret = self.src_suffixes(env)
|
||||
if not ret:
|
||||
return ''
|
||||
return ret[0]
|
||||
|
||||
def add_emitter(self, suffix, emitter):
|
||||
"""Add a suffix-emitter mapping to this Builder.
|
||||
|
||||
This assumes that emitter has been initialized with an
|
||||
appropriate dictionary type, and will throw a TypeError if
|
||||
not, so the caller is responsible for knowing that this is an
|
||||
appropriate method to call for the Builder in question.
|
||||
"""
|
||||
self.emitter[suffix] = emitter
|
||||
|
||||
def add_src_builder(self, builder):
|
||||
"""
|
||||
Add a new Builder to the list of src_builders.
|
||||
|
||||
This requires wiping out cached values so that the computed
|
||||
lists of source suffixes get re-calculated.
|
||||
"""
|
||||
self._memo = {}
|
||||
self.src_builder.append(builder)
|
||||
|
||||
def _get_sdict(self, env):
|
||||
"""
|
||||
Returns a dictionary mapping all of the source suffixes of all
|
||||
src_builders of this Builder to the underlying Builder that
|
||||
should be called first.
|
||||
|
||||
This dictionary is used for each target specified, so we save a
|
||||
lot of extra computation by memoizing it for each construction
|
||||
environment.
|
||||
|
||||
Note that this is re-computed each time, not cached, because there
|
||||
might be changes to one of our source Builders (or one of their
|
||||
source Builders, and so on, and so on...) that we can't "see."
|
||||
|
||||
The underlying methods we call cache their computed values,
|
||||
though, so we hope repeatedly aggregating them into a dictionary
|
||||
like this won't be too big a hit. We may need to look for a
|
||||
better way to do this if performance data show this has turned
|
||||
into a significant bottleneck.
|
||||
"""
|
||||
sdict = {}
|
||||
for bld in self.get_src_builders(env):
|
||||
for suf in bld.src_suffixes(env):
|
||||
sdict[suf] = bld
|
||||
return sdict
|
||||
|
||||
def src_builder_sources(self, env, source, overwarn={}):
|
||||
sdict = self._get_sdict(env)
|
||||
|
||||
src_suffixes = self.src_suffixes(env)
|
||||
|
||||
lengths = list(set(map(len, src_suffixes)))
|
||||
|
||||
def match_src_suffix(name, src_suffixes=src_suffixes, lengths=lengths):
|
||||
node_suffixes = [name[-l:] for l in lengths]
|
||||
for suf in src_suffixes:
|
||||
if suf in node_suffixes:
|
||||
return suf
|
||||
return None
|
||||
|
||||
result = []
|
||||
for s in SCons.Util.flatten(source):
|
||||
if SCons.Util.is_String(s):
|
||||
match_suffix = match_src_suffix(env.subst(s))
|
||||
if not match_suffix and '.' not in s:
|
||||
src_suf = self.get_src_suffix(env)
|
||||
s = self._adjustixes(s, None, src_suf)[0]
|
||||
else:
|
||||
match_suffix = match_src_suffix(s.name)
|
||||
if match_suffix:
|
||||
try:
|
||||
bld = sdict[match_suffix]
|
||||
except KeyError:
|
||||
result.append(s)
|
||||
else:
|
||||
tlist = bld._execute(env, None, [s], overwarn)
|
||||
# If the subsidiary Builder returned more than one
|
||||
# target, then filter out any sources that this
|
||||
# Builder isn't capable of building.
|
||||
if len(tlist) > 1:
|
||||
tlist = [t for t in tlist if match_src_suffix(t.name)]
|
||||
result.extend(tlist)
|
||||
else:
|
||||
result.append(s)
|
||||
|
||||
source_factory = env.get_factory(self.source_factory)
|
||||
|
||||
return env.arg2nodes(result, source_factory)
|
||||
|
||||
def _get_src_builders_key(self, env):
|
||||
return id(env)
|
||||
|
||||
@SCons.Memoize.CountDictCall(_get_src_builders_key)
|
||||
def get_src_builders(self, env):
|
||||
"""
|
||||
Returns the list of source Builders for this Builder.
|
||||
|
||||
This exists mainly to look up Builders referenced as
|
||||
strings in the 'BUILDER' variable of the construction
|
||||
environment and cache the result.
|
||||
"""
|
||||
memo_key = id(env)
|
||||
try:
|
||||
memo_dict = self._memo['get_src_builders']
|
||||
except KeyError:
|
||||
memo_dict = {}
|
||||
self._memo['get_src_builders'] = memo_dict
|
||||
else:
|
||||
try:
|
||||
return memo_dict[memo_key]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
builders = []
|
||||
for bld in self.src_builder:
|
||||
if SCons.Util.is_String(bld):
|
||||
try:
|
||||
bld = env['BUILDERS'][bld]
|
||||
except KeyError:
|
||||
continue
|
||||
builders.append(bld)
|
||||
|
||||
memo_dict[memo_key] = builders
|
||||
return builders
|
||||
|
||||
def _subst_src_suffixes_key(self, env):
|
||||
return id(env)
|
||||
|
||||
@SCons.Memoize.CountDictCall(_subst_src_suffixes_key)
|
||||
def subst_src_suffixes(self, env):
|
||||
"""
|
||||
The suffix list may contain construction variable expansions,
|
||||
so we have to evaluate the individual strings. To avoid doing
|
||||
this over and over, we memoize the results for each construction
|
||||
environment.
|
||||
"""
|
||||
memo_key = id(env)
|
||||
try:
|
||||
memo_dict = self._memo['subst_src_suffixes']
|
||||
except KeyError:
|
||||
memo_dict = {}
|
||||
self._memo['subst_src_suffixes'] = memo_dict
|
||||
else:
|
||||
try:
|
||||
return memo_dict[memo_key]
|
||||
except KeyError:
|
||||
pass
|
||||
suffixes = [env.subst(x) for x in self.src_suffix]
|
||||
memo_dict[memo_key] = suffixes
|
||||
return suffixes
|
||||
|
||||
def src_suffixes(self, env):
|
||||
"""
|
||||
Returns the list of source suffixes for all src_builders of this
|
||||
Builder.
|
||||
|
||||
This is essentially a recursive descent of the src_builder "tree."
|
||||
(This value isn't cached because there may be changes in a
|
||||
src_builder many levels deep that we can't see.)
|
||||
"""
|
||||
sdict = {}
|
||||
suffixes = self.subst_src_suffixes(env)
|
||||
for s in suffixes:
|
||||
sdict[s] = 1
|
||||
for builder in self.get_src_builders(env):
|
||||
for s in builder.src_suffixes(env):
|
||||
if s not in sdict:
|
||||
sdict[s] = 1
|
||||
suffixes.append(s)
|
||||
return suffixes
|
||||
|
||||
class CompositeBuilder(SCons.Util.Proxy):
|
||||
"""A Builder Proxy whose main purpose is to always have
|
||||
a DictCmdGenerator as its action, and to provide access
|
||||
to the DictCmdGenerator's add_action() method.
|
||||
"""
|
||||
|
||||
def __init__(self, builder, cmdgen):
|
||||
if SCons.Debug.track_instances: logInstanceCreation(self, 'Builder.CompositeBuilder')
|
||||
SCons.Util.Proxy.__init__(self, builder)
|
||||
|
||||
# cmdgen should always be an instance of DictCmdGenerator.
|
||||
self.cmdgen = cmdgen
|
||||
self.builder = builder
|
||||
|
||||
__call__ = SCons.Util.Delegate('__call__')
|
||||
|
||||
def add_action(self, suffix, action):
|
||||
self.cmdgen.add_action(suffix, action)
|
||||
self.set_src_suffix(self.cmdgen.src_suffixes())
|
||||
|
||||
def is_a_Builder(obj):
|
||||
""""Returns True if the specified obj is one of our Builder classes.
|
||||
|
||||
The test is complicated a bit by the fact that CompositeBuilder
|
||||
is a proxy, not a subclass of BuilderBase.
|
||||
"""
|
||||
return (isinstance(obj, BuilderBase)
|
||||
or isinstance(obj, CompositeBuilder)
|
||||
or callable(obj))
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
298
scons/scons-local-4.0.1/SCons/CacheDir.py
Normal file
298
scons/scons-local-4.0.1/SCons/CacheDir.py
Normal file
|
@ -0,0 +1,298 @@
|
|||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
__doc__ = """
|
||||
CacheDir support
|
||||
"""
|
||||
|
||||
import atexit
|
||||
import json
|
||||
import os
|
||||
import stat
|
||||
import sys
|
||||
|
||||
import SCons.Action
|
||||
import SCons.Errors
|
||||
import SCons.Warnings
|
||||
|
||||
cache_enabled = True
|
||||
cache_debug = False
|
||||
cache_force = False
|
||||
cache_show = False
|
||||
cache_readonly = False
|
||||
|
||||
def CacheRetrieveFunc(target, source, env):
|
||||
t = target[0]
|
||||
fs = t.fs
|
||||
cd = env.get_CacheDir()
|
||||
cd.requests += 1
|
||||
cachedir, cachefile = cd.cachepath(t)
|
||||
if not fs.exists(cachefile):
|
||||
cd.CacheDebug('CacheRetrieve(%s): %s not in cache\n', t, cachefile)
|
||||
return 1
|
||||
cd.hits += 1
|
||||
cd.CacheDebug('CacheRetrieve(%s): retrieving from %s\n', t, cachefile)
|
||||
if SCons.Action.execute_actions:
|
||||
if fs.islink(cachefile):
|
||||
fs.symlink(fs.readlink(cachefile), t.get_internal_path())
|
||||
else:
|
||||
env.copy_from_cache(cachefile, t.get_internal_path())
|
||||
try:
|
||||
os.utime(cachefile, None)
|
||||
except OSError:
|
||||
pass
|
||||
st = fs.stat(cachefile)
|
||||
fs.chmod(t.get_internal_path(), stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
|
||||
return 0
|
||||
|
||||
def CacheRetrieveString(target, source, env):
|
||||
t = target[0]
|
||||
fs = t.fs
|
||||
cd = env.get_CacheDir()
|
||||
cachedir, cachefile = cd.cachepath(t)
|
||||
if t.fs.exists(cachefile):
|
||||
return "Retrieved `%s' from cache" % t.get_internal_path()
|
||||
return None
|
||||
|
||||
CacheRetrieve = SCons.Action.Action(CacheRetrieveFunc, CacheRetrieveString)
|
||||
|
||||
CacheRetrieveSilent = SCons.Action.Action(CacheRetrieveFunc, None)
|
||||
|
||||
def CachePushFunc(target, source, env):
|
||||
if cache_readonly:
|
||||
return
|
||||
|
||||
t = target[0]
|
||||
if t.nocache:
|
||||
return
|
||||
fs = t.fs
|
||||
cd = env.get_CacheDir()
|
||||
cachedir, cachefile = cd.cachepath(t)
|
||||
if fs.exists(cachefile):
|
||||
# Don't bother copying it if it's already there. Note that
|
||||
# usually this "shouldn't happen" because if the file already
|
||||
# existed in cache, we'd have retrieved the file from there,
|
||||
# not built it. This can happen, though, in a race, if some
|
||||
# other person running the same build pushes their copy to
|
||||
# the cache after we decide we need to build it but before our
|
||||
# build completes.
|
||||
cd.CacheDebug('CachePush(%s): %s already exists in cache\n', t, cachefile)
|
||||
return
|
||||
|
||||
cd.CacheDebug('CachePush(%s): pushing to %s\n', t, cachefile)
|
||||
|
||||
tempfile = cachefile+'.tmp'+str(os.getpid())
|
||||
errfmt = "Unable to copy %s to cache. Cache file is %s"
|
||||
|
||||
if not fs.isdir(cachedir):
|
||||
try:
|
||||
fs.makedirs(cachedir)
|
||||
except EnvironmentError:
|
||||
# We may have received an exception because another process
|
||||
# has beaten us creating the directory.
|
||||
if not fs.isdir(cachedir):
|
||||
msg = errfmt % (str(target), cachefile)
|
||||
raise SCons.Errors.SConsEnvironmentError(msg)
|
||||
|
||||
try:
|
||||
if fs.islink(t.get_internal_path()):
|
||||
fs.symlink(fs.readlink(t.get_internal_path()), tempfile)
|
||||
else:
|
||||
fs.copy2(t.get_internal_path(), tempfile)
|
||||
fs.rename(tempfile, cachefile)
|
||||
st = fs.stat(t.get_internal_path())
|
||||
fs.chmod(cachefile, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
|
||||
except EnvironmentError:
|
||||
# It's possible someone else tried writing the file at the
|
||||
# same time we did, or else that there was some problem like
|
||||
# the CacheDir being on a separate file system that's full.
|
||||
# In any case, inability to push a file to cache doesn't affect
|
||||
# the correctness of the build, so just print a warning.
|
||||
msg = errfmt % (str(target), cachefile)
|
||||
SCons.Warnings.warn(SCons.Warnings.CacheWriteErrorWarning, msg)
|
||||
|
||||
CachePush = SCons.Action.Action(CachePushFunc, None)
|
||||
|
||||
|
||||
class CacheDir:
|
||||
|
||||
def __init__(self, path):
|
||||
"""
|
||||
Initialize a CacheDir object.
|
||||
|
||||
The cache configuration is stored in the object. It
|
||||
is read from the config file in the supplied path if
|
||||
one exists, if not the config file is created and
|
||||
the default config is written, as well as saved in the object.
|
||||
"""
|
||||
self.requests = 0
|
||||
self.hits = 0
|
||||
self.path = path
|
||||
self.current_cache_debug = None
|
||||
self.debugFP = None
|
||||
self.config = dict()
|
||||
if path is None:
|
||||
return
|
||||
|
||||
self._readconfig(path)
|
||||
|
||||
|
||||
def _readconfig(self, path):
|
||||
"""
|
||||
Read the cache config.
|
||||
|
||||
If directory or config file do not exist, create. Take advantage
|
||||
of Py3 capability in os.makedirs() and in file open(): just try
|
||||
the operation and handle failure appropriately.
|
||||
|
||||
Omit the check for old cache format, assume that's old enough
|
||||
there will be none of those left to worry about.
|
||||
|
||||
:param path: path to the cache directory
|
||||
"""
|
||||
config_file = os.path.join(path, 'config')
|
||||
try:
|
||||
os.makedirs(path, exist_ok=True)
|
||||
except FileExistsError:
|
||||
pass
|
||||
except OSError:
|
||||
msg = "Failed to create cache directory " + path
|
||||
raise SCons.Errors.SConsEnvironmentError(msg)
|
||||
|
||||
try:
|
||||
with open(config_file, 'x') as config:
|
||||
self.config['prefix_len'] = 2
|
||||
try:
|
||||
json.dump(self.config, config)
|
||||
except Exception:
|
||||
msg = "Failed to write cache configuration for " + path
|
||||
raise SCons.Errors.SConsEnvironmentError(msg)
|
||||
except FileExistsError:
|
||||
try:
|
||||
with open(config_file) as config:
|
||||
self.config = json.load(config)
|
||||
except ValueError:
|
||||
msg = "Failed to read cache configuration for " + path
|
||||
raise SCons.Errors.SConsEnvironmentError(msg)
|
||||
|
||||
|
||||
def CacheDebug(self, fmt, target, cachefile):
|
||||
if cache_debug != self.current_cache_debug:
|
||||
if cache_debug == '-':
|
||||
self.debugFP = sys.stdout
|
||||
elif cache_debug:
|
||||
def debug_cleanup(debugFP):
|
||||
debugFP.close()
|
||||
|
||||
self.debugFP = open(cache_debug, 'w')
|
||||
atexit.register(debug_cleanup, self.debugFP)
|
||||
else:
|
||||
self.debugFP = None
|
||||
self.current_cache_debug = cache_debug
|
||||
if self.debugFP:
|
||||
self.debugFP.write(fmt % (target, os.path.split(cachefile)[1]))
|
||||
self.debugFP.write("requests: %d, hits: %d, misses: %d, hit rate: %.2f%%\n" %
|
||||
(self.requests, self.hits, self.misses, self.hit_ratio))
|
||||
|
||||
@property
|
||||
def hit_ratio(self):
|
||||
return (100.0 * self.hits / self.requests if self.requests > 0 else 100)
|
||||
|
||||
@property
|
||||
def misses(self):
|
||||
return self.requests - self.hits
|
||||
|
||||
def is_enabled(self):
|
||||
return cache_enabled and self.path is not None
|
||||
|
||||
def is_readonly(self):
|
||||
return cache_readonly
|
||||
|
||||
def cachepath(self, node):
|
||||
"""
|
||||
"""
|
||||
if not self.is_enabled():
|
||||
return None, None
|
||||
|
||||
sig = node.get_cachedir_bsig()
|
||||
|
||||
subdir = sig[:self.config['prefix_len']].upper()
|
||||
|
||||
dir = os.path.join(self.path, subdir)
|
||||
return dir, os.path.join(dir, sig)
|
||||
|
||||
def retrieve(self, node):
|
||||
"""
|
||||
This method is called from multiple threads in a parallel build,
|
||||
so only do thread safe stuff here. Do thread unsafe stuff in
|
||||
built().
|
||||
|
||||
Note that there's a special trick here with the execute flag
|
||||
(one that's not normally done for other actions). Basically
|
||||
if the user requested a no_exec (-n) build, then
|
||||
SCons.Action.execute_actions is set to 0 and when any action
|
||||
is called, it does its showing but then just returns zero
|
||||
instead of actually calling the action execution operation.
|
||||
The problem for caching is that if the file does NOT exist in
|
||||
cache then the CacheRetrieveString won't return anything to
|
||||
show for the task, but the Action.__call__ won't call
|
||||
CacheRetrieveFunc; instead it just returns zero, which makes
|
||||
the code below think that the file *was* successfully
|
||||
retrieved from the cache, therefore it doesn't do any
|
||||
subsequent building. However, the CacheRetrieveString didn't
|
||||
print anything because it didn't actually exist in the cache,
|
||||
and no more build actions will be performed, so the user just
|
||||
sees nothing. The fix is to tell Action.__call__ to always
|
||||
execute the CacheRetrieveFunc and then have the latter
|
||||
explicitly check SCons.Action.execute_actions itself.
|
||||
"""
|
||||
if not self.is_enabled():
|
||||
return False
|
||||
|
||||
env = node.get_build_env()
|
||||
if cache_show:
|
||||
if CacheRetrieveSilent(node, [], env, execute=1) == 0:
|
||||
node.build(presub=0, execute=0)
|
||||
return True
|
||||
else:
|
||||
if CacheRetrieve(node, [], env, execute=1) == 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def push(self, node):
|
||||
if self.is_readonly() or not self.is_enabled():
|
||||
return
|
||||
return CachePush(node, [], node.get_build_env())
|
||||
|
||||
def push_if_forced(self, node):
|
||||
if cache_force:
|
||||
return self.push(node)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
816
scons/scons-local-4.0.1/SCons/Conftest.py
Normal file
816
scons/scons-local-4.0.1/SCons/Conftest.py
Normal file
|
@ -0,0 +1,816 @@
|
|||
"""SCons.Conftest
|
||||
|
||||
Autoconf-like configuration support; low level implementation of tests.
|
||||
"""
|
||||
|
||||
#
|
||||
# Copyright (c) 2003 Stichting NLnet Labs
|
||||
# Copyright (c) 2001, 2002, 2003 Steven Knight
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
#
|
||||
# The purpose of this module is to define how a check is to be performed.
|
||||
# Use one of the Check...() functions below.
|
||||
#
|
||||
|
||||
#
|
||||
# A context class is used that defines functions for carrying out the tests,
|
||||
# logging and messages. The following methods and members must be present:
|
||||
#
|
||||
# context.Display(msg) Function called to print messages that are normally
|
||||
# displayed for the user. Newlines are explicitly used.
|
||||
# The text should also be written to the logfile!
|
||||
#
|
||||
# context.Log(msg) Function called to write to a log file.
|
||||
#
|
||||
# context.BuildProg(text, ext)
|
||||
# Function called to build a program, using "ext" for the
|
||||
# file extention. Must return an empty string for
|
||||
# success, an error message for failure.
|
||||
# For reliable test results building should be done just
|
||||
# like an actual program would be build, using the same
|
||||
# command and arguments (including configure results so
|
||||
# far).
|
||||
#
|
||||
# context.CompileProg(text, ext)
|
||||
# Function called to compile a program, using "ext" for
|
||||
# the file extention. Must return an empty string for
|
||||
# success, an error message for failure.
|
||||
# For reliable test results compiling should be done just
|
||||
# like an actual source file would be compiled, using the
|
||||
# same command and arguments (including configure results
|
||||
# so far).
|
||||
#
|
||||
# context.AppendLIBS(lib_name_list)
|
||||
# Append "lib_name_list" to the value of LIBS.
|
||||
# "lib_namelist" is a list of strings.
|
||||
# Return the value of LIBS before changing it (any type
|
||||
# can be used, it is passed to SetLIBS() later.)
|
||||
#
|
||||
# context.PrependLIBS(lib_name_list)
|
||||
# Prepend "lib_name_list" to the value of LIBS.
|
||||
# "lib_namelist" is a list of strings.
|
||||
# Return the value of LIBS before changing it (any type
|
||||
# can be used, it is passed to SetLIBS() later.)
|
||||
#
|
||||
# context.SetLIBS(value)
|
||||
# Set LIBS to "value". The type of "value" is what
|
||||
# AppendLIBS() returned.
|
||||
# Return the value of LIBS before changing it (any type
|
||||
# can be used, it is passed to SetLIBS() later.)
|
||||
#
|
||||
# context.headerfilename
|
||||
# Name of file to append configure results to, usually
|
||||
# "confdefs.h".
|
||||
# The file must not exist or be empty when starting.
|
||||
# Empty or None to skip this (some tests will not work!).
|
||||
#
|
||||
# context.config_h (may be missing). If present, must be a string, which
|
||||
# will be filled with the contents of a config_h file.
|
||||
#
|
||||
# context.vardict Dictionary holding variables used for the tests and
|
||||
# stores results from the tests, used for the build
|
||||
# commands.
|
||||
# Normally contains "CC", "LIBS", "CPPFLAGS", etc.
|
||||
#
|
||||
# context.havedict Dictionary holding results from the tests that are to
|
||||
# be used inside a program.
|
||||
# Names often start with "HAVE_". These are zero
|
||||
# (feature not present) or one (feature present). Other
|
||||
# variables may have any value, e.g., "PERLVERSION" can
|
||||
# be a number and "SYSTEMNAME" a string.
|
||||
#
|
||||
|
||||
import re
|
||||
|
||||
#
|
||||
# PUBLIC VARIABLES
|
||||
#
|
||||
|
||||
LogInputFiles = 1 # Set that to log the input files in case of a failed test
|
||||
LogErrorMessages = 1 # Set that to log Conftest-generated error messages
|
||||
|
||||
#
|
||||
# PUBLIC FUNCTIONS
|
||||
#
|
||||
|
||||
# Generic remarks:
|
||||
# - When a language is specified which is not supported the test fails. The
|
||||
# message is a bit different, because not all the arguments for the normal
|
||||
# message are available yet (chicken-egg problem).
|
||||
|
||||
|
||||
def CheckBuilder(context, text = None, language = None):
|
||||
"""
|
||||
Configure check to see if the compiler works.
|
||||
Note that this uses the current value of compiler and linker flags, make
|
||||
sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
|
||||
"language" should be "C" or "C++" and is used to select the compiler.
|
||||
Default is "C".
|
||||
"text" may be used to specify the code to be build.
|
||||
Returns an empty string for success, an error message for failure.
|
||||
"""
|
||||
lang, suffix, msg = _lang2suffix(language)
|
||||
if msg:
|
||||
context.Display("%s\n" % msg)
|
||||
return msg
|
||||
|
||||
if not text:
|
||||
text = """
|
||||
int main(void) {
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
|
||||
context.Display("Checking if building a %s file works... " % lang)
|
||||
ret = context.BuildProg(text, suffix)
|
||||
_YesNoResult(context, ret, None, text)
|
||||
return ret
|
||||
|
||||
def CheckCC(context):
|
||||
"""
|
||||
Configure check for a working C compiler.
|
||||
|
||||
This checks whether the C compiler, as defined in the $CC construction
|
||||
variable, can compile a C source file. It uses the current $CCCOM value
|
||||
too, so that it can test against non working flags.
|
||||
|
||||
"""
|
||||
context.Display("Checking whether the C compiler works... ")
|
||||
text = """
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
ret = _check_empty_program(context, 'CC', text, 'C')
|
||||
_YesNoResult(context, ret, None, text)
|
||||
return ret
|
||||
|
||||
def CheckSHCC(context):
|
||||
"""
|
||||
Configure check for a working shared C compiler.
|
||||
|
||||
This checks whether the C compiler, as defined in the $SHCC construction
|
||||
variable, can compile a C source file. It uses the current $SHCCCOM value
|
||||
too, so that it can test against non working flags.
|
||||
|
||||
"""
|
||||
context.Display("Checking whether the (shared) C compiler works... ")
|
||||
text = """
|
||||
int foo(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
ret = _check_empty_program(context, 'SHCC', text, 'C', use_shared = True)
|
||||
_YesNoResult(context, ret, None, text)
|
||||
return ret
|
||||
|
||||
def CheckCXX(context):
|
||||
"""
|
||||
Configure check for a working CXX compiler.
|
||||
|
||||
This checks whether the CXX compiler, as defined in the $CXX construction
|
||||
variable, can compile a CXX source file. It uses the current $CXXCOM value
|
||||
too, so that it can test against non working flags.
|
||||
|
||||
"""
|
||||
context.Display("Checking whether the C++ compiler works... ")
|
||||
text = """
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
ret = _check_empty_program(context, 'CXX', text, 'C++')
|
||||
_YesNoResult(context, ret, None, text)
|
||||
return ret
|
||||
|
||||
def CheckSHCXX(context):
|
||||
"""
|
||||
Configure check for a working shared CXX compiler.
|
||||
|
||||
This checks whether the CXX compiler, as defined in the $SHCXX construction
|
||||
variable, can compile a CXX source file. It uses the current $SHCXXCOM value
|
||||
too, so that it can test against non working flags.
|
||||
|
||||
"""
|
||||
context.Display("Checking whether the (shared) C++ compiler works... ")
|
||||
text = """
|
||||
int main(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
ret = _check_empty_program(context, 'SHCXX', text, 'C++', use_shared = True)
|
||||
_YesNoResult(context, ret, None, text)
|
||||
return ret
|
||||
|
||||
def _check_empty_program(context, comp, text, language, use_shared = False):
|
||||
"""Return 0 on success, 1 otherwise."""
|
||||
if comp not in context.env or not context.env[comp]:
|
||||
# The compiler construction variable is not set or empty
|
||||
return 1
|
||||
|
||||
lang, suffix, msg = _lang2suffix(language)
|
||||
if msg:
|
||||
return 1
|
||||
|
||||
if use_shared:
|
||||
return context.CompileSharedObject(text, suffix)
|
||||
else:
|
||||
return context.CompileProg(text, suffix)
|
||||
|
||||
|
||||
def CheckFunc(context, function_name, header = None, language = None):
|
||||
"""
|
||||
Configure check for a function "function_name".
|
||||
"language" should be "C" or "C++" and is used to select the compiler.
|
||||
Default is "C".
|
||||
Optional "header" can be defined to define a function prototype, include a
|
||||
header file or anything else that comes before main().
|
||||
Sets HAVE_function_name in context.havedict according to the result.
|
||||
Note that this uses the current value of compiler and linker flags, make
|
||||
sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
|
||||
Returns an empty string for success, an error message for failure.
|
||||
"""
|
||||
|
||||
# Remarks from autoconf:
|
||||
# - Don't include <ctype.h> because on OSF/1 3.0 it includes <sys/types.h>
|
||||
# which includes <sys/select.h> which contains a prototype for select.
|
||||
# Similarly for bzero.
|
||||
# - assert.h is included to define __stub macros and hopefully few
|
||||
# prototypes, which can conflict with char $1(); below.
|
||||
# - Override any gcc2 internal prototype to avoid an error.
|
||||
# - We use char for the function declaration because int might match the
|
||||
# return type of a gcc2 builtin and then its argument prototype would
|
||||
# still apply.
|
||||
# - The GNU C library defines this for functions which it implements to
|
||||
# always fail with ENOSYS. Some functions are actually named something
|
||||
# starting with __ and the normal name is an alias.
|
||||
|
||||
if context.headerfilename:
|
||||
includetext = '#include "%s"' % context.headerfilename
|
||||
else:
|
||||
includetext = ''
|
||||
if not header:
|
||||
header = """
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char %s();""" % function_name
|
||||
|
||||
lang, suffix, msg = _lang2suffix(language)
|
||||
if msg:
|
||||
context.Display("Cannot check for %s(): %s\n" % (function_name, msg))
|
||||
return msg
|
||||
|
||||
text = """
|
||||
%(include)s
|
||||
#include <assert.h>
|
||||
%(hdr)s
|
||||
|
||||
#if _MSC_VER && !__INTEL_COMPILER
|
||||
#pragma function(%(name)s)
|
||||
#endif
|
||||
|
||||
int main(void) {
|
||||
#if defined (__stub_%(name)s) || defined (__stub___%(name)s)
|
||||
fail fail fail
|
||||
#else
|
||||
%(name)s();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
""" % { 'name': function_name,
|
||||
'include': includetext,
|
||||
'hdr': header }
|
||||
|
||||
context.Display("Checking for %s function %s()... " % (lang, function_name))
|
||||
ret = context.BuildProg(text, suffix)
|
||||
_YesNoResult(context, ret, "HAVE_" + function_name, text,
|
||||
"Define to 1 if the system has the function `%s'." %\
|
||||
function_name)
|
||||
return ret
|
||||
|
||||
|
||||
def CheckHeader(context, header_name, header=None, language=None,
|
||||
include_quotes=None):
|
||||
"""
|
||||
Configure check for a C or C++ header file "header_name".
|
||||
Optional "header" can be defined to do something before including the
|
||||
header file (unusual, supported for consistency).
|
||||
"language" should be "C" or "C++" and is used to select the compiler.
|
||||
Default is "C".
|
||||
Sets HAVE_header_name in context.havedict according to the result.
|
||||
Note that this uses the current value of compiler and linker flags, make
|
||||
sure $CFLAGS and $CPPFLAGS are set correctly.
|
||||
Returns an empty string for success, an error message for failure.
|
||||
"""
|
||||
# Why compile the program instead of just running the preprocessor?
|
||||
# It is possible that the header file exists, but actually using it may
|
||||
# fail (e.g., because it depends on other header files). Thus this test is
|
||||
# more strict. It may require using the "header" argument.
|
||||
#
|
||||
# Use <> by default, because the check is normally used for system header
|
||||
# files. SCons passes '""' to overrule this.
|
||||
|
||||
# Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
|
||||
if context.headerfilename:
|
||||
includetext = '#include "%s"\n' % context.headerfilename
|
||||
else:
|
||||
includetext = ''
|
||||
if not header:
|
||||
header = ""
|
||||
|
||||
lang, suffix, msg = _lang2suffix(language)
|
||||
if msg:
|
||||
context.Display("Cannot check for header file %s: %s\n"
|
||||
% (header_name, msg))
|
||||
return msg
|
||||
|
||||
if not include_quotes:
|
||||
include_quotes = "<>"
|
||||
|
||||
text = "%s%s\n#include %s%s%s\n\n" % (includetext, header,
|
||||
include_quotes[0], header_name, include_quotes[1])
|
||||
|
||||
context.Display("Checking for %s header file %s... " % (lang, header_name))
|
||||
ret = context.CompileProg(text, suffix)
|
||||
_YesNoResult(context, ret, "HAVE_" + header_name, text,
|
||||
"Define to 1 if you have the <%s> header file." % header_name)
|
||||
return ret
|
||||
|
||||
|
||||
def CheckType(context, type_name, fallback = None,
|
||||
header = None, language = None):
|
||||
"""
|
||||
Configure check for a C or C++ type "type_name".
|
||||
Optional "header" can be defined to include a header file.
|
||||
"language" should be "C" or "C++" and is used to select the compiler.
|
||||
Default is "C".
|
||||
Sets HAVE_type_name in context.havedict according to the result.
|
||||
Note that this uses the current value of compiler and linker flags, make
|
||||
sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
|
||||
Returns an empty string for success, an error message for failure.
|
||||
"""
|
||||
|
||||
# Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
|
||||
if context.headerfilename:
|
||||
includetext = '#include "%s"' % context.headerfilename
|
||||
else:
|
||||
includetext = ''
|
||||
if not header:
|
||||
header = ""
|
||||
|
||||
lang, suffix, msg = _lang2suffix(language)
|
||||
if msg:
|
||||
context.Display("Cannot check for %s type: %s\n" % (type_name, msg))
|
||||
return msg
|
||||
|
||||
# Remarks from autoconf about this test:
|
||||
# - Grepping for the type in include files is not reliable (grep isn't
|
||||
# portable anyway).
|
||||
# - Using "TYPE my_var;" doesn't work for const qualified types in C++.
|
||||
# Adding an initializer is not valid for some C++ classes.
|
||||
# - Using the type as parameter to a function either fails for K&$ C or for
|
||||
# C++.
|
||||
# - Using "TYPE *my_var;" is valid in C for some types that are not
|
||||
# declared (struct something).
|
||||
# - Using "sizeof(TYPE)" is valid when TYPE is actually a variable.
|
||||
# - Using the previous two together works reliably.
|
||||
text = """
|
||||
%(include)s
|
||||
%(header)s
|
||||
|
||||
int main(void) {
|
||||
if ((%(name)s *) 0)
|
||||
return 0;
|
||||
if (sizeof (%(name)s))
|
||||
return 0;
|
||||
}
|
||||
""" % { 'include': includetext,
|
||||
'header': header,
|
||||
'name': type_name }
|
||||
|
||||
context.Display("Checking for %s type %s... " % (lang, type_name))
|
||||
ret = context.BuildProg(text, suffix)
|
||||
_YesNoResult(context, ret, "HAVE_" + type_name, text,
|
||||
"Define to 1 if the system has the type `%s'." % type_name)
|
||||
if ret and fallback and context.headerfilename:
|
||||
f = open(context.headerfilename, "a")
|
||||
f.write("typedef %s %s;\n" % (fallback, type_name))
|
||||
f.close()
|
||||
|
||||
return ret
|
||||
|
||||
def CheckTypeSize(context, type_name, header = None, language = None, expect = None):
|
||||
"""This check can be used to get the size of a given type, or to check whether
|
||||
the type is of expected size.
|
||||
|
||||
Arguments:
|
||||
- type : str
|
||||
the type to check
|
||||
- includes : sequence
|
||||
list of headers to include in the test code before testing the type
|
||||
- language : str
|
||||
'C' or 'C++'
|
||||
- expect : int
|
||||
if given, will test wether the type has the given number of bytes.
|
||||
If not given, will automatically find the size.
|
||||
|
||||
Returns:
|
||||
status : int
|
||||
0 if the check failed, or the found size of the type if the check succeeded."""
|
||||
|
||||
# Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
|
||||
if context.headerfilename:
|
||||
includetext = '#include "%s"' % context.headerfilename
|
||||
else:
|
||||
includetext = ''
|
||||
|
||||
if not header:
|
||||
header = ""
|
||||
|
||||
lang, suffix, msg = _lang2suffix(language)
|
||||
if msg:
|
||||
context.Display("Cannot check for %s type: %s\n" % (type_name, msg))
|
||||
return msg
|
||||
|
||||
src = includetext + header
|
||||
if expect is not None:
|
||||
# Only check if the given size is the right one
|
||||
context.Display('Checking %s is %d bytes... ' % (type_name, expect))
|
||||
|
||||
# test code taken from autoconf: this is a pretty clever hack to find that
|
||||
# a type is of a given size using only compilation. This speeds things up
|
||||
# quite a bit compared to straightforward code using TryRun
|
||||
src = src + r"""
|
||||
typedef %s scons_check_type;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
static int test_array[1 - 2 * !(((long int) (sizeof(scons_check_type))) == %d)];
|
||||
test_array[0] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
|
||||
st = context.CompileProg(src % (type_name, expect), suffix)
|
||||
if not st:
|
||||
context.Display("yes\n")
|
||||
_Have(context, "SIZEOF_%s" % type_name, expect,
|
||||
"The size of `%s', as computed by sizeof." % type_name)
|
||||
return expect
|
||||
else:
|
||||
context.Display("no\n")
|
||||
_LogFailed(context, src, st)
|
||||
return 0
|
||||
else:
|
||||
# Only check if the given size is the right one
|
||||
context.Message('Checking size of %s ... ' % type_name)
|
||||
|
||||
# We have to be careful with the program we wish to test here since
|
||||
# compilation will be attempted using the current environment's flags.
|
||||
# So make sure that the program will compile without any warning. For
|
||||
# example using: 'int main(int argc, char** argv)' will fail with the
|
||||
# '-Wall -Werror' flags since the variables argc and argv would not be
|
||||
# used in the program...
|
||||
#
|
||||
src = src + """
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
int main(void) {
|
||||
printf("%d", (int)sizeof(""" + type_name + """));
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
st, out = context.RunProg(src, suffix)
|
||||
try:
|
||||
size = int(out)
|
||||
except ValueError:
|
||||
# If cannot convert output of test prog to an integer (the size),
|
||||
# something went wront, so just fail
|
||||
st = 1
|
||||
size = 0
|
||||
|
||||
if not st:
|
||||
context.Display("yes\n")
|
||||
_Have(context, "SIZEOF_%s" % type_name, size,
|
||||
"The size of `%s', as computed by sizeof." % type_name)
|
||||
return size
|
||||
else:
|
||||
context.Display("no\n")
|
||||
_LogFailed(context, src, st)
|
||||
return 0
|
||||
|
||||
return 0
|
||||
|
||||
def CheckDeclaration(context, symbol, includes = None, language = None):
|
||||
"""Checks whether symbol is declared.
|
||||
|
||||
Use the same test as autoconf, that is test whether the symbol is defined
|
||||
as a macro or can be used as an r-value.
|
||||
|
||||
Arguments:
|
||||
symbol : str
|
||||
the symbol to check
|
||||
includes : str
|
||||
Optional "header" can be defined to include a header file.
|
||||
language : str
|
||||
only C and C++ supported.
|
||||
|
||||
Returns:
|
||||
status : bool
|
||||
True if the check failed, False if succeeded."""
|
||||
|
||||
# Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
|
||||
if context.headerfilename:
|
||||
includetext = '#include "%s"' % context.headerfilename
|
||||
else:
|
||||
includetext = ''
|
||||
|
||||
if not includes:
|
||||
includes = ""
|
||||
|
||||
lang, suffix, msg = _lang2suffix(language)
|
||||
if msg:
|
||||
context.Display("Cannot check for declaration %s: %s\n" % (symbol, msg))
|
||||
return msg
|
||||
|
||||
src = includetext + includes
|
||||
context.Display('Checking whether %s is declared... ' % symbol)
|
||||
|
||||
src = src + r"""
|
||||
int main(void)
|
||||
{
|
||||
#ifndef %s
|
||||
(void) %s;
|
||||
#endif
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
""" % (symbol, symbol)
|
||||
|
||||
st = context.CompileProg(src, suffix)
|
||||
_YesNoResult(context, st, "HAVE_DECL_" + symbol, src,
|
||||
"Set to 1 if %s is defined." % symbol)
|
||||
return st
|
||||
|
||||
def CheckLib(context, libs, func_name = None, header = None,
|
||||
extra_libs = None, call = None, language = None, autoadd = 1,
|
||||
append = True):
|
||||
"""
|
||||
Configure check for a C or C++ libraries "libs". Searches through
|
||||
the list of libraries, until one is found where the test succeeds.
|
||||
Tests if "func_name" or "call" exists in the library. Note: if it exists
|
||||
in another library the test succeeds anyway!
|
||||
Optional "header" can be defined to include a header file. If not given a
|
||||
default prototype for "func_name" is added.
|
||||
Optional "extra_libs" is a list of library names to be added after
|
||||
"lib_name" in the build command. To be used for libraries that "lib_name"
|
||||
depends on.
|
||||
Optional "call" replaces the call to "func_name" in the test code. It must
|
||||
consist of complete C statements, including a trailing ";".
|
||||
Both "func_name" and "call" arguments are optional, and in that case, just
|
||||
linking against the libs is tested.
|
||||
"language" should be "C" or "C++" and is used to select the compiler.
|
||||
Default is "C".
|
||||
Note that this uses the current value of compiler and linker flags, make
|
||||
sure $CFLAGS, $CPPFLAGS and $LIBS are set correctly.
|
||||
Returns an empty string for success, an error message for failure.
|
||||
"""
|
||||
# Include "confdefs.h" first, so that the header can use HAVE_HEADER_H.
|
||||
if context.headerfilename:
|
||||
includetext = '#include "%s"' % context.headerfilename
|
||||
else:
|
||||
includetext = ''
|
||||
if not header:
|
||||
header = ""
|
||||
|
||||
text = """
|
||||
%s
|
||||
%s""" % (includetext, header)
|
||||
|
||||
# Add a function declaration if needed.
|
||||
if func_name and func_name != "main":
|
||||
if not header:
|
||||
text = text + """
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char %s();
|
||||
""" % func_name
|
||||
|
||||
# The actual test code.
|
||||
if not call:
|
||||
call = "%s();" % func_name
|
||||
|
||||
# if no function to test, leave main() blank
|
||||
text = text + """
|
||||
int
|
||||
main() {
|
||||
%s
|
||||
return 0;
|
||||
}
|
||||
""" % (call or "")
|
||||
|
||||
if call:
|
||||
i = call.find("\n")
|
||||
if i > 0:
|
||||
calltext = call[:i] + ".."
|
||||
elif call[-1] == ';':
|
||||
calltext = call[:-1]
|
||||
else:
|
||||
calltext = call
|
||||
|
||||
for lib_name in libs:
|
||||
|
||||
lang, suffix, msg = _lang2suffix(language)
|
||||
if msg:
|
||||
context.Display("Cannot check for library %s: %s\n" % (lib_name, msg))
|
||||
return msg
|
||||
|
||||
# if a function was specified to run in main(), say it
|
||||
if call:
|
||||
context.Display("Checking for %s in %s library %s... "
|
||||
% (calltext, lang, lib_name))
|
||||
# otherwise, just say the name of library and language
|
||||
else:
|
||||
context.Display("Checking for %s library %s... "
|
||||
% (lang, lib_name))
|
||||
|
||||
if lib_name:
|
||||
l = [ lib_name ]
|
||||
if extra_libs:
|
||||
l.extend(extra_libs)
|
||||
if append:
|
||||
oldLIBS = context.AppendLIBS(l)
|
||||
else:
|
||||
oldLIBS = context.PrependLIBS(l)
|
||||
sym = "HAVE_LIB" + lib_name
|
||||
else:
|
||||
oldLIBS = -1
|
||||
sym = None
|
||||
|
||||
ret = context.BuildProg(text, suffix)
|
||||
|
||||
_YesNoResult(context, ret, sym, text,
|
||||
"Define to 1 if you have the `%s' library." % lib_name)
|
||||
if oldLIBS != -1 and (ret or not autoadd):
|
||||
context.SetLIBS(oldLIBS)
|
||||
|
||||
if not ret:
|
||||
return ret
|
||||
|
||||
return ret
|
||||
|
||||
def CheckProg(context, prog_name):
|
||||
"""
|
||||
Configure check for a specific program.
|
||||
|
||||
Check whether program prog_name exists in path. If it is found,
|
||||
returns the path for it, otherwise returns None.
|
||||
"""
|
||||
context.Display("Checking whether %s program exists..." % prog_name)
|
||||
path = context.env.WhereIs(prog_name)
|
||||
if path:
|
||||
context.Display(path + "\n")
|
||||
else:
|
||||
context.Display("no\n")
|
||||
return path
|
||||
|
||||
|
||||
#
|
||||
# END OF PUBLIC FUNCTIONS
|
||||
#
|
||||
|
||||
def _YesNoResult(context, ret, key, text, comment = None):
|
||||
r"""
|
||||
Handle the result of a test with a "yes" or "no" result.
|
||||
|
||||
:Parameters:
|
||||
- `ret` is the return value: empty if OK, error message when not.
|
||||
- `key` is the name of the symbol to be defined (HAVE_foo).
|
||||
- `text` is the source code of the program used for testing.
|
||||
- `comment` is the C comment to add above the line defining the symbol (the comment is automatically put inside a /\* \*/). If None, no comment is added.
|
||||
"""
|
||||
if key:
|
||||
_Have(context, key, not ret, comment)
|
||||
if ret:
|
||||
context.Display("no\n")
|
||||
_LogFailed(context, text, ret)
|
||||
else:
|
||||
context.Display("yes\n")
|
||||
|
||||
|
||||
def _Have(context, key, have, comment = None):
|
||||
r"""
|
||||
Store result of a test in context.havedict and context.headerfilename.
|
||||
|
||||
:Parameters:
|
||||
- `key` - is a "HAVE_abc" name. It is turned into all CAPITALS and non-alphanumerics are replaced by an underscore.
|
||||
- `have` - value as it should appear in the header file, include quotes when desired and escape special characters!
|
||||
- `comment` is the C comment to add above the line defining the symbol (the comment is automatically put inside a /\* \*/). If None, no comment is added.
|
||||
|
||||
|
||||
The value of "have" can be:
|
||||
- 1 - Feature is defined, add "#define key".
|
||||
- 0 - Feature is not defined, add "/\* #undef key \*/". Adding "undef" is what autoconf does. Not useful for the compiler, but it shows that the test was done.
|
||||
- number - Feature is defined to this number "#define key have". Doesn't work for 0 or 1, use a string then.
|
||||
- string - Feature is defined to this string "#define key have".
|
||||
|
||||
|
||||
"""
|
||||
key_up = key.upper()
|
||||
key_up = re.sub('[^A-Z0-9_]', '_', key_up)
|
||||
context.havedict[key_up] = have
|
||||
if have == 1:
|
||||
line = "#define %s 1\n" % key_up
|
||||
elif have == 0:
|
||||
line = "/* #undef %s */\n" % key_up
|
||||
elif isinstance(have, int):
|
||||
line = "#define %s %d\n" % (key_up, have)
|
||||
else:
|
||||
line = "#define %s %s\n" % (key_up, str(have))
|
||||
|
||||
if comment is not None:
|
||||
lines = "\n/* %s */\n" % comment + line
|
||||
else:
|
||||
lines = "\n" + line
|
||||
|
||||
if context.headerfilename:
|
||||
f = open(context.headerfilename, "a")
|
||||
f.write(lines)
|
||||
f.close()
|
||||
elif hasattr(context,'config_h'):
|
||||
context.config_h = context.config_h + lines
|
||||
|
||||
|
||||
def _LogFailed(context, text, msg):
|
||||
"""
|
||||
Write to the log about a failed program.
|
||||
Add line numbers, so that error messages can be understood.
|
||||
"""
|
||||
if LogInputFiles:
|
||||
context.Log("Failed program was:\n")
|
||||
lines = text.split('\n')
|
||||
if len(lines) and lines[-1] == '':
|
||||
lines = lines[:-1] # remove trailing empty line
|
||||
n = 1
|
||||
for line in lines:
|
||||
context.Log("%d: %s\n" % (n, line))
|
||||
n = n + 1
|
||||
if LogErrorMessages:
|
||||
context.Log("Error message: %s\n" % msg)
|
||||
|
||||
|
||||
def _lang2suffix(lang):
|
||||
"""
|
||||
Convert a language name to a suffix.
|
||||
When "lang" is empty or None C is assumed.
|
||||
Returns a tuple (lang, suffix, None) when it works.
|
||||
For an unrecognized language returns (None, None, msg).
|
||||
|
||||
Where:
|
||||
- lang = the unified language name
|
||||
- suffix = the suffix, including the leading dot
|
||||
- msg = an error message
|
||||
"""
|
||||
if not lang or lang in ["C", "c"]:
|
||||
return ("C", ".c", None)
|
||||
if lang in ["c++", "C++", "cpp", "CXX", "cxx"]:
|
||||
return ("C++", ".cpp", None)
|
||||
|
||||
return None, None, "Unsupported language: %s" % lang
|
||||
|
||||
|
||||
# vim: set sw=4 et sts=4 tw=79 fo+=l:
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
261
scons/scons-local-4.0.1/SCons/Debug.py
Normal file
261
scons/scons-local-4.0.1/SCons/Debug.py
Normal file
|
@ -0,0 +1,261 @@
|
|||
"""SCons.Debug
|
||||
|
||||
Code for debugging SCons internal things. Shouldn't be
|
||||
needed by most users. Quick shortcuts:
|
||||
|
||||
from SCons.Debug import caller_trace
|
||||
caller_trace()
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import atexit
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import weakref
|
||||
import inspect
|
||||
|
||||
# Global variable that gets set to 'True' by the Main script,
|
||||
# when the creation of class instances should get tracked.
|
||||
track_instances = False
|
||||
# List of currently tracked classes
|
||||
tracked_classes = {}
|
||||
|
||||
def logInstanceCreation(instance, name=None):
|
||||
if name is None:
|
||||
name = instance.__class__.__name__
|
||||
if name not in tracked_classes:
|
||||
tracked_classes[name] = []
|
||||
if hasattr(instance, '__dict__'):
|
||||
tracked_classes[name].append(weakref.ref(instance))
|
||||
else:
|
||||
# weakref doesn't seem to work when the instance
|
||||
# contains only slots...
|
||||
tracked_classes[name].append(instance)
|
||||
|
||||
def string_to_classes(s):
|
||||
if s == '*':
|
||||
return sorted(tracked_classes.keys())
|
||||
else:
|
||||
return s.split()
|
||||
|
||||
def fetchLoggedInstances(classes="*"):
|
||||
classnames = string_to_classes(classes)
|
||||
return [(cn, len(tracked_classes[cn])) for cn in classnames]
|
||||
|
||||
def countLoggedInstances(classes, file=sys.stdout):
|
||||
for classname in string_to_classes(classes):
|
||||
file.write("%s: %d\n" % (classname, len(tracked_classes[classname])))
|
||||
|
||||
def listLoggedInstances(classes, file=sys.stdout):
|
||||
for classname in string_to_classes(classes):
|
||||
file.write('\n%s:\n' % classname)
|
||||
for ref in tracked_classes[classname]:
|
||||
if inspect.isclass(ref):
|
||||
obj = ref()
|
||||
else:
|
||||
obj = ref
|
||||
if obj is not None:
|
||||
file.write(' %s\n' % repr(obj))
|
||||
|
||||
def dumpLoggedInstances(classes, file=sys.stdout):
|
||||
for classname in string_to_classes(classes):
|
||||
file.write('\n%s:\n' % classname)
|
||||
for ref in tracked_classes[classname]:
|
||||
obj = ref()
|
||||
if obj is not None:
|
||||
file.write(' %s:\n' % obj)
|
||||
for key, value in obj.__dict__.items():
|
||||
file.write(' %20s : %s\n' % (key, value))
|
||||
|
||||
|
||||
|
||||
if sys.platform[:5] == "linux":
|
||||
# Linux doesn't actually support memory usage stats from getrusage().
|
||||
def memory():
|
||||
with open('/proc/self/stat') as f:
|
||||
mstr = f.read()
|
||||
mstr = mstr.split()[22]
|
||||
return int(mstr)
|
||||
elif sys.platform[:6] == 'darwin':
|
||||
#TODO really get memory stats for OS X
|
||||
def memory():
|
||||
return 0
|
||||
else:
|
||||
try:
|
||||
import resource
|
||||
except ImportError:
|
||||
try:
|
||||
import win32process
|
||||
import win32api
|
||||
except ImportError:
|
||||
def memory():
|
||||
return 0
|
||||
else:
|
||||
def memory():
|
||||
process_handle = win32api.GetCurrentProcess()
|
||||
memory_info = win32process.GetProcessMemoryInfo( process_handle )
|
||||
return memory_info['PeakWorkingSetSize']
|
||||
else:
|
||||
def memory():
|
||||
res = resource.getrusage(resource.RUSAGE_SELF)
|
||||
return res[4]
|
||||
|
||||
# returns caller's stack
|
||||
def caller_stack():
|
||||
import traceback
|
||||
tb = traceback.extract_stack()
|
||||
# strip itself and the caller from the output
|
||||
tb = tb[:-2]
|
||||
result = []
|
||||
for back in tb:
|
||||
# (filename, line number, function name, text)
|
||||
key = back[:3]
|
||||
result.append('%s:%d(%s)' % func_shorten(key))
|
||||
return result
|
||||
|
||||
caller_bases = {}
|
||||
caller_dicts = {}
|
||||
|
||||
def caller_trace(back=0):
|
||||
"""
|
||||
Trace caller stack and save info into global dicts, which
|
||||
are printed automatically at the end of SCons execution.
|
||||
"""
|
||||
global caller_bases, caller_dicts
|
||||
import traceback
|
||||
tb = traceback.extract_stack(limit=3+back)
|
||||
tb.reverse()
|
||||
callee = tb[1][:3]
|
||||
caller_bases[callee] = caller_bases.get(callee, 0) + 1
|
||||
for caller in tb[2:]:
|
||||
caller = callee + caller[:3]
|
||||
try:
|
||||
entry = caller_dicts[callee]
|
||||
except KeyError:
|
||||
caller_dicts[callee] = entry = {}
|
||||
entry[caller] = entry.get(caller, 0) + 1
|
||||
callee = caller
|
||||
|
||||
# print a single caller and its callers, if any
|
||||
def _dump_one_caller(key, file, level=0):
|
||||
leader = ' '*level
|
||||
for v,c in sorted([(-v,c) for c,v in caller_dicts[key].items()]):
|
||||
file.write("%s %6d %s:%d(%s)\n" % ((leader,-v) + func_shorten(c[-3:])))
|
||||
if c in caller_dicts:
|
||||
_dump_one_caller(c, file, level+1)
|
||||
|
||||
# print each call tree
|
||||
def dump_caller_counts(file=sys.stdout):
|
||||
for k in sorted(caller_bases.keys()):
|
||||
file.write("Callers of %s:%d(%s), %d calls:\n"
|
||||
% (func_shorten(k) + (caller_bases[k],)))
|
||||
_dump_one_caller(k, file)
|
||||
|
||||
shorten_list = [
|
||||
( '/scons/SCons/', 1),
|
||||
( '/src/engine/SCons/', 1),
|
||||
( '/usr/lib/python', 0),
|
||||
]
|
||||
|
||||
if os.sep != '/':
|
||||
shorten_list = [(t[0].replace('/', os.sep), t[1]) for t in shorten_list]
|
||||
|
||||
def func_shorten(func_tuple):
|
||||
f = func_tuple[0]
|
||||
for t in shorten_list:
|
||||
i = f.find(t[0])
|
||||
if i >= 0:
|
||||
if t[1]:
|
||||
i = i + len(t[0])
|
||||
return (f[i:],)+func_tuple[1:]
|
||||
return func_tuple
|
||||
|
||||
|
||||
TraceFP = {}
|
||||
if sys.platform == 'win32':
|
||||
TraceDefault = 'con'
|
||||
else:
|
||||
TraceDefault = '/dev/tty'
|
||||
TimeStampDefault = False
|
||||
StartTime = time.time()
|
||||
PreviousTime = StartTime
|
||||
|
||||
def Trace(msg, filename=None, mode='w', tstamp=False):
|
||||
"""Write a trace message.
|
||||
|
||||
Write messages when debugging which do not interfere with stdout.
|
||||
Useful in tests, which monitor stdout and would break with
|
||||
unexpected output. Trace messages can go to the console (which is
|
||||
opened as a file), or to a disk file; the file argument persists
|
||||
across calls unless overridden.
|
||||
|
||||
Args:
|
||||
filename: file to write trace message to. If omitted,
|
||||
write to the previous trace file (default: console).
|
||||
mode: file open mode (default: 'w')
|
||||
tstamp: write relative timestamps with trace. Outputs time since
|
||||
scons was started, and time since last trace (default: False)
|
||||
|
||||
"""
|
||||
global TraceDefault
|
||||
global TimeStampDefault
|
||||
global PreviousTime
|
||||
|
||||
def trace_cleanup(traceFP):
|
||||
traceFP.close()
|
||||
|
||||
if file is None:
|
||||
file = TraceDefault
|
||||
else:
|
||||
TraceDefault = file
|
||||
if not tstamp:
|
||||
tstamp = TimeStampDefault
|
||||
else:
|
||||
TimeStampDefault = tstamp
|
||||
try:
|
||||
fp = TraceFP[file]
|
||||
except KeyError:
|
||||
try:
|
||||
fp = TraceFP[file] = open(file, mode)
|
||||
atexit.register(trace_cleanup, fp)
|
||||
except TypeError:
|
||||
# Assume we were passed an open file pointer.
|
||||
fp = file
|
||||
if tstamp:
|
||||
now = time.time()
|
||||
fp.write('%8.4f %8.4f: ' % (now - StartTime, now - PreviousTime))
|
||||
PreviousTime = now
|
||||
fp.write(msg)
|
||||
fp.flush()
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
594
scons/scons-local-4.0.1/SCons/Defaults.py
Normal file
594
scons/scons-local-4.0.1/SCons/Defaults.py
Normal file
|
@ -0,0 +1,594 @@
|
|||
"""SCons.Defaults
|
||||
|
||||
Builders and other things for the local site. Here's where we'll
|
||||
duplicate the functionality of autoconf until we move it into the
|
||||
installation procedure or use something like qmconf.
|
||||
|
||||
The code that reads the registry to find MSVC components was borrowed
|
||||
from distutils.msvccompiler.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
|
||||
import os
|
||||
import errno
|
||||
import shutil
|
||||
import stat
|
||||
import time
|
||||
import sys
|
||||
|
||||
import SCons.Action
|
||||
import SCons.Builder
|
||||
import SCons.CacheDir
|
||||
import SCons.Environment
|
||||
import SCons.PathList
|
||||
import SCons.Subst
|
||||
import SCons.Tool
|
||||
|
||||
# A placeholder for a default Environment (for fetching source files
|
||||
# from source code management systems and the like). This must be
|
||||
# initialized later, after the top-level directory is set by the calling
|
||||
# interface.
|
||||
_default_env = None
|
||||
|
||||
# Lazily instantiate the default environment so the overhead of creating
|
||||
# it doesn't apply when it's not needed.
|
||||
def _fetch_DefaultEnvironment(*args, **kw):
|
||||
"""
|
||||
Returns the already-created default construction environment.
|
||||
"""
|
||||
global _default_env
|
||||
return _default_env
|
||||
|
||||
def DefaultEnvironment(*args, **kw):
|
||||
"""
|
||||
Initial public entry point for creating the default construction
|
||||
Environment.
|
||||
|
||||
After creating the environment, we overwrite our name
|
||||
(DefaultEnvironment) with the _fetch_DefaultEnvironment() function,
|
||||
which more efficiently returns the initialized default construction
|
||||
environment without checking for its existence.
|
||||
|
||||
(This function still exists with its _default_check because someone
|
||||
else (*cough* Script/__init__.py *cough*) may keep a reference
|
||||
to this function. So we can't use the fully functional idiom of
|
||||
having the name originally be a something that *only* creates the
|
||||
construction environment and then overwrites the name.)
|
||||
"""
|
||||
global _default_env
|
||||
if not _default_env:
|
||||
import SCons.Util
|
||||
_default_env = SCons.Environment.Environment(*args, **kw)
|
||||
if SCons.Util.md5:
|
||||
_default_env.Decider('MD5')
|
||||
else:
|
||||
_default_env.Decider('timestamp-match')
|
||||
global DefaultEnvironment
|
||||
DefaultEnvironment = _fetch_DefaultEnvironment
|
||||
_default_env._CacheDir_path = None
|
||||
return _default_env
|
||||
|
||||
# Emitters for setting the shared attribute on object files,
|
||||
# and an action for checking that all of the source files
|
||||
# going into a shared library are, in fact, shared.
|
||||
def StaticObjectEmitter(target, source, env):
|
||||
for tgt in target:
|
||||
tgt.attributes.shared = None
|
||||
return (target, source)
|
||||
|
||||
def SharedObjectEmitter(target, source, env):
|
||||
for tgt in target:
|
||||
tgt.attributes.shared = 1
|
||||
return (target, source)
|
||||
|
||||
def SharedFlagChecker(source, target, env):
|
||||
same = env.subst('$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME')
|
||||
if same == '0' or same == '' or same == 'False':
|
||||
for src in source:
|
||||
try:
|
||||
shared = src.attributes.shared
|
||||
except AttributeError:
|
||||
shared = None
|
||||
if not shared:
|
||||
raise SCons.Errors.UserError("Source file: %s is static and is not compatible with shared target: %s" % (src, target[0]))
|
||||
|
||||
SharedCheck = SCons.Action.Action(SharedFlagChecker, None)
|
||||
|
||||
# Some people were using these variable name before we made
|
||||
# SourceFileScanner part of the public interface. Don't break their
|
||||
# SConscript files until we've given them some fair warning and a
|
||||
# transition period.
|
||||
CScan = SCons.Tool.CScanner
|
||||
DScan = SCons.Tool.DScanner
|
||||
LaTeXScan = SCons.Tool.LaTeXScanner
|
||||
ObjSourceScan = SCons.Tool.SourceFileScanner
|
||||
ProgScan = SCons.Tool.ProgramScanner
|
||||
|
||||
# These aren't really tool scanners, so they don't quite belong with
|
||||
# the rest of those in Tool/__init__.py, but I'm not sure where else
|
||||
# they should go. Leave them here for now.
|
||||
import SCons.Scanner.Dir
|
||||
DirScanner = SCons.Scanner.Dir.DirScanner()
|
||||
DirEntryScanner = SCons.Scanner.Dir.DirEntryScanner()
|
||||
|
||||
# Actions for common languages.
|
||||
CAction = SCons.Action.Action("$CCCOM", "$CCCOMSTR")
|
||||
ShCAction = SCons.Action.Action("$SHCCCOM", "$SHCCCOMSTR")
|
||||
CXXAction = SCons.Action.Action("$CXXCOM", "$CXXCOMSTR")
|
||||
ShCXXAction = SCons.Action.Action("$SHCXXCOM", "$SHCXXCOMSTR")
|
||||
|
||||
DAction = SCons.Action.Action("$DCOM", "$DCOMSTR")
|
||||
ShDAction = SCons.Action.Action("$SHDCOM", "$SHDCOMSTR")
|
||||
|
||||
ASAction = SCons.Action.Action("$ASCOM", "$ASCOMSTR")
|
||||
ASPPAction = SCons.Action.Action("$ASPPCOM", "$ASPPCOMSTR")
|
||||
|
||||
LinkAction = SCons.Action.Action("$LINKCOM", "$LINKCOMSTR")
|
||||
ShLinkAction = SCons.Action.Action("$SHLINKCOM", "$SHLINKCOMSTR")
|
||||
|
||||
LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR")
|
||||
|
||||
# Common tasks that we allow users to perform in platform-independent
|
||||
# ways by creating ActionFactory instances.
|
||||
ActionFactory = SCons.Action.ActionFactory
|
||||
|
||||
def get_paths_str(dest):
|
||||
# If dest is a list, we need to manually call str() on each element
|
||||
if SCons.Util.is_List(dest):
|
||||
elem_strs = []
|
||||
for element in dest:
|
||||
elem_strs.append('"' + str(element) + '"')
|
||||
return '[' + ', '.join(elem_strs) + ']'
|
||||
else:
|
||||
return '"' + str(dest) + '"'
|
||||
|
||||
permission_dic = {
|
||||
'u':{
|
||||
'r':stat.S_IRUSR,
|
||||
'w':stat.S_IWUSR,
|
||||
'x':stat.S_IXUSR
|
||||
},
|
||||
'g':{
|
||||
'r':stat.S_IRGRP,
|
||||
'w':stat.S_IWGRP,
|
||||
'x':stat.S_IXGRP
|
||||
},
|
||||
'o':{
|
||||
'r':stat.S_IROTH,
|
||||
'w':stat.S_IWOTH,
|
||||
'x':stat.S_IXOTH
|
||||
}
|
||||
}
|
||||
|
||||
def chmod_func(dest, mode):
|
||||
import SCons.Util
|
||||
from string import digits
|
||||
SCons.Node.FS.invalidate_node_memos(dest)
|
||||
if not SCons.Util.is_List(dest):
|
||||
dest = [dest]
|
||||
if SCons.Util.is_String(mode) and 0 not in [i in digits for i in mode]:
|
||||
mode = int(mode, 8)
|
||||
if not SCons.Util.is_String(mode):
|
||||
for element in dest:
|
||||
os.chmod(str(element), mode)
|
||||
else:
|
||||
mode = str(mode)
|
||||
for operation in mode.split(","):
|
||||
if "=" in operation:
|
||||
operator = "="
|
||||
elif "+" in operation:
|
||||
operator = "+"
|
||||
elif "-" in operation:
|
||||
operator = "-"
|
||||
else:
|
||||
raise SyntaxError("Could not find +, - or =")
|
||||
operation_list = operation.split(operator)
|
||||
if len(operation_list) != 2:
|
||||
raise SyntaxError("More than one operator found")
|
||||
user = operation_list[0].strip().replace("a", "ugo")
|
||||
permission = operation_list[1].strip()
|
||||
new_perm = 0
|
||||
for u in user:
|
||||
for p in permission:
|
||||
try:
|
||||
new_perm = new_perm | permission_dic[u][p]
|
||||
except KeyError:
|
||||
raise SyntaxError("Unrecognized user or permission format")
|
||||
for element in dest:
|
||||
curr_perm = os.stat(str(element)).st_mode
|
||||
if operator == "=":
|
||||
os.chmod(str(element), new_perm)
|
||||
elif operator == "+":
|
||||
os.chmod(str(element), curr_perm | new_perm)
|
||||
elif operator == "-":
|
||||
os.chmod(str(element), curr_perm & ~new_perm)
|
||||
|
||||
def chmod_strfunc(dest, mode):
|
||||
import SCons.Util
|
||||
if not SCons.Util.is_String(mode):
|
||||
return 'Chmod(%s, 0%o)' % (get_paths_str(dest), mode)
|
||||
else:
|
||||
return 'Chmod(%s, "%s")' % (get_paths_str(dest), str(mode))
|
||||
|
||||
Chmod = ActionFactory(chmod_func, chmod_strfunc)
|
||||
|
||||
def copy_func(dest, src, symlinks=True):
|
||||
"""
|
||||
If symlinks (is true), then a symbolic link will be
|
||||
shallow copied and recreated as a symbolic link; otherwise, copying
|
||||
a symbolic link will be equivalent to copying the symbolic link's
|
||||
final target regardless of symbolic link depth.
|
||||
"""
|
||||
|
||||
dest = str(dest)
|
||||
src = str(src)
|
||||
|
||||
SCons.Node.FS.invalidate_node_memos(dest)
|
||||
if SCons.Util.is_List(src) and os.path.isdir(dest):
|
||||
for file in src:
|
||||
shutil.copy2(file, dest)
|
||||
return 0
|
||||
elif os.path.islink(src):
|
||||
if symlinks:
|
||||
return os.symlink(os.readlink(src), dest)
|
||||
else:
|
||||
return copy_func(dest, os.path.realpath(src))
|
||||
elif os.path.isfile(src):
|
||||
shutil.copy2(src, dest)
|
||||
return 0
|
||||
else:
|
||||
shutil.copytree(src, dest, symlinks)
|
||||
# copytree returns None in python2 and destination string in python3
|
||||
# A error is raised in both cases, so we can just return 0 for success
|
||||
return 0
|
||||
|
||||
Copy = ActionFactory(
|
||||
copy_func,
|
||||
lambda dest, src, symlinks=True: 'Copy("%s", "%s")' % (dest, src)
|
||||
)
|
||||
|
||||
def delete_func(dest, must_exist=0):
|
||||
SCons.Node.FS.invalidate_node_memos(dest)
|
||||
if not SCons.Util.is_List(dest):
|
||||
dest = [dest]
|
||||
for entry in dest:
|
||||
entry = str(entry)
|
||||
# os.path.exists returns False with broken links that exist
|
||||
entry_exists = os.path.exists(entry) or os.path.islink(entry)
|
||||
if not entry_exists and not must_exist:
|
||||
continue
|
||||
# os.path.isdir returns True when entry is a link to a dir
|
||||
if os.path.isdir(entry) and not os.path.islink(entry):
|
||||
shutil.rmtree(entry, 1)
|
||||
continue
|
||||
os.unlink(entry)
|
||||
|
||||
def delete_strfunc(dest, must_exist=0):
|
||||
return 'Delete(%s)' % get_paths_str(dest)
|
||||
|
||||
Delete = ActionFactory(delete_func, delete_strfunc)
|
||||
|
||||
def mkdir_func(dest):
|
||||
SCons.Node.FS.invalidate_node_memos(dest)
|
||||
if not SCons.Util.is_List(dest):
|
||||
dest = [dest]
|
||||
for entry in dest:
|
||||
try:
|
||||
os.makedirs(str(entry))
|
||||
except os.error as e:
|
||||
p = str(entry)
|
||||
if (e.args[0] == errno.EEXIST or
|
||||
(sys.platform=='win32' and e.args[0]==183)) \
|
||||
and os.path.isdir(str(entry)):
|
||||
pass # not an error if already exists
|
||||
else:
|
||||
raise
|
||||
|
||||
Mkdir = ActionFactory(mkdir_func,
|
||||
lambda dir: 'Mkdir(%s)' % get_paths_str(dir))
|
||||
|
||||
def move_func(dest, src):
|
||||
SCons.Node.FS.invalidate_node_memos(dest)
|
||||
SCons.Node.FS.invalidate_node_memos(src)
|
||||
shutil.move(src, dest)
|
||||
|
||||
Move = ActionFactory(move_func,
|
||||
lambda dest, src: 'Move("%s", "%s")' % (dest, src),
|
||||
convert=str)
|
||||
|
||||
def touch_func(dest):
|
||||
SCons.Node.FS.invalidate_node_memos(dest)
|
||||
if not SCons.Util.is_List(dest):
|
||||
dest = [dest]
|
||||
for file in dest:
|
||||
file = str(file)
|
||||
mtime = int(time.time())
|
||||
if os.path.exists(file):
|
||||
atime = os.path.getatime(file)
|
||||
else:
|
||||
with open(file, 'w'):
|
||||
atime = mtime
|
||||
os.utime(file, (atime, mtime))
|
||||
|
||||
Touch = ActionFactory(touch_func,
|
||||
lambda file: 'Touch(%s)' % get_paths_str(file))
|
||||
|
||||
# Internal utility functions
|
||||
|
||||
|
||||
def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None):
|
||||
"""
|
||||
Creates a new list from 'list' by first interpolating each element
|
||||
in the list using the 'env' dictionary and then calling f on the
|
||||
list, and finally calling _concat_ixes to concatenate 'prefix' and
|
||||
'suffix' onto each element of the list.
|
||||
"""
|
||||
if not list:
|
||||
return list
|
||||
|
||||
l = f(SCons.PathList.PathList(list).subst_path(env, target, source))
|
||||
if l is not None:
|
||||
list = l
|
||||
|
||||
return _concat_ixes(prefix, list, suffix, env)
|
||||
|
||||
|
||||
def _concat_ixes(prefix, list, suffix, env):
|
||||
"""
|
||||
Creates a new list from 'list' by concatenating the 'prefix' and
|
||||
'suffix' arguments onto each element of the list. A trailing space
|
||||
on 'prefix' or leading space on 'suffix' will cause them to be put
|
||||
into separate list elements rather than being concatenated.
|
||||
"""
|
||||
|
||||
result = []
|
||||
|
||||
# ensure that prefix and suffix are strings
|
||||
prefix = str(env.subst(prefix, SCons.Subst.SUBST_RAW))
|
||||
suffix = str(env.subst(suffix, SCons.Subst.SUBST_RAW))
|
||||
|
||||
for x in list:
|
||||
if isinstance(x, SCons.Node.FS.File):
|
||||
result.append(x)
|
||||
continue
|
||||
x = str(x)
|
||||
if x:
|
||||
|
||||
if prefix:
|
||||
if prefix[-1] == ' ':
|
||||
result.append(prefix[:-1])
|
||||
elif x[:len(prefix)] != prefix:
|
||||
x = prefix + x
|
||||
|
||||
result.append(x)
|
||||
|
||||
if suffix:
|
||||
if suffix[0] == ' ':
|
||||
result.append(suffix[1:])
|
||||
elif x[-len(suffix):] != suffix:
|
||||
result[-1] = result[-1]+suffix
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def _stripixes(prefix, itms, suffix, stripprefixes, stripsuffixes, env, c=None):
|
||||
"""
|
||||
This is a wrapper around _concat()/_concat_ixes() that checks for
|
||||
the existence of prefixes or suffixes on list items and strips them
|
||||
where it finds them. This is used by tools (like the GNU linker)
|
||||
that need to turn something like 'libfoo.a' into '-lfoo'.
|
||||
"""
|
||||
|
||||
if not itms:
|
||||
return itms
|
||||
|
||||
if not callable(c):
|
||||
env_c = env['_concat']
|
||||
if env_c != _concat and callable(env_c):
|
||||
# There's a custom _concat() method in the construction
|
||||
# environment, and we've allowed people to set that in
|
||||
# the past (see test/custom-concat.py), so preserve the
|
||||
# backwards compatibility.
|
||||
c = env_c
|
||||
else:
|
||||
c = _concat_ixes
|
||||
|
||||
stripprefixes = list(map(env.subst, SCons.Util.flatten(stripprefixes)))
|
||||
stripsuffixes = list(map(env.subst, SCons.Util.flatten(stripsuffixes)))
|
||||
|
||||
stripped = []
|
||||
for l in SCons.PathList.PathList(itms).subst_path(env, None, None):
|
||||
if isinstance(l, SCons.Node.FS.File):
|
||||
stripped.append(l)
|
||||
continue
|
||||
|
||||
if not SCons.Util.is_String(l):
|
||||
l = str(l)
|
||||
|
||||
for stripprefix in stripprefixes:
|
||||
lsp = len(stripprefix)
|
||||
if l[:lsp] == stripprefix:
|
||||
l = l[lsp:]
|
||||
# Do not strip more than one prefix
|
||||
break
|
||||
|
||||
for stripsuffix in stripsuffixes:
|
||||
lss = len(stripsuffix)
|
||||
if l[-lss:] == stripsuffix:
|
||||
l = l[:-lss]
|
||||
# Do not strip more than one suffix
|
||||
break
|
||||
|
||||
stripped.append(l)
|
||||
|
||||
return c(prefix, stripped, suffix, env)
|
||||
|
||||
def processDefines(defs):
|
||||
"""process defines, resolving strings, lists, dictionaries, into a list of
|
||||
strings
|
||||
"""
|
||||
if SCons.Util.is_List(defs):
|
||||
l = []
|
||||
for d in defs:
|
||||
if d is None:
|
||||
continue
|
||||
elif SCons.Util.is_List(d) or isinstance(d, tuple):
|
||||
if len(d) >= 2:
|
||||
l.append(str(d[0]) + '=' + str(d[1]))
|
||||
else:
|
||||
l.append(str(d[0]))
|
||||
elif SCons.Util.is_Dict(d):
|
||||
for macro,value in d.items():
|
||||
if value is not None:
|
||||
l.append(str(macro) + '=' + str(value))
|
||||
else:
|
||||
l.append(str(macro))
|
||||
elif SCons.Util.is_String(d):
|
||||
l.append(str(d))
|
||||
else:
|
||||
raise SCons.Errors.UserError("DEFINE %s is not a list, dict, string or None."%repr(d))
|
||||
elif SCons.Util.is_Dict(defs):
|
||||
# The items in a dictionary are stored in random order, but
|
||||
# if the order of the command-line options changes from
|
||||
# invocation to invocation, then the signature of the command
|
||||
# line will change and we'll get random unnecessary rebuilds.
|
||||
# Consequently, we have to sort the keys to ensure a
|
||||
# consistent order...
|
||||
l = []
|
||||
for k,v in sorted(defs.items()):
|
||||
if v is None:
|
||||
l.append(str(k))
|
||||
else:
|
||||
l.append(str(k) + '=' + str(v))
|
||||
else:
|
||||
l = [str(defs)]
|
||||
return l
|
||||
|
||||
|
||||
def _defines(prefix, defs, suffix, env, c=_concat_ixes):
|
||||
"""A wrapper around _concat_ixes that turns a list or string
|
||||
into a list of C preprocessor command-line definitions.
|
||||
"""
|
||||
|
||||
return c(prefix, env.subst_path(processDefines(defs)), suffix, env)
|
||||
|
||||
|
||||
class NullCmdGenerator:
|
||||
"""This is a callable class that can be used in place of other
|
||||
command generators if you don't want them to do anything.
|
||||
|
||||
The __call__ method for this class simply returns the thing
|
||||
you instantiated it with.
|
||||
|
||||
Example usage:
|
||||
env["DO_NOTHING"] = NullCmdGenerator
|
||||
env["LINKCOM"] = "${DO_NOTHING('$LINK $SOURCES $TARGET')}"
|
||||
"""
|
||||
|
||||
def __init__(self, cmd):
|
||||
self.cmd = cmd
|
||||
|
||||
def __call__(self, target, source, env, for_signature=None):
|
||||
return self.cmd
|
||||
|
||||
|
||||
class Variable_Method_Caller:
|
||||
"""A class for finding a construction variable on the stack and
|
||||
calling one of its methods.
|
||||
|
||||
We use this to support "construction variables" in our string
|
||||
eval()s that actually stand in for methods--specifically, use
|
||||
of "RDirs" in call to _concat that should actually execute the
|
||||
"TARGET.RDirs" method. (We used to support this by creating a little
|
||||
"build dictionary" that mapped RDirs to the method, but this got in
|
||||
the way of Memoizing construction environments, because we had to
|
||||
create new environment objects to hold the variables.)
|
||||
"""
|
||||
def __init__(self, variable, method):
|
||||
self.variable = variable
|
||||
self.method = method
|
||||
def __call__(self, *args, **kw):
|
||||
try: 1//0
|
||||
except ZeroDivisionError:
|
||||
# Don't start iterating with the current stack-frame to
|
||||
# prevent creating reference cycles (f_back is safe).
|
||||
frame = sys.exc_info()[2].tb_frame.f_back
|
||||
variable = self.variable
|
||||
while frame:
|
||||
if variable in frame.f_locals:
|
||||
v = frame.f_locals[variable]
|
||||
if v:
|
||||
method = getattr(v, self.method)
|
||||
return method(*args, **kw)
|
||||
frame = frame.f_back
|
||||
return None
|
||||
|
||||
# if $version_var is not empty, returns env[flags_var], otherwise returns None
|
||||
def __libversionflags(env, version_var, flags_var):
|
||||
try:
|
||||
if env.subst('$'+version_var):
|
||||
return env[flags_var]
|
||||
except KeyError:
|
||||
pass
|
||||
return None
|
||||
|
||||
ConstructionEnvironment = {
|
||||
'BUILDERS' : {},
|
||||
'SCANNERS' : [ SCons.Tool.SourceFileScanner ],
|
||||
'CONFIGUREDIR' : '#/.sconf_temp',
|
||||
'CONFIGURELOG' : '#/config.log',
|
||||
'CPPSUFFIXES' : SCons.Tool.CSuffixes,
|
||||
'DSUFFIXES' : SCons.Tool.DSuffixes,
|
||||
'ENV' : {},
|
||||
'IDLSUFFIXES' : SCons.Tool.IDLSuffixes,
|
||||
'_concat' : _concat,
|
||||
'_defines' : _defines,
|
||||
'_stripixes' : _stripixes,
|
||||
'_LIBFLAGS' : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
|
||||
'_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
|
||||
'_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
|
||||
'_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
|
||||
|
||||
'__libversionflags' : __libversionflags,
|
||||
'__SHLIBVERSIONFLAGS' : '${__libversionflags(__env__,"SHLIBVERSION","_SHLIBVERSIONFLAGS")}',
|
||||
'__LDMODULEVERSIONFLAGS' : '${__libversionflags(__env__,"LDMODULEVERSION","_LDMODULEVERSIONFLAGS")}',
|
||||
'__DSHLIBVERSIONFLAGS' : '${__libversionflags(__env__,"DSHLIBVERSION","_DSHLIBVERSIONFLAGS")}',
|
||||
|
||||
'TEMPFILE' : NullCmdGenerator,
|
||||
'TEMPFILEARGJOIN': ' ',
|
||||
'Dir' : Variable_Method_Caller('TARGET', 'Dir'),
|
||||
'Dirs' : Variable_Method_Caller('TARGET', 'Dirs'),
|
||||
'File' : Variable_Method_Caller('TARGET', 'File'),
|
||||
'RDirs' : Variable_Method_Caller('TARGET', 'RDirs'),
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
2498
scons/scons-local-4.0.1/SCons/Environment.py
Normal file
2498
scons/scons-local-4.0.1/SCons/Environment.py
Normal file
File diff suppressed because it is too large
Load diff
97
scons/scons-local-4.0.1/SCons/EnvironmentValues.py
Normal file
97
scons/scons-local-4.0.1/SCons/EnvironmentValues.py
Normal file
|
@ -0,0 +1,97 @@
|
|||
import re
|
||||
|
||||
_is_valid_var = re.compile(r'[_a-zA-Z]\w*$')
|
||||
|
||||
_rm = re.compile(r'\$[()]')
|
||||
_remove = re.compile(r'\$\([^$]*(\$[^)][^$]*)*\$\)')
|
||||
|
||||
# Regular expressions for splitting strings and handling substitutions,
|
||||
# for use by the scons_subst() and scons_subst_list() functions:
|
||||
#
|
||||
# The first expression compiled matches all of the $-introduced tokens
|
||||
# that we need to process in some way, and is used for substitutions.
|
||||
# The expressions it matches are:
|
||||
#
|
||||
# "$$"
|
||||
# "$("
|
||||
# "$)"
|
||||
# "$variable" [must begin with alphabetic or underscore]
|
||||
# "${any stuff}"
|
||||
#
|
||||
# The second expression compiled is used for splitting strings into tokens
|
||||
# to be processed, and it matches all of the tokens listed above, plus
|
||||
# the following that affect how arguments do or don't get joined together:
|
||||
#
|
||||
# " " [white space]
|
||||
# "non-white-space" [without any dollar signs]
|
||||
# "$" [single dollar sign]
|
||||
#
|
||||
_dollar_exps_str = r'\$[\$\(\)]|\$[_a-zA-Z][\.\w]*|\${[^}]*}'
|
||||
_dollar_exps = re.compile(r'(%s)' % _dollar_exps_str)
|
||||
_separate_args = re.compile(r'(%s|\s+|[^\s$]+|\$)' % _dollar_exps_str)
|
||||
|
||||
# This regular expression is used to replace strings of multiple white
|
||||
# space characters in the string result from the scons_subst() function.
|
||||
_space_sep = re.compile(r'[\t ]+(?![^{]*})')
|
||||
|
||||
class ValueTypes:
|
||||
"""
|
||||
Enum to store what type of value the variable holds.
|
||||
"""
|
||||
UNKNOWN = 0
|
||||
STRING = 1
|
||||
CALLABLE = 2
|
||||
VARIABLE = 3
|
||||
|
||||
|
||||
class EnvironmentValue:
|
||||
"""
|
||||
Hold a single value. We're going to cache parsed version of the file
|
||||
We're going to keep track of variables which feed into this values evaluation
|
||||
"""
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
self.var_type = ValueTypes.UNKNOWN
|
||||
|
||||
if callable(self.value):
|
||||
self.var_type = ValueTypes.CALLABLE
|
||||
else:
|
||||
self.parse_value()
|
||||
|
||||
|
||||
def parse_value(self):
|
||||
"""
|
||||
Scan the string and break into component values
|
||||
"""
|
||||
|
||||
try:
|
||||
if '$' not in self.value:
|
||||
self._parsed = self.value
|
||||
self.var_type = ValueTypes.STRING
|
||||
else:
|
||||
# Now we need to parse the specified string
|
||||
result = _dollar_exps.sub(sub_match, args)
|
||||
print(result)
|
||||
pass
|
||||
except TypeError:
|
||||
# likely callable? either way we don't parse
|
||||
self._parsed = self.value
|
||||
|
||||
def parse_trial(self):
|
||||
"""
|
||||
Try alternate parsing methods.
|
||||
:return:
|
||||
"""
|
||||
parts = []
|
||||
for c in self.value:
|
||||
pass
|
||||
|
||||
|
||||
class EnvironmentValues:
|
||||
"""
|
||||
A class to hold all the environment variables
|
||||
"""
|
||||
def __init__(self, **kw):
|
||||
self._dict = {}
|
||||
for k in kw:
|
||||
self._dict[k] = EnvironmentValue(kw[k])
|
16
scons/scons-local-4.0.1/SCons/EnvironmentValuesTest.py
Normal file
16
scons/scons-local-4.0.1/SCons/EnvironmentValuesTest.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
import unittest
|
||||
|
||||
from SCons.EnvironmentValues import EnvironmentValues
|
||||
|
||||
class MyTestCase(unittest.TestCase):
|
||||
def test_simple_environmentValues(self):
|
||||
"""Test comparing SubstitutionEnvironments
|
||||
"""
|
||||
|
||||
env1 = EnvironmentValues(XXX='x')
|
||||
env2 = EnvironmentValues(XXX='x',XX="$X", X1="${X}", X2="$($X$)")
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
225
scons/scons-local-4.0.1/SCons/Errors.py
Normal file
225
scons/scons-local-4.0.1/SCons/Errors.py
Normal file
|
@ -0,0 +1,225 @@
|
|||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
"""SCons.Errors
|
||||
|
||||
This file contains the exception classes used to handle internal
|
||||
and user errors in SCons.
|
||||
|
||||
"""
|
||||
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import shutil
|
||||
import SCons.Util
|
||||
|
||||
|
||||
class BuildError(Exception):
|
||||
"""SCons Errors that can occur while building.
|
||||
|
||||
Attributes:
|
||||
Information about the cause of the build error :
|
||||
|
||||
errstr: a description of the error message
|
||||
|
||||
status: the return code of the action that caused the build error.
|
||||
Must be set to a non-zero value even if the build error is not due
|
||||
to an action returning a non-zero returned code.
|
||||
|
||||
exitstatus: SCons exit status due to this build error.
|
||||
Must be nonzero unless due to an explicit Exit()
|
||||
call. Not always the same as status, since
|
||||
actions return a status code that should be
|
||||
respected, but SCons typically exits with 2
|
||||
irrespective of the return value of the failed
|
||||
action.
|
||||
|
||||
filename: The name of the file or directory that caused the
|
||||
build error. Set to None if no files are associated with
|
||||
this error. This might be different from the target
|
||||
being built. For example, failure to create the
|
||||
directory in which the target file will appear. It
|
||||
can be None if the error is not due to a particular
|
||||
filename.
|
||||
|
||||
exc_info: Info about exception that caused the build
|
||||
error. Set to (None, None, None) if this build
|
||||
error is not due to an exception.
|
||||
|
||||
Information about the what caused the build error :
|
||||
|
||||
node: the error occurred while building this target node(s)
|
||||
|
||||
executor: the executor that caused the build to fail (might
|
||||
be None if the build failures is not due to the
|
||||
executor failing)
|
||||
|
||||
action: the action that caused the build to fail (might be
|
||||
None if the build failures is not due to the an
|
||||
action failure)
|
||||
|
||||
command: the command line for the action that caused the
|
||||
build to fail (might be None if the build failures
|
||||
is not due to the an action failure)
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
node=None, errstr="Unknown error", status=2, exitstatus=2,
|
||||
filename=None, executor=None, action=None, command=None,
|
||||
exc_info=(None, None, None)):
|
||||
|
||||
# py3: errstr should be string and not bytes.
|
||||
|
||||
self.errstr = SCons.Util.to_String(errstr)
|
||||
self.status = status
|
||||
self.exitstatus = exitstatus
|
||||
self.filename = filename
|
||||
self.exc_info = exc_info
|
||||
|
||||
self.node = node
|
||||
self.executor = executor
|
||||
self.action = action
|
||||
self.command = command
|
||||
|
||||
Exception.__init__(self, node, errstr, status, exitstatus, filename,
|
||||
executor, action, command, exc_info)
|
||||
|
||||
def __str__(self):
|
||||
if self.filename:
|
||||
return self.filename + ': ' + self.errstr
|
||||
else:
|
||||
return self.errstr
|
||||
|
||||
class InternalError(Exception):
|
||||
pass
|
||||
|
||||
class UserError(Exception):
|
||||
pass
|
||||
|
||||
class StopError(Exception):
|
||||
pass
|
||||
|
||||
class SConsEnvironmentError(Exception):
|
||||
pass
|
||||
|
||||
class MSVCError(IOError):
|
||||
pass
|
||||
|
||||
class ExplicitExit(Exception):
|
||||
def __init__(self, node=None, status=None, *args):
|
||||
self.node = node
|
||||
self.status = status
|
||||
self.exitstatus = status
|
||||
Exception.__init__(self, *args)
|
||||
|
||||
def convert_to_BuildError(status, exc_info=None):
|
||||
"""Convert a return code to a BuildError Exception.
|
||||
|
||||
The `buildError.status` we set here will normally be
|
||||
used as the exit status of the "scons" process.
|
||||
|
||||
Args:
|
||||
status: can either be a return code or an Exception.
|
||||
exc_info (tuple, optional): explicit exception information.
|
||||
|
||||
"""
|
||||
|
||||
if not exc_info and isinstance(status, Exception):
|
||||
exc_info = (status.__class__, status, None)
|
||||
|
||||
|
||||
if isinstance(status, BuildError):
|
||||
buildError = status
|
||||
buildError.exitstatus = 2 # always exit with 2 on build errors
|
||||
elif isinstance(status, ExplicitExit):
|
||||
status = status.status
|
||||
errstr = 'Explicit exit, status %s' % status
|
||||
buildError = BuildError(
|
||||
errstr=errstr,
|
||||
status=status, # might be 0, OK here
|
||||
exitstatus=status, # might be 0, OK here
|
||||
exc_info=exc_info)
|
||||
elif isinstance(status, (StopError, UserError)):
|
||||
buildError = BuildError(
|
||||
errstr=str(status),
|
||||
status=2,
|
||||
exitstatus=2,
|
||||
exc_info=exc_info)
|
||||
elif isinstance(status, shutil.SameFileError):
|
||||
# PY3 has a exception for when copying file to itself
|
||||
# It's object provides info differently than below
|
||||
try:
|
||||
filename = status.filename
|
||||
except AttributeError:
|
||||
filename = None
|
||||
|
||||
buildError = BuildError(
|
||||
errstr=status.args[0],
|
||||
status=status.errno,
|
||||
exitstatus=2,
|
||||
filename=filename,
|
||||
exc_info=exc_info)
|
||||
|
||||
elif isinstance(status, (SConsEnvironmentError, OSError, IOError)):
|
||||
# If an IOError/OSError happens, raise a BuildError.
|
||||
# Report the name of the file or directory that caused the
|
||||
# error, which might be different from the target being built
|
||||
# (for example, failure to create the directory in which the
|
||||
# target file will appear).
|
||||
filename = getattr(status, 'filename', None)
|
||||
strerror = getattr(status, 'strerror', str(status))
|
||||
errno = getattr(status, 'errno', 2)
|
||||
|
||||
buildError = BuildError(
|
||||
errstr=strerror,
|
||||
status=errno,
|
||||
exitstatus=2,
|
||||
filename=filename,
|
||||
exc_info=exc_info)
|
||||
elif isinstance(status, Exception):
|
||||
buildError = BuildError(
|
||||
errstr='%s : %s' % (status.__class__.__name__, status),
|
||||
status=2,
|
||||
exitstatus=2,
|
||||
exc_info=exc_info)
|
||||
elif SCons.Util.is_String(status):
|
||||
buildError = BuildError(
|
||||
errstr=status,
|
||||
status=2,
|
||||
exitstatus=2)
|
||||
else:
|
||||
buildError = BuildError(
|
||||
errstr="Error %s" % status,
|
||||
status=status,
|
||||
exitstatus=2)
|
||||
|
||||
#import sys
|
||||
#sys.stderr.write("convert_to_BuildError: status %s => (errstr %s, status %s)\n"%(status,buildError.errstr, buildError.status))
|
||||
return buildError
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
671
scons/scons-local-4.0.1/SCons/Executor.py
Normal file
671
scons/scons-local-4.0.1/SCons/Executor.py
Normal file
|
@ -0,0 +1,671 @@
|
|||
"""SCons.Executor
|
||||
|
||||
A module for executing actions with specific lists of target and source
|
||||
Nodes.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import collections
|
||||
|
||||
import SCons.Debug
|
||||
from SCons.Debug import logInstanceCreation
|
||||
import SCons.Errors
|
||||
import SCons.Memoize
|
||||
import SCons.Util
|
||||
from SCons.compat import NoSlotsPyPy
|
||||
|
||||
class Batch:
|
||||
"""Remembers exact association between targets
|
||||
and sources of executor."""
|
||||
|
||||
__slots__ = ('targets',
|
||||
'sources')
|
||||
|
||||
def __init__(self, targets=[], sources=[]):
|
||||
self.targets = targets
|
||||
self.sources = sources
|
||||
|
||||
|
||||
|
||||
class TSList(collections.UserList):
|
||||
"""A class that implements $TARGETS or $SOURCES expansions by wrapping
|
||||
an executor Method. This class is used in the Executor.lvars()
|
||||
to delay creation of NodeList objects until they're needed.
|
||||
|
||||
Note that we subclass collections.UserList purely so that the
|
||||
is_Sequence() function will identify an object of this class as
|
||||
a list during variable expansion. We're not really using any
|
||||
collections.UserList methods in practice.
|
||||
"""
|
||||
def __init__(self, func):
|
||||
self.func = func
|
||||
def __getattr__(self, attr):
|
||||
nl = self.func()
|
||||
return getattr(nl, attr)
|
||||
def __getitem__(self, i):
|
||||
nl = self.func()
|
||||
return nl[i]
|
||||
def __getslice__(self, i, j):
|
||||
nl = self.func()
|
||||
i, j = max(i, 0), max(j, 0)
|
||||
return nl[i:j]
|
||||
def __str__(self):
|
||||
nl = self.func()
|
||||
return str(nl)
|
||||
def __repr__(self):
|
||||
nl = self.func()
|
||||
return repr(nl)
|
||||
|
||||
class TSObject:
|
||||
"""A class that implements $TARGET or $SOURCE expansions by wrapping
|
||||
an Executor method.
|
||||
"""
|
||||
def __init__(self, func):
|
||||
self.func = func
|
||||
def __getattr__(self, attr):
|
||||
n = self.func()
|
||||
return getattr(n, attr)
|
||||
def __str__(self):
|
||||
n = self.func()
|
||||
if n:
|
||||
return str(n)
|
||||
return ''
|
||||
def __repr__(self):
|
||||
n = self.func()
|
||||
if n:
|
||||
return repr(n)
|
||||
return ''
|
||||
|
||||
def rfile(node):
|
||||
"""
|
||||
A function to return the results of a Node's rfile() method,
|
||||
if it exists, and the Node itself otherwise (if it's a Value
|
||||
Node, e.g.).
|
||||
"""
|
||||
try:
|
||||
rfile = node.rfile
|
||||
except AttributeError:
|
||||
return node
|
||||
else:
|
||||
return rfile()
|
||||
|
||||
|
||||
def execute_nothing(obj, target, kw):
|
||||
return 0
|
||||
|
||||
def execute_action_list(obj, target, kw):
|
||||
"""Actually execute the action list."""
|
||||
env = obj.get_build_env()
|
||||
kw = obj.get_kw(kw)
|
||||
status = 0
|
||||
for act in obj.get_action_list():
|
||||
args = ([], [], env)
|
||||
status = act(*args, **kw)
|
||||
if isinstance(status, SCons.Errors.BuildError):
|
||||
status.executor = obj
|
||||
raise status # TODO pylint E0702: raising int not allowed
|
||||
elif status:
|
||||
msg = "Error %s" % status
|
||||
raise SCons.Errors.BuildError(
|
||||
errstr=msg,
|
||||
node=obj.batches[0].targets,
|
||||
executor=obj,
|
||||
action=act)
|
||||
return status
|
||||
|
||||
_do_execute_map = {0 : execute_nothing,
|
||||
1 : execute_action_list}
|
||||
|
||||
|
||||
def execute_actions_str(obj):
|
||||
env = obj.get_build_env()
|
||||
return "\n".join([action.genstring(obj.get_all_targets(),
|
||||
obj.get_all_sources(),
|
||||
env)
|
||||
for action in obj.get_action_list()])
|
||||
|
||||
def execute_null_str(obj):
|
||||
return ''
|
||||
|
||||
_execute_str_map = {0 : execute_null_str,
|
||||
1 : execute_actions_str}
|
||||
|
||||
|
||||
class Executor(object, metaclass=NoSlotsPyPy):
|
||||
"""A class for controlling instances of executing an action.
|
||||
|
||||
This largely exists to hold a single association of an action,
|
||||
environment, list of environment override dictionaries, targets
|
||||
and sources for later processing as needed.
|
||||
"""
|
||||
|
||||
__slots__ = ('pre_actions',
|
||||
'post_actions',
|
||||
'env',
|
||||
'overridelist',
|
||||
'batches',
|
||||
'builder_kw',
|
||||
'_memo',
|
||||
'lvars',
|
||||
'_changed_sources_list',
|
||||
'_changed_targets_list',
|
||||
'_unchanged_sources_list',
|
||||
'_unchanged_targets_list',
|
||||
'action_list',
|
||||
'_do_execute',
|
||||
'_execute_str')
|
||||
|
||||
def __init__(self, action, env=None, overridelist=[{}],
|
||||
targets=[], sources=[], builder_kw={}):
|
||||
if SCons.Debug.track_instances: logInstanceCreation(self, 'Executor.Executor')
|
||||
self.set_action_list(action)
|
||||
self.pre_actions = []
|
||||
self.post_actions = []
|
||||
self.env = env
|
||||
self.overridelist = overridelist
|
||||
if targets or sources:
|
||||
self.batches = [Batch(targets[:], sources[:])]
|
||||
else:
|
||||
self.batches = []
|
||||
self.builder_kw = builder_kw
|
||||
self._do_execute = 1
|
||||
self._execute_str = 1
|
||||
self._memo = {}
|
||||
|
||||
def get_lvars(self):
|
||||
try:
|
||||
return self.lvars
|
||||
except AttributeError:
|
||||
self.lvars = {
|
||||
'CHANGED_SOURCES' : TSList(self._get_changed_sources),
|
||||
'CHANGED_TARGETS' : TSList(self._get_changed_targets),
|
||||
'SOURCE' : TSObject(self._get_source),
|
||||
'SOURCES' : TSList(self._get_sources),
|
||||
'TARGET' : TSObject(self._get_target),
|
||||
'TARGETS' : TSList(self._get_targets),
|
||||
'UNCHANGED_SOURCES' : TSList(self._get_unchanged_sources),
|
||||
'UNCHANGED_TARGETS' : TSList(self._get_unchanged_targets),
|
||||
}
|
||||
return self.lvars
|
||||
|
||||
def _get_changes(self):
|
||||
cs = []
|
||||
ct = []
|
||||
us = []
|
||||
ut = []
|
||||
for b in self.batches:
|
||||
# don't add targets marked always build to unchanged lists
|
||||
# add to changed list as they always need to build
|
||||
if not b.targets[0].always_build and b.targets[0].is_up_to_date():
|
||||
us.extend(list(map(rfile, b.sources)))
|
||||
ut.extend(b.targets)
|
||||
else:
|
||||
cs.extend(list(map(rfile, b.sources)))
|
||||
ct.extend(b.targets)
|
||||
self._changed_sources_list = SCons.Util.NodeList(cs)
|
||||
self._changed_targets_list = SCons.Util.NodeList(ct)
|
||||
self._unchanged_sources_list = SCons.Util.NodeList(us)
|
||||
self._unchanged_targets_list = SCons.Util.NodeList(ut)
|
||||
|
||||
def _get_changed_sources(self, *args, **kw):
|
||||
try:
|
||||
return self._changed_sources_list
|
||||
except AttributeError:
|
||||
self._get_changes()
|
||||
return self._changed_sources_list
|
||||
|
||||
def _get_changed_targets(self, *args, **kw):
|
||||
try:
|
||||
return self._changed_targets_list
|
||||
except AttributeError:
|
||||
self._get_changes()
|
||||
return self._changed_targets_list
|
||||
|
||||
def _get_source(self, *args, **kw):
|
||||
return rfile(self.batches[0].sources[0]).get_subst_proxy()
|
||||
|
||||
def _get_sources(self, *args, **kw):
|
||||
return SCons.Util.NodeList([rfile(n).get_subst_proxy() for n in self.get_all_sources()])
|
||||
|
||||
def _get_target(self, *args, **kw):
|
||||
return self.batches[0].targets[0].get_subst_proxy()
|
||||
|
||||
def _get_targets(self, *args, **kw):
|
||||
return SCons.Util.NodeList([n.get_subst_proxy() for n in self.get_all_targets()])
|
||||
|
||||
def _get_unchanged_sources(self, *args, **kw):
|
||||
try:
|
||||
return self._unchanged_sources_list
|
||||
except AttributeError:
|
||||
self._get_changes()
|
||||
return self._unchanged_sources_list
|
||||
|
||||
def _get_unchanged_targets(self, *args, **kw):
|
||||
try:
|
||||
return self._unchanged_targets_list
|
||||
except AttributeError:
|
||||
self._get_changes()
|
||||
return self._unchanged_targets_list
|
||||
|
||||
def get_action_targets(self):
|
||||
if not self.action_list:
|
||||
return []
|
||||
targets_string = self.action_list[0].get_targets(self.env, self)
|
||||
if targets_string[0] == '$':
|
||||
targets_string = targets_string[1:]
|
||||
return self.get_lvars()[targets_string]
|
||||
|
||||
def set_action_list(self, action):
|
||||
import SCons.Util
|
||||
if not SCons.Util.is_List(action):
|
||||
if not action:
|
||||
import SCons.Errors
|
||||
raise SCons.Errors.UserError("Executor must have an action.")
|
||||
action = [action]
|
||||
self.action_list = action
|
||||
|
||||
def get_action_list(self):
|
||||
if self.action_list is None:
|
||||
return []
|
||||
return self.pre_actions + self.action_list + self.post_actions
|
||||
|
||||
def get_all_targets(self):
|
||||
"""Returns all targets for all batches of this Executor."""
|
||||
result = []
|
||||
for batch in self.batches:
|
||||
result.extend(batch.targets)
|
||||
return result
|
||||
|
||||
def get_all_sources(self):
|
||||
"""Returns all sources for all batches of this Executor."""
|
||||
result = []
|
||||
for batch in self.batches:
|
||||
result.extend(batch.sources)
|
||||
return result
|
||||
|
||||
def get_all_children(self):
|
||||
"""Returns all unique children (dependencies) for all batches
|
||||
of this Executor.
|
||||
|
||||
The Taskmaster can recognize when it's already evaluated a
|
||||
Node, so we don't have to make this list unique for its intended
|
||||
canonical use case, but we expect there to be a lot of redundancy
|
||||
(long lists of batched .cc files #including the same .h files
|
||||
over and over), so removing the duplicates once up front should
|
||||
save the Taskmaster a lot of work.
|
||||
"""
|
||||
result = SCons.Util.UniqueList([])
|
||||
for target in self.get_all_targets():
|
||||
result.extend(target.children())
|
||||
return result
|
||||
|
||||
def get_all_prerequisites(self):
|
||||
"""Returns all unique (order-only) prerequisites for all batches
|
||||
of this Executor.
|
||||
"""
|
||||
result = SCons.Util.UniqueList([])
|
||||
for target in self.get_all_targets():
|
||||
if target.prerequisites is not None:
|
||||
result.extend(target.prerequisites)
|
||||
return result
|
||||
|
||||
def get_action_side_effects(self):
|
||||
|
||||
"""Returns all side effects for all batches of this
|
||||
Executor used by the underlying Action.
|
||||
"""
|
||||
result = SCons.Util.UniqueList([])
|
||||
for target in self.get_action_targets():
|
||||
result.extend(target.side_effects)
|
||||
return result
|
||||
|
||||
@SCons.Memoize.CountMethodCall
|
||||
def get_build_env(self):
|
||||
"""Fetch or create the appropriate build Environment
|
||||
for this Executor.
|
||||
"""
|
||||
try:
|
||||
return self._memo['get_build_env']
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
# Create the build environment instance with appropriate
|
||||
# overrides. These get evaluated against the current
|
||||
# environment's construction variables so that users can
|
||||
# add to existing values by referencing the variable in
|
||||
# the expansion.
|
||||
overrides = {}
|
||||
for odict in self.overridelist:
|
||||
overrides.update(odict)
|
||||
|
||||
import SCons.Defaults
|
||||
env = self.env or SCons.Defaults.DefaultEnvironment()
|
||||
build_env = env.Override(overrides)
|
||||
|
||||
self._memo['get_build_env'] = build_env
|
||||
|
||||
return build_env
|
||||
|
||||
def get_build_scanner_path(self, scanner):
|
||||
"""Fetch the scanner path for this executor's targets and sources.
|
||||
"""
|
||||
env = self.get_build_env()
|
||||
try:
|
||||
cwd = self.batches[0].targets[0].cwd
|
||||
except (IndexError, AttributeError):
|
||||
cwd = None
|
||||
return scanner.path(env, cwd,
|
||||
self.get_all_targets(),
|
||||
self.get_all_sources())
|
||||
|
||||
def get_kw(self, kw={}):
|
||||
result = self.builder_kw.copy()
|
||||
result.update(kw)
|
||||
result['executor'] = self
|
||||
return result
|
||||
|
||||
# use extra indirection because with new-style objects (Python 2.2
|
||||
# and above) we can't override special methods, and nullify() needs
|
||||
# to be able to do this.
|
||||
|
||||
def __call__(self, target, **kw):
|
||||
return _do_execute_map[self._do_execute](self, target, kw)
|
||||
|
||||
def cleanup(self):
|
||||
self._memo = {}
|
||||
|
||||
def add_sources(self, sources):
|
||||
"""Add source files to this Executor's list. This is necessary
|
||||
for "multi" Builders that can be called repeatedly to build up
|
||||
a source file list for a given target."""
|
||||
# TODO(batch): extend to multiple batches
|
||||
assert (len(self.batches) == 1)
|
||||
# TODO(batch): remove duplicates?
|
||||
sources = [x for x in sources if x not in self.batches[0].sources]
|
||||
self.batches[0].sources.extend(sources)
|
||||
|
||||
def get_sources(self):
|
||||
return self.batches[0].sources
|
||||
|
||||
def add_batch(self, targets, sources):
|
||||
"""Add pair of associated target and source to this Executor's list.
|
||||
This is necessary for "batch" Builders that can be called repeatedly
|
||||
to build up a list of matching target and source files that will be
|
||||
used in order to update multiple target files at once from multiple
|
||||
corresponding source files, for tools like MSVC that support it."""
|
||||
self.batches.append(Batch(targets, sources))
|
||||
|
||||
def prepare(self):
|
||||
"""
|
||||
Preparatory checks for whether this Executor can go ahead
|
||||
and (try to) build its targets.
|
||||
"""
|
||||
for s in self.get_all_sources():
|
||||
if s.missing():
|
||||
msg = "Source `%s' not found, needed by target `%s'."
|
||||
raise SCons.Errors.StopError(msg % (s, self.batches[0].targets[0]))
|
||||
|
||||
def add_pre_action(self, action):
|
||||
self.pre_actions.append(action)
|
||||
|
||||
def add_post_action(self, action):
|
||||
self.post_actions.append(action)
|
||||
|
||||
# another extra indirection for new-style objects and nullify...
|
||||
|
||||
def __str__(self):
|
||||
return _execute_str_map[self._execute_str](self)
|
||||
|
||||
def nullify(self):
|
||||
self.cleanup()
|
||||
self._do_execute = 0
|
||||
self._execute_str = 0
|
||||
|
||||
@SCons.Memoize.CountMethodCall
|
||||
def get_contents(self):
|
||||
"""Fetch the signature contents. This is the main reason this
|
||||
class exists, so we can compute this once and cache it regardless
|
||||
of how many target or source Nodes there are.
|
||||
|
||||
Returns bytes
|
||||
"""
|
||||
try:
|
||||
return self._memo['get_contents']
|
||||
except KeyError:
|
||||
pass
|
||||
env = self.get_build_env()
|
||||
|
||||
action_list = self.get_action_list()
|
||||
all_targets = self.get_all_targets()
|
||||
all_sources = self.get_all_sources()
|
||||
|
||||
result = bytearray("",'utf-8').join([action.get_contents(all_targets,
|
||||
all_sources,
|
||||
env)
|
||||
for action in action_list])
|
||||
|
||||
self._memo['get_contents'] = result
|
||||
return result
|
||||
|
||||
def get_timestamp(self):
|
||||
"""Fetch a time stamp for this Executor. We don't have one, of
|
||||
course (only files do), but this is the interface used by the
|
||||
timestamp module.
|
||||
"""
|
||||
return 0
|
||||
|
||||
def scan_targets(self, scanner):
|
||||
# TODO(batch): scan by batches
|
||||
self.scan(scanner, self.get_all_targets())
|
||||
|
||||
def scan_sources(self, scanner):
|
||||
# TODO(batch): scan by batches
|
||||
if self.batches[0].sources:
|
||||
self.scan(scanner, self.get_all_sources())
|
||||
|
||||
def scan(self, scanner, node_list):
|
||||
"""Scan a list of this Executor's files (targets or sources) for
|
||||
implicit dependencies and update all of the targets with them.
|
||||
This essentially short-circuits an N*M scan of the sources for
|
||||
each individual target, which is a hell of a lot more efficient.
|
||||
"""
|
||||
env = self.get_build_env()
|
||||
path = self.get_build_scanner_path
|
||||
kw = self.get_kw()
|
||||
|
||||
# TODO(batch): scan by batches)
|
||||
deps = []
|
||||
|
||||
for node in node_list:
|
||||
node.disambiguate()
|
||||
deps.extend(node.get_implicit_deps(env, scanner, path, kw))
|
||||
|
||||
deps.extend(self.get_implicit_deps())
|
||||
|
||||
for tgt in self.get_all_targets():
|
||||
tgt.add_to_implicit(deps)
|
||||
|
||||
def _get_unignored_sources_key(self, node, ignore=()):
|
||||
return (node,) + tuple(ignore)
|
||||
|
||||
@SCons.Memoize.CountDictCall(_get_unignored_sources_key)
|
||||
def get_unignored_sources(self, node, ignore=()):
|
||||
key = (node,) + tuple(ignore)
|
||||
try:
|
||||
memo_dict = self._memo['get_unignored_sources']
|
||||
except KeyError:
|
||||
memo_dict = {}
|
||||
self._memo['get_unignored_sources'] = memo_dict
|
||||
else:
|
||||
try:
|
||||
return memo_dict[key]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if node:
|
||||
# TODO: better way to do this (it's a linear search,
|
||||
# but it may not be critical path)?
|
||||
sourcelist = []
|
||||
for b in self.batches:
|
||||
if node in b.targets:
|
||||
sourcelist = b.sources
|
||||
break
|
||||
else:
|
||||
sourcelist = self.get_all_sources()
|
||||
if ignore:
|
||||
idict = {}
|
||||
for i in ignore:
|
||||
idict[i] = 1
|
||||
sourcelist = [s for s in sourcelist if s not in idict]
|
||||
|
||||
memo_dict[key] = sourcelist
|
||||
|
||||
return sourcelist
|
||||
|
||||
def get_implicit_deps(self):
|
||||
"""Return the executor's implicit dependencies, i.e. the nodes of
|
||||
the commands to be executed."""
|
||||
result = []
|
||||
build_env = self.get_build_env()
|
||||
for act in self.get_action_list():
|
||||
deps = act.get_implicit_deps(self.get_all_targets(),
|
||||
self.get_all_sources(),
|
||||
build_env)
|
||||
result.extend(deps)
|
||||
return result
|
||||
|
||||
|
||||
|
||||
_batch_executors = {}
|
||||
|
||||
def GetBatchExecutor(key):
|
||||
return _batch_executors[key]
|
||||
|
||||
def AddBatchExecutor(key, executor):
|
||||
assert key not in _batch_executors
|
||||
_batch_executors[key] = executor
|
||||
|
||||
nullenv = None
|
||||
|
||||
|
||||
class NullEnvironment(SCons.Util.Null):
|
||||
import SCons.CacheDir
|
||||
_CacheDir_path = None
|
||||
_CacheDir = SCons.CacheDir.CacheDir(None)
|
||||
def get_CacheDir(self):
|
||||
return self._CacheDir
|
||||
|
||||
|
||||
def get_NullEnvironment():
|
||||
"""Use singleton pattern for Null Environments."""
|
||||
global nullenv
|
||||
|
||||
if nullenv is None:
|
||||
nullenv = NullEnvironment()
|
||||
return nullenv
|
||||
|
||||
class Null(object, metaclass=NoSlotsPyPy):
|
||||
"""A null Executor, with a null build Environment, that does
|
||||
nothing when the rest of the methods call it.
|
||||
|
||||
This might be able to disappear when we refactor things to
|
||||
disassociate Builders from Nodes entirely, so we're not
|
||||
going to worry about unit tests for this--at least for now.
|
||||
"""
|
||||
|
||||
__slots__ = ('pre_actions',
|
||||
'post_actions',
|
||||
'env',
|
||||
'overridelist',
|
||||
'batches',
|
||||
'builder_kw',
|
||||
'_memo',
|
||||
'lvars',
|
||||
'_changed_sources_list',
|
||||
'_changed_targets_list',
|
||||
'_unchanged_sources_list',
|
||||
'_unchanged_targets_list',
|
||||
'action_list',
|
||||
'_do_execute',
|
||||
'_execute_str')
|
||||
|
||||
def __init__(self, *args, **kw):
|
||||
if SCons.Debug.track_instances:
|
||||
logInstanceCreation(self, 'Executor.Null')
|
||||
self.batches = [Batch(kw['targets'][:], [])]
|
||||
def get_build_env(self):
|
||||
return get_NullEnvironment()
|
||||
def get_build_scanner_path(self):
|
||||
return None
|
||||
def cleanup(self):
|
||||
pass
|
||||
def prepare(self):
|
||||
pass
|
||||
def get_unignored_sources(self, *args, **kw):
|
||||
return tuple(())
|
||||
def get_action_targets(self):
|
||||
return []
|
||||
def get_action_list(self):
|
||||
return []
|
||||
def get_all_targets(self):
|
||||
return self.batches[0].targets
|
||||
def get_all_sources(self):
|
||||
return self.batches[0].targets[0].sources
|
||||
def get_all_children(self):
|
||||
return self.batches[0].targets[0].children()
|
||||
def get_all_prerequisites(self):
|
||||
return []
|
||||
def get_action_side_effects(self):
|
||||
return []
|
||||
def __call__(self, *args, **kw):
|
||||
return 0
|
||||
def get_contents(self):
|
||||
return ''
|
||||
def _morph(self):
|
||||
"""Morph this Null executor to a real Executor object."""
|
||||
batches = self.batches
|
||||
self.__class__ = Executor
|
||||
self.__init__([])
|
||||
self.batches = batches
|
||||
|
||||
# The following methods require morphing this Null Executor to a
|
||||
# real Executor object.
|
||||
|
||||
def add_pre_action(self, action):
|
||||
self._morph()
|
||||
self.add_pre_action(action)
|
||||
def add_post_action(self, action):
|
||||
self._morph()
|
||||
self.add_post_action(action)
|
||||
def set_action_list(self, action):
|
||||
self._morph()
|
||||
self.set_action_list(action)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
435
scons/scons-local-4.0.1/SCons/Job.py
Normal file
435
scons/scons-local-4.0.1/SCons/Job.py
Normal file
|
@ -0,0 +1,435 @@
|
|||
"""SCons.Job
|
||||
|
||||
This module defines the Serial and Parallel classes that execute tasks to
|
||||
complete a build. The Jobs class provides a higher level interface to start,
|
||||
stop, and wait on jobs.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import SCons.compat
|
||||
|
||||
import os
|
||||
import signal
|
||||
|
||||
import SCons.Errors
|
||||
|
||||
# The default stack size (in kilobytes) of the threads used to execute
|
||||
# jobs in parallel.
|
||||
#
|
||||
# We use a stack size of 256 kilobytes. The default on some platforms
|
||||
# is too large and prevents us from creating enough threads to fully
|
||||
# parallelized the build. For example, the default stack size on linux
|
||||
# is 8 MBytes.
|
||||
|
||||
explicit_stack_size = None
|
||||
default_stack_size = 256
|
||||
|
||||
interrupt_msg = 'Build interrupted.'
|
||||
|
||||
|
||||
class InterruptState:
|
||||
def __init__(self):
|
||||
self.interrupted = False
|
||||
|
||||
def set(self):
|
||||
self.interrupted = True
|
||||
|
||||
def __call__(self):
|
||||
return self.interrupted
|
||||
|
||||
|
||||
class Jobs:
|
||||
"""An instance of this class initializes N jobs, and provides
|
||||
methods for starting, stopping, and waiting on all N jobs.
|
||||
"""
|
||||
|
||||
def __init__(self, num, taskmaster):
|
||||
"""
|
||||
Create 'num' jobs using the given taskmaster.
|
||||
|
||||
If 'num' is 1 or less, then a serial job will be used,
|
||||
otherwise a parallel job with 'num' worker threads will
|
||||
be used.
|
||||
|
||||
The 'num_jobs' attribute will be set to the actual number of jobs
|
||||
allocated. If more than one job is requested but the Parallel
|
||||
class can't do it, it gets reset to 1. Wrapping interfaces that
|
||||
care should check the value of 'num_jobs' after initialization.
|
||||
"""
|
||||
|
||||
self.job = None
|
||||
if num > 1:
|
||||
stack_size = explicit_stack_size
|
||||
if stack_size is None:
|
||||
stack_size = default_stack_size
|
||||
|
||||
try:
|
||||
self.job = Parallel(taskmaster, num, stack_size)
|
||||
self.num_jobs = num
|
||||
except NameError:
|
||||
pass
|
||||
if self.job is None:
|
||||
self.job = Serial(taskmaster)
|
||||
self.num_jobs = 1
|
||||
|
||||
def run(self, postfunc=lambda: None):
|
||||
"""Run the jobs.
|
||||
|
||||
postfunc() will be invoked after the jobs has run. It will be
|
||||
invoked even if the jobs are interrupted by a keyboard
|
||||
interrupt (well, in fact by a signal such as either SIGINT,
|
||||
SIGTERM or SIGHUP). The execution of postfunc() is protected
|
||||
against keyboard interrupts and is guaranteed to run to
|
||||
completion."""
|
||||
self._setup_sig_handler()
|
||||
try:
|
||||
self.job.start()
|
||||
finally:
|
||||
postfunc()
|
||||
self._reset_sig_handler()
|
||||
|
||||
def were_interrupted(self):
|
||||
"""Returns whether the jobs were interrupted by a signal."""
|
||||
return self.job.interrupted()
|
||||
|
||||
def _setup_sig_handler(self):
|
||||
"""Setup an interrupt handler so that SCons can shutdown cleanly in
|
||||
various conditions:
|
||||
|
||||
a) SIGINT: Keyboard interrupt
|
||||
b) SIGTERM: kill or system shutdown
|
||||
c) SIGHUP: Controlling shell exiting
|
||||
|
||||
We handle all of these cases by stopping the taskmaster. It
|
||||
turns out that it's very difficult to stop the build process
|
||||
by throwing asynchronously an exception such as
|
||||
KeyboardInterrupt. For example, the python Condition
|
||||
variables (threading.Condition) and queues do not seem to be
|
||||
asynchronous-exception-safe. It would require adding a whole
|
||||
bunch of try/finally block and except KeyboardInterrupt all
|
||||
over the place.
|
||||
|
||||
Note also that we have to be careful to handle the case when
|
||||
SCons forks before executing another process. In that case, we
|
||||
want the child to exit immediately.
|
||||
"""
|
||||
def handler(signum, stack, self=self, parentpid=os.getpid()):
|
||||
if os.getpid() == parentpid:
|
||||
self.job.taskmaster.stop()
|
||||
self.job.interrupted.set()
|
||||
else:
|
||||
os._exit(2)
|
||||
|
||||
self.old_sigint = signal.signal(signal.SIGINT, handler)
|
||||
self.old_sigterm = signal.signal(signal.SIGTERM, handler)
|
||||
try:
|
||||
self.old_sighup = signal.signal(signal.SIGHUP, handler)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def _reset_sig_handler(self):
|
||||
"""Restore the signal handlers to their previous state (before the
|
||||
call to _setup_sig_handler()."""
|
||||
|
||||
signal.signal(signal.SIGINT, self.old_sigint)
|
||||
signal.signal(signal.SIGTERM, self.old_sigterm)
|
||||
try:
|
||||
signal.signal(signal.SIGHUP, self.old_sighup)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
class Serial:
|
||||
"""This class is used to execute tasks in series, and is more efficient
|
||||
than Parallel, but is only appropriate for non-parallel builds. Only
|
||||
one instance of this class should be in existence at a time.
|
||||
|
||||
This class is not thread safe.
|
||||
"""
|
||||
|
||||
def __init__(self, taskmaster):
|
||||
"""Create a new serial job given a taskmaster.
|
||||
|
||||
The taskmaster's next_task() method should return the next task
|
||||
that needs to be executed, or None if there are no more tasks. The
|
||||
taskmaster's executed() method will be called for each task when it
|
||||
is successfully executed, or failed() will be called if it failed to
|
||||
execute (e.g. execute() raised an exception)."""
|
||||
|
||||
self.taskmaster = taskmaster
|
||||
self.interrupted = InterruptState()
|
||||
|
||||
def start(self):
|
||||
"""Start the job. This will begin pulling tasks from the taskmaster
|
||||
and executing them, and return when there are no more tasks. If a task
|
||||
fails to execute (i.e. execute() raises an exception), then the job will
|
||||
stop."""
|
||||
|
||||
while True:
|
||||
task = self.taskmaster.next_task()
|
||||
|
||||
if task is None:
|
||||
break
|
||||
|
||||
try:
|
||||
task.prepare()
|
||||
if task.needs_execute():
|
||||
task.execute()
|
||||
except Exception:
|
||||
if self.interrupted():
|
||||
try:
|
||||
raise SCons.Errors.BuildError(
|
||||
task.targets[0], errstr=interrupt_msg)
|
||||
except:
|
||||
task.exception_set()
|
||||
else:
|
||||
task.exception_set()
|
||||
|
||||
# Let the failed() callback function arrange for the
|
||||
# build to stop if that's appropriate.
|
||||
task.failed()
|
||||
else:
|
||||
task.executed()
|
||||
|
||||
task.postprocess()
|
||||
self.taskmaster.cleanup()
|
||||
|
||||
|
||||
# Trap import failure so that everything in the Job module but the
|
||||
# Parallel class (and its dependent classes) will work if the interpreter
|
||||
# doesn't support threads.
|
||||
try:
|
||||
import queue
|
||||
import threading
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
class Worker(threading.Thread):
|
||||
"""A worker thread waits on a task to be posted to its request queue,
|
||||
dequeues the task, executes it, and posts a tuple including the task
|
||||
and a boolean indicating whether the task executed successfully. """
|
||||
|
||||
def __init__(self, requestQueue, resultsQueue, interrupted):
|
||||
threading.Thread.__init__(self)
|
||||
self.setDaemon(1)
|
||||
self.requestQueue = requestQueue
|
||||
self.resultsQueue = resultsQueue
|
||||
self.interrupted = interrupted
|
||||
self.start()
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
task = self.requestQueue.get()
|
||||
|
||||
if task is None:
|
||||
# The "None" value is used as a sentinel by
|
||||
# ThreadPool.cleanup(). This indicates that there
|
||||
# are no more tasks, so we should quit.
|
||||
break
|
||||
|
||||
try:
|
||||
if self.interrupted():
|
||||
raise SCons.Errors.BuildError(
|
||||
task.targets[0], errstr=interrupt_msg)
|
||||
task.execute()
|
||||
except:
|
||||
task.exception_set()
|
||||
ok = False
|
||||
else:
|
||||
ok = True
|
||||
|
||||
self.resultsQueue.put((task, ok))
|
||||
|
||||
class ThreadPool:
|
||||
"""This class is responsible for spawning and managing worker threads."""
|
||||
|
||||
def __init__(self, num, stack_size, interrupted):
|
||||
"""Create the request and reply queues, and 'num' worker threads.
|
||||
|
||||
One must specify the stack size of the worker threads. The
|
||||
stack size is specified in kilobytes.
|
||||
"""
|
||||
self.requestQueue = queue.Queue(0)
|
||||
self.resultsQueue = queue.Queue(0)
|
||||
|
||||
try:
|
||||
prev_size = threading.stack_size(stack_size*1024)
|
||||
except AttributeError as e:
|
||||
# Only print a warning if the stack size has been
|
||||
# explicitly set.
|
||||
if explicit_stack_size is not None:
|
||||
msg = "Setting stack size is unsupported by this version of Python:\n " + \
|
||||
e.args[0]
|
||||
SCons.Warnings.warn(SCons.Warnings.StackSizeWarning, msg)
|
||||
except ValueError as e:
|
||||
msg = "Setting stack size failed:\n " + str(e)
|
||||
SCons.Warnings.warn(SCons.Warnings.StackSizeWarning, msg)
|
||||
|
||||
# Create worker threads
|
||||
self.workers = []
|
||||
for _ in range(num):
|
||||
worker = Worker(self.requestQueue, self.resultsQueue, interrupted)
|
||||
self.workers.append(worker)
|
||||
|
||||
if 'prev_size' in locals():
|
||||
threading.stack_size(prev_size)
|
||||
|
||||
def put(self, task):
|
||||
"""Put task into request queue."""
|
||||
self.requestQueue.put(task)
|
||||
|
||||
def get(self):
|
||||
"""Remove and return a result tuple from the results queue."""
|
||||
return self.resultsQueue.get()
|
||||
|
||||
def preparation_failed(self, task):
|
||||
self.resultsQueue.put((task, False))
|
||||
|
||||
def cleanup(self):
|
||||
"""
|
||||
Shuts down the thread pool, giving each worker thread a
|
||||
chance to shut down gracefully.
|
||||
"""
|
||||
# For each worker thread, put a sentinel "None" value
|
||||
# on the requestQueue (indicating that there's no work
|
||||
# to be done) so that each worker thread will get one and
|
||||
# terminate gracefully.
|
||||
for _ in self.workers:
|
||||
self.requestQueue.put(None)
|
||||
|
||||
# Wait for all of the workers to terminate.
|
||||
#
|
||||
# If we don't do this, later Python versions (2.4, 2.5) often
|
||||
# seem to raise exceptions during shutdown. This happens
|
||||
# in requestQueue.get(), as an assertion failure that
|
||||
# requestQueue.not_full is notified while not acquired,
|
||||
# seemingly because the main thread has shut down (or is
|
||||
# in the process of doing so) while the workers are still
|
||||
# trying to pull sentinels off the requestQueue.
|
||||
#
|
||||
# Normally these terminations should happen fairly quickly,
|
||||
# but we'll stick a one-second timeout on here just in case
|
||||
# someone gets hung.
|
||||
for worker in self.workers:
|
||||
worker.join(1.0)
|
||||
self.workers = []
|
||||
|
||||
class Parallel:
|
||||
"""This class is used to execute tasks in parallel, and is somewhat
|
||||
less efficient than Serial, but is appropriate for parallel builds.
|
||||
|
||||
This class is thread safe.
|
||||
"""
|
||||
|
||||
def __init__(self, taskmaster, num, stack_size):
|
||||
"""Create a new parallel job given a taskmaster.
|
||||
|
||||
The taskmaster's next_task() method should return the next
|
||||
task that needs to be executed, or None if there are no more
|
||||
tasks. The taskmaster's executed() method will be called
|
||||
for each task when it is successfully executed, or failed()
|
||||
will be called if the task failed to execute (i.e. execute()
|
||||
raised an exception).
|
||||
|
||||
Note: calls to taskmaster are serialized, but calls to
|
||||
execute() on distinct tasks are not serialized, because
|
||||
that is the whole point of parallel jobs: they can execute
|
||||
multiple tasks simultaneously. """
|
||||
|
||||
self.taskmaster = taskmaster
|
||||
self.interrupted = InterruptState()
|
||||
self.tp = ThreadPool(num, stack_size, self.interrupted)
|
||||
|
||||
self.maxjobs = num
|
||||
|
||||
def start(self):
|
||||
"""Start the job. This will begin pulling tasks from the
|
||||
taskmaster and executing them, and return when there are no
|
||||
more tasks. If a task fails to execute (i.e. execute() raises
|
||||
an exception), then the job will stop."""
|
||||
|
||||
jobs = 0
|
||||
|
||||
while True:
|
||||
# Start up as many available tasks as we're
|
||||
# allowed to.
|
||||
while jobs < self.maxjobs:
|
||||
task = self.taskmaster.next_task()
|
||||
if task is None:
|
||||
break
|
||||
|
||||
try:
|
||||
# prepare task for execution
|
||||
task.prepare()
|
||||
except:
|
||||
task.exception_set()
|
||||
task.failed()
|
||||
task.postprocess()
|
||||
else:
|
||||
if task.needs_execute():
|
||||
# dispatch task
|
||||
self.tp.put(task)
|
||||
jobs = jobs + 1
|
||||
else:
|
||||
task.executed()
|
||||
task.postprocess()
|
||||
|
||||
if not task and not jobs: break
|
||||
|
||||
# Let any/all completed tasks finish up before we go
|
||||
# back and put the next batch of tasks on the queue.
|
||||
while True:
|
||||
task, ok = self.tp.get()
|
||||
jobs = jobs - 1
|
||||
|
||||
if ok:
|
||||
task.executed()
|
||||
else:
|
||||
if self.interrupted():
|
||||
try:
|
||||
raise SCons.Errors.BuildError(
|
||||
task.targets[0], errstr=interrupt_msg)
|
||||
except:
|
||||
task.exception_set()
|
||||
|
||||
# Let the failed() callback function arrange
|
||||
# for the build to stop if that's appropriate.
|
||||
task.failed()
|
||||
|
||||
task.postprocess()
|
||||
|
||||
if self.tp.resultsQueue.empty():
|
||||
break
|
||||
|
||||
self.tp.cleanup()
|
||||
self.taskmaster.cleanup()
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
243
scons/scons-local-4.0.1/SCons/Memoize.py
Normal file
243
scons/scons-local-4.0.1/SCons/Memoize.py
Normal file
|
@ -0,0 +1,243 @@
|
|||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
__doc__ = """Memoizer
|
||||
|
||||
A decorator-based implementation to count hits and misses of the computed
|
||||
values that various methods cache in memory.
|
||||
|
||||
Use of this modules assumes that wrapped methods be coded to cache their
|
||||
values in a consistent way. In particular, it requires that the class uses a
|
||||
dictionary named "_memo" to store the cached values.
|
||||
|
||||
Here is an example of wrapping a method that returns a computed value,
|
||||
with no input parameters::
|
||||
|
||||
@SCons.Memoize.CountMethodCall
|
||||
def foo(self):
|
||||
|
||||
try: # Memoization
|
||||
return self._memo['foo'] # Memoization
|
||||
except KeyError: # Memoization
|
||||
pass # Memoization
|
||||
|
||||
result = self.compute_foo_value()
|
||||
|
||||
self._memo['foo'] = result # Memoization
|
||||
|
||||
return result
|
||||
|
||||
Here is an example of wrapping a method that will return different values
|
||||
based on one or more input arguments::
|
||||
|
||||
def _bar_key(self, argument): # Memoization
|
||||
return argument # Memoization
|
||||
|
||||
@SCons.Memoize.CountDictCall(_bar_key)
|
||||
def bar(self, argument):
|
||||
|
||||
memo_key = argument # Memoization
|
||||
try: # Memoization
|
||||
memo_dict = self._memo['bar'] # Memoization
|
||||
except KeyError: # Memoization
|
||||
memo_dict = {} # Memoization
|
||||
self._memo['dict'] = memo_dict # Memoization
|
||||
else: # Memoization
|
||||
try: # Memoization
|
||||
return memo_dict[memo_key] # Memoization
|
||||
except KeyError: # Memoization
|
||||
pass # Memoization
|
||||
|
||||
result = self.compute_bar_value(argument)
|
||||
|
||||
memo_dict[memo_key] = result # Memoization
|
||||
|
||||
return result
|
||||
|
||||
Deciding what to cache is tricky, because different configurations
|
||||
can have radically different performance tradeoffs, and because the
|
||||
tradeoffs involved are often so non-obvious. Consequently, deciding
|
||||
whether or not to cache a given method will likely be more of an art than
|
||||
a science, but should still be based on available data from this module.
|
||||
Here are some VERY GENERAL guidelines about deciding whether or not to
|
||||
cache return values from a method that's being called a lot:
|
||||
|
||||
-- The first question to ask is, "Can we change the calling code
|
||||
so this method isn't called so often?" Sometimes this can be
|
||||
done by changing the algorithm. Sometimes the *caller* should
|
||||
be memoized, not the method you're looking at.
|
||||
|
||||
-- The memoized function should be timed with multiple configurations
|
||||
to make sure it doesn't inadvertently slow down some other
|
||||
configuration.
|
||||
|
||||
-- When memoizing values based on a dictionary key composed of
|
||||
input arguments, you don't need to use all of the arguments
|
||||
if some of them don't affect the return values.
|
||||
|
||||
"""
|
||||
|
||||
# A flag controlling whether or not we actually use memoization.
|
||||
use_memoizer = None
|
||||
|
||||
# Global list of counter objects
|
||||
CounterList = {}
|
||||
|
||||
class Counter:
|
||||
"""
|
||||
Base class for counting memoization hits and misses.
|
||||
|
||||
We expect that the initialization in a matching decorator will
|
||||
fill in the correct class name and method name that represents
|
||||
the name of the function being counted.
|
||||
"""
|
||||
def __init__(self, cls_name, method_name):
|
||||
"""
|
||||
"""
|
||||
self.cls_name = cls_name
|
||||
self.method_name = method_name
|
||||
self.hit = 0
|
||||
self.miss = 0
|
||||
def key(self):
|
||||
return self.cls_name+'.'+self.method_name
|
||||
def display(self):
|
||||
print(" {:7d} hits {:7d} misses {}()".format(self.hit, self.miss, self.key()))
|
||||
def __eq__(self, other):
|
||||
try:
|
||||
return self.key() == other.key()
|
||||
except AttributeError:
|
||||
return True
|
||||
|
||||
class CountValue(Counter):
|
||||
"""
|
||||
A counter class for simple, atomic memoized values.
|
||||
|
||||
A CountValue object should be instantiated in a decorator for each of
|
||||
the class's methods that memoizes its return value by simply storing
|
||||
the return value in its _memo dictionary.
|
||||
"""
|
||||
def count(self, *args, **kw):
|
||||
""" Counts whether the memoized value has already been
|
||||
set (a hit) or not (a miss).
|
||||
"""
|
||||
obj = args[0]
|
||||
if self.method_name in obj._memo:
|
||||
self.hit = self.hit + 1
|
||||
else:
|
||||
self.miss = self.miss + 1
|
||||
|
||||
class CountDict(Counter):
|
||||
"""
|
||||
A counter class for memoized values stored in a dictionary, with
|
||||
keys based on the method's input arguments.
|
||||
|
||||
A CountDict object is instantiated in a decorator for each of the
|
||||
class's methods that memoizes its return value in a dictionary,
|
||||
indexed by some key that can be computed from one or more of
|
||||
its input arguments.
|
||||
"""
|
||||
def __init__(self, cls_name, method_name, keymaker):
|
||||
"""
|
||||
"""
|
||||
Counter.__init__(self, cls_name, method_name)
|
||||
self.keymaker = keymaker
|
||||
def count(self, *args, **kw):
|
||||
""" Counts whether the computed key value is already present
|
||||
in the memoization dictionary (a hit) or not (a miss).
|
||||
"""
|
||||
obj = args[0]
|
||||
try:
|
||||
memo_dict = obj._memo[self.method_name]
|
||||
except KeyError:
|
||||
self.miss = self.miss + 1
|
||||
else:
|
||||
key = self.keymaker(*args, **kw)
|
||||
if key in memo_dict:
|
||||
self.hit = self.hit + 1
|
||||
else:
|
||||
self.miss = self.miss + 1
|
||||
|
||||
def Dump(title=None):
|
||||
""" Dump the hit/miss count for all the counters
|
||||
collected so far.
|
||||
"""
|
||||
if title:
|
||||
print(title)
|
||||
for counter in sorted(CounterList):
|
||||
CounterList[counter].display()
|
||||
|
||||
def EnableMemoization():
|
||||
global use_memoizer
|
||||
use_memoizer = 1
|
||||
|
||||
def CountMethodCall(fn):
|
||||
""" Decorator for counting memoizer hits/misses while retrieving
|
||||
a simple value in a class method. It wraps the given method
|
||||
fn and uses a CountValue object to keep track of the
|
||||
caching statistics.
|
||||
Wrapping gets enabled by calling EnableMemoization().
|
||||
"""
|
||||
if use_memoizer:
|
||||
def wrapper(self, *args, **kwargs):
|
||||
global CounterList
|
||||
key = self.__class__.__name__+'.'+fn.__name__
|
||||
if key not in CounterList:
|
||||
CounterList[key] = CountValue(self.__class__.__name__, fn.__name__)
|
||||
CounterList[key].count(self, *args, **kwargs)
|
||||
return fn(self, *args, **kwargs)
|
||||
wrapper.__name__= fn.__name__
|
||||
return wrapper
|
||||
else:
|
||||
return fn
|
||||
|
||||
def CountDictCall(keyfunc):
|
||||
""" Decorator for counting memoizer hits/misses while accessing
|
||||
dictionary values with a key-generating function. Like
|
||||
CountMethodCall above, it wraps the given method
|
||||
fn and uses a CountDict object to keep track of the
|
||||
caching statistics. The dict-key function keyfunc has to
|
||||
get passed in the decorator call and gets stored in the
|
||||
CountDict instance.
|
||||
Wrapping gets enabled by calling EnableMemoization().
|
||||
"""
|
||||
def decorator(fn):
|
||||
if use_memoizer:
|
||||
def wrapper(self, *args, **kwargs):
|
||||
global CounterList
|
||||
key = self.__class__.__name__+'.'+fn.__name__
|
||||
if key not in CounterList:
|
||||
CounterList[key] = CountDict(self.__class__.__name__, fn.__name__, keyfunc)
|
||||
CounterList[key].count(self, *args, **kwargs)
|
||||
return fn(self, *args, **kwargs)
|
||||
wrapper.__name__= fn.__name__
|
||||
return wrapper
|
||||
else:
|
||||
return fn
|
||||
return decorator
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
182
scons/scons-local-4.0.1/SCons/Node/Alias.py
Normal file
182
scons/scons-local-4.0.1/SCons/Node/Alias.py
Normal file
|
@ -0,0 +1,182 @@
|
|||
|
||||
"""scons.Node.Alias
|
||||
|
||||
Alias nodes.
|
||||
|
||||
This creates a hash of global Aliases (dummy targets).
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import collections
|
||||
|
||||
import SCons.Errors
|
||||
import SCons.Node
|
||||
import SCons.Util
|
||||
from SCons.Util import MD5signature
|
||||
|
||||
class AliasNameSpace(collections.UserDict):
|
||||
def Alias(self, name, **kw):
|
||||
if isinstance(name, SCons.Node.Alias.Alias):
|
||||
return name
|
||||
try:
|
||||
a = self[name]
|
||||
except KeyError:
|
||||
a = SCons.Node.Alias.Alias(name, **kw)
|
||||
self[name] = a
|
||||
return a
|
||||
|
||||
def lookup(self, name, **kw):
|
||||
try:
|
||||
return self[name]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
class AliasNodeInfo(SCons.Node.NodeInfoBase):
|
||||
__slots__ = ('csig',)
|
||||
current_version_id = 2
|
||||
field_list = ['csig']
|
||||
def str_to_node(self, s):
|
||||
return default_ans.Alias(s)
|
||||
|
||||
def __getstate__(self):
|
||||
"""
|
||||
Return all fields that shall be pickled. Walk the slots in the class
|
||||
hierarchy and add those to the state dictionary. If a '__dict__' slot is
|
||||
available, copy all entries to the dictionary. Also include the version
|
||||
id, which is fixed for all instances of a class.
|
||||
"""
|
||||
state = getattr(self, '__dict__', {}).copy()
|
||||
for obj in type(self).mro():
|
||||
for name in getattr(obj,'__slots__',()):
|
||||
if hasattr(self, name):
|
||||
state[name] = getattr(self, name)
|
||||
|
||||
state['_version_id'] = self.current_version_id
|
||||
try:
|
||||
del state['__weakref__']
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
return state
|
||||
|
||||
def __setstate__(self, state):
|
||||
"""
|
||||
Restore the attributes from a pickled state.
|
||||
"""
|
||||
# TODO check or discard version
|
||||
del state['_version_id']
|
||||
for key, value in state.items():
|
||||
if key not in ('__weakref__',):
|
||||
setattr(self, key, value)
|
||||
|
||||
|
||||
class AliasBuildInfo(SCons.Node.BuildInfoBase):
|
||||
__slots__ = ()
|
||||
current_version_id = 2
|
||||
|
||||
class Alias(SCons.Node.Node):
|
||||
|
||||
NodeInfo = AliasNodeInfo
|
||||
BuildInfo = AliasBuildInfo
|
||||
|
||||
def __init__(self, name):
|
||||
SCons.Node.Node.__init__(self)
|
||||
self.name = name
|
||||
self.changed_since_last_build = 1
|
||||
self.store_info = 0
|
||||
|
||||
def str_for_display(self):
|
||||
return '"' + self.__str__() + '"'
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def make_ready(self):
|
||||
self.get_csig()
|
||||
|
||||
really_build = SCons.Node.Node.build
|
||||
is_up_to_date = SCons.Node.Node.children_are_up_to_date
|
||||
|
||||
def is_under(self, dir):
|
||||
# Make Alias nodes get built regardless of
|
||||
# what directory scons was run from. Alias nodes
|
||||
# are outside the filesystem:
|
||||
return 1
|
||||
|
||||
def get_contents(self):
|
||||
"""The contents of an alias is the concatenation
|
||||
of the content signatures of all its sources."""
|
||||
childsigs = [n.get_csig() for n in self.children()]
|
||||
return ''.join(childsigs)
|
||||
|
||||
def sconsign(self):
|
||||
"""An Alias is not recorded in .sconsign files"""
|
||||
pass
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
def build(self):
|
||||
"""A "builder" for aliases."""
|
||||
pass
|
||||
|
||||
def convert(self):
|
||||
try: del self.builder
|
||||
except AttributeError: pass
|
||||
self.reset_executor()
|
||||
self.build = self.really_build
|
||||
|
||||
def get_csig(self):
|
||||
"""
|
||||
Generate a node's content signature, the digested signature
|
||||
of its content.
|
||||
|
||||
node - the node
|
||||
cache - alternate node to use for the signature cache
|
||||
returns - the content signature
|
||||
"""
|
||||
try:
|
||||
return self.ninfo.csig
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
contents = self.get_contents()
|
||||
csig = MD5signature(contents)
|
||||
self.get_ninfo().csig = csig
|
||||
return csig
|
||||
|
||||
default_ans = AliasNameSpace()
|
||||
|
||||
SCons.Node.arg2nodes_lookups.append(default_ans.lookup)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
3831
scons/scons-local-4.0.1/SCons/Node/FS.py
Normal file
3831
scons/scons-local-4.0.1/SCons/Node/FS.py
Normal file
File diff suppressed because it is too large
Load diff
215
scons/scons-local-4.0.1/SCons/Node/Python.py
Normal file
215
scons/scons-local-4.0.1/SCons/Node/Python.py
Normal file
|
@ -0,0 +1,215 @@
|
|||
"""scons.Node.Python
|
||||
|
||||
Python nodes.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import SCons.Node
|
||||
|
||||
_memo_lookup_map = {}
|
||||
|
||||
|
||||
class ValueNodeInfo(SCons.Node.NodeInfoBase):
|
||||
__slots__ = ('csig',)
|
||||
current_version_id = 2
|
||||
|
||||
field_list = ['csig']
|
||||
|
||||
def str_to_node(self, s):
|
||||
return ValueWithMemo(s)
|
||||
|
||||
def __getstate__(self):
|
||||
"""
|
||||
Return all fields that shall be pickled. Walk the slots in the class
|
||||
hierarchy and add those to the state dictionary. If a '__dict__' slot
|
||||
is available, copy all entries to the dictionary. Also include the
|
||||
version id, which is fixed for all instances of a class.
|
||||
"""
|
||||
state = getattr(self, '__dict__', {}).copy()
|
||||
for obj in type(self).mro():
|
||||
for name in getattr(obj, '__slots__', ()):
|
||||
if hasattr(self, name):
|
||||
state[name] = getattr(self, name)
|
||||
|
||||
state['_version_id'] = self.current_version_id
|
||||
try:
|
||||
del state['__weakref__']
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
return state
|
||||
|
||||
def __setstate__(self, state):
|
||||
"""
|
||||
Restore the attributes from a pickled state.
|
||||
"""
|
||||
# TODO check or discard version
|
||||
del state['_version_id']
|
||||
for key, value in state.items():
|
||||
if key not in ('__weakref__',):
|
||||
setattr(self, key, value)
|
||||
|
||||
|
||||
class ValueBuildInfo(SCons.Node.BuildInfoBase):
|
||||
__slots__ = ()
|
||||
current_version_id = 2
|
||||
|
||||
|
||||
class Value(SCons.Node.Node):
|
||||
"""A class for Python variables, typically passed on the command line
|
||||
or generated by a script, but not from a file or some other source.
|
||||
"""
|
||||
|
||||
NodeInfo = ValueNodeInfo
|
||||
BuildInfo = ValueBuildInfo
|
||||
|
||||
def __init__(self, value, built_value=None, name=None):
|
||||
SCons.Node.Node.__init__(self)
|
||||
self.value = value
|
||||
self.changed_since_last_build = 6
|
||||
self.store_info = 0
|
||||
if built_value is not None:
|
||||
self.built_value = built_value
|
||||
|
||||
# Set a name so it can be a child of a node and not break
|
||||
# its parent's implementation of Node.get_contents.
|
||||
if name:
|
||||
self.name = name
|
||||
else:
|
||||
self.name = str(value)
|
||||
|
||||
def str_for_display(self):
|
||||
return repr(self.value)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.value)
|
||||
|
||||
def make_ready(self):
|
||||
self.get_csig()
|
||||
|
||||
def build(self, **kw):
|
||||
if not hasattr(self, 'built_value'):
|
||||
SCons.Node.Node.build(self, **kw)
|
||||
|
||||
is_up_to_date = SCons.Node.Node.children_are_up_to_date
|
||||
|
||||
def is_under(self, dir):
|
||||
# Make Value nodes get built regardless of
|
||||
# what directory scons was run from. Value nodes
|
||||
# are outside the filesystem:
|
||||
return 1
|
||||
|
||||
def write(self, built_value):
|
||||
"""Set the value of the node."""
|
||||
self.built_value = built_value
|
||||
|
||||
def read(self):
|
||||
"""Return the value. If necessary, the value is built."""
|
||||
self.build()
|
||||
if not hasattr(self, 'built_value'):
|
||||
self.built_value = self.value
|
||||
return self.built_value
|
||||
|
||||
def get_text_contents(self):
|
||||
"""By the assumption that the node.built_value is a
|
||||
deterministic product of the sources, the contents of a Value
|
||||
are the concatenation of all the contents of its sources. As
|
||||
the value need not be built when get_contents() is called, we
|
||||
cannot use the actual node.built_value."""
|
||||
###TODO: something reasonable about universal newlines
|
||||
contents = str(self.value)
|
||||
for kid in self.children(None):
|
||||
contents = contents + kid.get_contents().decode()
|
||||
return contents
|
||||
|
||||
def get_contents(self):
|
||||
"""
|
||||
Get contents for signature calculations.
|
||||
:return: bytes
|
||||
"""
|
||||
text_contents = self.get_text_contents()
|
||||
try:
|
||||
return text_contents.encode()
|
||||
except UnicodeDecodeError:
|
||||
# Already encoded as python2 str are bytes
|
||||
return text_contents
|
||||
|
||||
def changed_since_last_build(self, target, prev_ni):
|
||||
cur_csig = self.get_csig()
|
||||
try:
|
||||
return cur_csig != prev_ni.csig
|
||||
except AttributeError:
|
||||
return 1
|
||||
|
||||
def get_csig(self, calc=None):
|
||||
"""Because we're a Python value node and don't have a real
|
||||
timestamp, we get to ignore the calculator and just use the
|
||||
value contents.
|
||||
|
||||
Returns string. Ideally string of hex digits. (Not bytes)
|
||||
"""
|
||||
try:
|
||||
return self.ninfo.csig
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
contents = self.get_text_contents()
|
||||
|
||||
self.get_ninfo().csig = contents
|
||||
return contents
|
||||
|
||||
|
||||
def ValueWithMemo(value, built_value=None, name=None):
|
||||
"""
|
||||
Memoized Value() node factory.
|
||||
"""
|
||||
global _memo_lookup_map
|
||||
|
||||
# No current support for memoizing a value that needs to be built.
|
||||
if built_value:
|
||||
return Value(value, built_value, name=name)
|
||||
|
||||
try:
|
||||
memo_lookup_key = hash((value, name))
|
||||
except TypeError:
|
||||
# Non-primitive types will hit this codepath.
|
||||
return Value(value, name=name)
|
||||
|
||||
try:
|
||||
return _memo_lookup_map[memo_lookup_key]
|
||||
except KeyError:
|
||||
v = Value(value, built_value, name)
|
||||
_memo_lookup_map[memo_lookup_key] = v
|
||||
return v
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
1786
scons/scons-local-4.0.1/SCons/Node/__init__.py
Normal file
1786
scons/scons-local-4.0.1/SCons/Node/__init__.py
Normal file
File diff suppressed because it is too large
Load diff
227
scons/scons-local-4.0.1/SCons/PathList.py
Normal file
227
scons/scons-local-4.0.1/SCons/PathList.py
Normal file
|
@ -0,0 +1,227 @@
|
|||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
__doc__ = """SCons.PathList
|
||||
|
||||
A module for handling lists of directory paths (the sort of things
|
||||
that get set as CPPPATH, LIBPATH, etc.) with as much caching of data and
|
||||
efficiency as we can, while still keeping the evaluation delayed so that we
|
||||
Do the Right Thing (almost) regardless of how the variable is specified.
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
import SCons.Memoize
|
||||
import SCons.Node
|
||||
import SCons.Util
|
||||
|
||||
#
|
||||
# Variables to specify the different types of entries in a PathList object:
|
||||
#
|
||||
|
||||
TYPE_STRING_NO_SUBST = 0 # string with no '$'
|
||||
TYPE_STRING_SUBST = 1 # string containing '$'
|
||||
TYPE_OBJECT = 2 # other object
|
||||
|
||||
def node_conv(obj):
|
||||
"""
|
||||
This is the "string conversion" routine that we have our substitutions
|
||||
use to return Nodes, not strings. This relies on the fact that an
|
||||
EntryProxy object has a get() method that returns the underlying
|
||||
Node that it wraps, which is a bit of architectural dependence
|
||||
that we might need to break or modify in the future in response to
|
||||
additional requirements.
|
||||
"""
|
||||
try:
|
||||
get = obj.get
|
||||
except AttributeError:
|
||||
if isinstance(obj, SCons.Node.Node) or SCons.Util.is_Sequence( obj ):
|
||||
result = obj
|
||||
else:
|
||||
result = str(obj)
|
||||
else:
|
||||
result = get()
|
||||
return result
|
||||
|
||||
class _PathList:
|
||||
"""
|
||||
An actual PathList object.
|
||||
"""
|
||||
def __init__(self, pathlist):
|
||||
"""
|
||||
Initializes a PathList object, canonicalizing the input and
|
||||
pre-processing it for quicker substitution later.
|
||||
|
||||
The stored representation of the PathList is a list of tuples
|
||||
containing (type, value), where the "type" is one of the TYPE_*
|
||||
variables defined above. We distinguish between:
|
||||
|
||||
strings that contain no '$' and therefore need no
|
||||
delayed-evaluation string substitution (we expect that there
|
||||
will be many of these and that we therefore get a pretty
|
||||
big win from avoiding string substitution)
|
||||
|
||||
strings that contain '$' and therefore need substitution
|
||||
(the hard case is things like '${TARGET.dir}/include',
|
||||
which require re-evaluation for every target + source)
|
||||
|
||||
other objects (which may be something like an EntryProxy
|
||||
that needs a method called to return a Node)
|
||||
|
||||
Pre-identifying the type of each element in the PathList up-front
|
||||
and storing the type in the list of tuples is intended to reduce
|
||||
the amount of calculation when we actually do the substitution
|
||||
over and over for each target.
|
||||
"""
|
||||
if SCons.Util.is_String(pathlist):
|
||||
pathlist = pathlist.split(os.pathsep)
|
||||
elif not SCons.Util.is_Sequence(pathlist):
|
||||
pathlist = [pathlist]
|
||||
|
||||
pl = []
|
||||
for p in pathlist:
|
||||
try:
|
||||
found = '$' in p
|
||||
except (AttributeError, TypeError):
|
||||
type = TYPE_OBJECT
|
||||
else:
|
||||
if not found:
|
||||
type = TYPE_STRING_NO_SUBST
|
||||
else:
|
||||
type = TYPE_STRING_SUBST
|
||||
pl.append((type, p))
|
||||
|
||||
self.pathlist = tuple(pl)
|
||||
|
||||
def __len__(self): return len(self.pathlist)
|
||||
|
||||
def __getitem__(self, i): return self.pathlist[i]
|
||||
|
||||
def subst_path(self, env, target, source):
|
||||
"""
|
||||
Performs construction variable substitution on a pre-digested
|
||||
PathList for a specific target and source.
|
||||
"""
|
||||
result = []
|
||||
for type, value in self.pathlist:
|
||||
if type == TYPE_STRING_SUBST:
|
||||
value = env.subst(value, target=target, source=source,
|
||||
conv=node_conv)
|
||||
if SCons.Util.is_Sequence(value):
|
||||
result.extend(SCons.Util.flatten(value))
|
||||
elif value:
|
||||
result.append(value)
|
||||
elif type == TYPE_OBJECT:
|
||||
value = node_conv(value)
|
||||
if value:
|
||||
result.append(value)
|
||||
elif value:
|
||||
result.append(value)
|
||||
return tuple(result)
|
||||
|
||||
|
||||
class PathListCache:
|
||||
"""
|
||||
A class to handle caching of PathList lookups.
|
||||
|
||||
This class gets instantiated once and then deleted from the namespace,
|
||||
so it's used as a Singleton (although we don't enforce that in the
|
||||
usual Pythonic ways). We could have just made the cache a dictionary
|
||||
in the module namespace, but putting it in this class allows us to
|
||||
use the same Memoizer pattern that we use elsewhere to count cache
|
||||
hits and misses, which is very valuable.
|
||||
|
||||
Lookup keys in the cache are computed by the _PathList_key() method.
|
||||
Cache lookup should be quick, so we don't spend cycles canonicalizing
|
||||
all forms of the same lookup key. For example, 'x:y' and ['x',
|
||||
'y'] logically represent the same list, but we don't bother to
|
||||
split string representations and treat those two equivalently.
|
||||
(Note, however, that we do, treat lists and tuples the same.)
|
||||
|
||||
The main type of duplication we're trying to catch will come from
|
||||
looking up the same path list from two different clones of the
|
||||
same construction environment. That is, given
|
||||
|
||||
env2 = env1.Clone()
|
||||
|
||||
both env1 and env2 will have the same CPPPATH value, and we can
|
||||
cheaply avoid re-parsing both values of CPPPATH by using the
|
||||
common value from this cache.
|
||||
"""
|
||||
def __init__(self):
|
||||
self._memo = {}
|
||||
|
||||
def _PathList_key(self, pathlist):
|
||||
"""
|
||||
Returns the key for memoization of PathLists.
|
||||
|
||||
Note that we want this to be pretty quick, so we don't completely
|
||||
canonicalize all forms of the same list. For example,
|
||||
'dir1:$ROOT/dir2' and ['$ROOT/dir1', 'dir'] may logically
|
||||
represent the same list if you're executing from $ROOT, but
|
||||
we're not going to bother splitting strings into path elements,
|
||||
or massaging strings into Nodes, to identify that equivalence.
|
||||
We just want to eliminate obvious redundancy from the normal
|
||||
case of re-using exactly the same cloned value for a path.
|
||||
"""
|
||||
if SCons.Util.is_Sequence(pathlist):
|
||||
pathlist = tuple(SCons.Util.flatten(pathlist))
|
||||
return pathlist
|
||||
|
||||
@SCons.Memoize.CountDictCall(_PathList_key)
|
||||
def PathList(self, pathlist):
|
||||
"""
|
||||
Returns the cached _PathList object for the specified pathlist,
|
||||
creating and caching a new object as necessary.
|
||||
"""
|
||||
pathlist = self._PathList_key(pathlist)
|
||||
try:
|
||||
memo_dict = self._memo['PathList']
|
||||
except KeyError:
|
||||
memo_dict = {}
|
||||
self._memo['PathList'] = memo_dict
|
||||
else:
|
||||
try:
|
||||
return memo_dict[pathlist]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
result = _PathList(pathlist)
|
||||
|
||||
memo_dict[pathlist] = result
|
||||
|
||||
return result
|
||||
|
||||
PathList = PathListCache().PathList
|
||||
|
||||
|
||||
del PathListCache
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
302
scons/scons-local-4.0.1/SCons/Platform/__init__.py
Normal file
302
scons/scons-local-4.0.1/SCons/Platform/__init__.py
Normal file
|
@ -0,0 +1,302 @@
|
|||
"""SCons.Platform
|
||||
|
||||
SCons platform selection.
|
||||
|
||||
This looks for modules that define a callable object that can modify a
|
||||
construction environment as appropriate for a given platform.
|
||||
|
||||
Note that we take a more simplistic view of "platform" than Python does.
|
||||
We're looking for a single string that determines a set of
|
||||
tool-independent variables with which to initialize a construction
|
||||
environment. Consequently, we'll examine both sys.platform and os.name
|
||||
(and anything else that might come in to play) in order to return some
|
||||
specification which is unique enough for our purposes.
|
||||
|
||||
Note that because this subsystem just *selects* a callable that can
|
||||
modify a construction environment, it's possible for people to define
|
||||
their own "platform specification" in an arbitrary callable function.
|
||||
No one needs to use or tie in to this subsystem in order to roll
|
||||
their own platform definition.
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import SCons.compat
|
||||
|
||||
import importlib
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
import SCons.Errors
|
||||
import SCons.Subst
|
||||
import SCons.Tool
|
||||
|
||||
|
||||
def platform_default():
|
||||
"""Return the platform string for our execution environment.
|
||||
|
||||
The returned value should map to one of the SCons/Platform/\*.py
|
||||
files. Since scons is architecture independent, though, we don't
|
||||
care about the machine architecture.
|
||||
"""
|
||||
osname = os.name
|
||||
if osname == 'java':
|
||||
osname = os._osType
|
||||
if osname == 'posix':
|
||||
if sys.platform == 'cygwin':
|
||||
return 'cygwin'
|
||||
elif sys.platform.find('irix') != -1:
|
||||
return 'irix'
|
||||
elif sys.platform.find('sunos') != -1:
|
||||
return 'sunos'
|
||||
elif sys.platform.find('hp-ux') != -1:
|
||||
return 'hpux'
|
||||
elif sys.platform.find('aix') != -1:
|
||||
return 'aix'
|
||||
elif sys.platform.find('darwin') != -1:
|
||||
return 'darwin'
|
||||
else:
|
||||
return 'posix'
|
||||
elif os.name == 'os2':
|
||||
return 'os2'
|
||||
else:
|
||||
return sys.platform
|
||||
|
||||
|
||||
def platform_module(name = platform_default()):
|
||||
"""Return the imported module for the platform.
|
||||
|
||||
This looks for a module name that matches the specified argument.
|
||||
If the name is unspecified, we fetch the appropriate default for
|
||||
our execution environment.
|
||||
"""
|
||||
full_name = 'SCons.Platform.' + name
|
||||
if full_name not in sys.modules:
|
||||
if os.name == 'java':
|
||||
eval(full_name)
|
||||
else:
|
||||
try:
|
||||
# the specific platform module is a relative import
|
||||
mod = importlib.import_module("." + name, __name__)
|
||||
except ImportError:
|
||||
try:
|
||||
import zipimport
|
||||
importer = zipimport.zipimporter( sys.modules['SCons.Platform'].__path__[0] )
|
||||
mod = importer.load_module(full_name)
|
||||
except ImportError:
|
||||
raise SCons.Errors.UserError("No platform named '%s'" % name)
|
||||
setattr(SCons.Platform, name, mod)
|
||||
return sys.modules[full_name]
|
||||
|
||||
|
||||
def DefaultToolList(platform, env):
|
||||
"""Select a default tool list for the specified platform.
|
||||
"""
|
||||
return SCons.Tool.tool_list(platform, env)
|
||||
|
||||
|
||||
class PlatformSpec:
|
||||
def __init__(self, name, generate):
|
||||
self.name = name
|
||||
self.generate = generate
|
||||
|
||||
def __call__(self, *args, **kw):
|
||||
return self.generate(*args, **kw)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class TempFileMunge:
|
||||
"""Convert long command lines to use a temporary file.
|
||||
|
||||
You can set an Environment variable (usually `TEMPFILE`) to this,
|
||||
then call it with a string argument, and it will perform temporary
|
||||
file substitution on it. This is used to circumvent limitations on
|
||||
the length of command lines. Example::
|
||||
|
||||
env["TEMPFILE"] = TempFileMunge
|
||||
env["LINKCOM"] = "${TEMPFILE('$LINK $TARGET $SOURCES','$LINKCOMSTR')}"
|
||||
|
||||
By default, the name of the temporary file used begins with a
|
||||
prefix of '@'. This may be configured for other tool chains by
|
||||
setting the TEMPFILEPREFIX variable. Example::
|
||||
|
||||
env["TEMPFILEPREFIX"] = '-@' # diab compiler
|
||||
env["TEMPFILEPREFIX"] = '-via' # arm tool chain
|
||||
env["TEMPFILEPREFIX"] = '' # (the empty string) PC Lint
|
||||
|
||||
You can configure the extension of the temporary file through the
|
||||
TEMPFILESUFFIX variable, which defaults to '.lnk' (see comments
|
||||
in the code below). Example::
|
||||
|
||||
env["TEMPFILESUFFIX"] = '.lnt' # PC Lint
|
||||
|
||||
Entries in the temporary file are separated by the value of the
|
||||
TEMPFILEARGJOIN variable, which defaults to an OS-appropriate value.
|
||||
|
||||
"""
|
||||
def __init__(self, cmd, cmdstr = None):
|
||||
self.cmd = cmd
|
||||
self.cmdstr = cmdstr
|
||||
|
||||
def __call__(self, target, source, env, for_signature):
|
||||
if for_signature:
|
||||
# If we're being called for signature calculation, it's
|
||||
# because we're being called by the string expansion in
|
||||
# Subst.py, which has the logic to strip any $( $) that
|
||||
# may be in the command line we squirreled away. So we
|
||||
# just return the raw command line and let the upper
|
||||
# string substitution layers do their thing.
|
||||
return self.cmd
|
||||
|
||||
# Now we're actually being called because someone is actually
|
||||
# going to try to execute the command, so we have to do our
|
||||
# own expansion.
|
||||
cmd = env.subst_list(self.cmd, SCons.Subst.SUBST_CMD, target, source)[0]
|
||||
try:
|
||||
maxline = int(env.subst('$MAXLINELENGTH'))
|
||||
except ValueError:
|
||||
maxline = 2048
|
||||
|
||||
length = 0
|
||||
for c in cmd:
|
||||
length += len(c)
|
||||
length += len(cmd) - 1
|
||||
if length <= maxline:
|
||||
return self.cmd
|
||||
|
||||
# Check if we already created the temporary file for this target
|
||||
# It should have been previously done by Action.strfunction() call
|
||||
node = target[0] if SCons.Util.is_List(target) else target
|
||||
cmdlist = getattr(node.attributes, 'tempfile_cmdlist', None) \
|
||||
if node is not None else None
|
||||
if cmdlist is not None:
|
||||
return cmdlist
|
||||
|
||||
# Default to the .lnk suffix for the benefit of the Phar Lap
|
||||
# linkloc linker, which likes to append an .lnk suffix if
|
||||
# none is given.
|
||||
if 'TEMPFILESUFFIX' in env:
|
||||
suffix = env.subst('$TEMPFILESUFFIX')
|
||||
else:
|
||||
suffix = '.lnk'
|
||||
|
||||
if 'TEMPFILEDIR' in env:
|
||||
tempfile_dir = env.subst('$TEMPFILEDIR')
|
||||
os.makedirs(tempfile_dir, exist_ok=True)
|
||||
else:
|
||||
tempfile_dir = None
|
||||
|
||||
fd, tmp = tempfile.mkstemp(suffix, dir=tempfile_dir, text=True)
|
||||
native_tmp = SCons.Util.get_native_path(tmp)
|
||||
|
||||
if env.get('SHELL', None) == 'sh':
|
||||
# The sh shell will try to escape the backslashes in the
|
||||
# path, so unescape them.
|
||||
native_tmp = native_tmp.replace('\\', r'\\\\')
|
||||
# In Cygwin, we want to use rm to delete the temporary
|
||||
# file, because del does not exist in the sh shell.
|
||||
rm = env.Detect('rm') or 'del'
|
||||
else:
|
||||
# Don't use 'rm' if the shell is not sh, because rm won't
|
||||
# work with the Windows shells (cmd.exe or command.com) or
|
||||
# Windows path names.
|
||||
rm = 'del'
|
||||
|
||||
prefix = env.subst('$TEMPFILEPREFIX')
|
||||
if not prefix:
|
||||
prefix = '@'
|
||||
|
||||
args = list(map(SCons.Subst.quote_spaces, cmd[1:]))
|
||||
join_char = env.get('TEMPFILEARGJOIN',' ')
|
||||
os.write(fd, bytearray(join_char.join(args) + "\n",'utf-8'))
|
||||
os.close(fd)
|
||||
|
||||
# XXX Using the SCons.Action.print_actions value directly
|
||||
# like this is bogus, but expedient. This class should
|
||||
# really be rewritten as an Action that defines the
|
||||
# __call__() and strfunction() methods and lets the
|
||||
# normal action-execution logic handle whether or not to
|
||||
# print/execute the action. The problem, though, is all
|
||||
# of that is decided before we execute this method as
|
||||
# part of expanding the $TEMPFILE construction variable.
|
||||
# Consequently, refactoring this will have to wait until
|
||||
# we get more flexible with allowing Actions to exist
|
||||
# independently and get strung together arbitrarily like
|
||||
# Ant tasks. In the meantime, it's going to be more
|
||||
# user-friendly to not let obsession with architectural
|
||||
# purity get in the way of just being helpful, so we'll
|
||||
# reach into SCons.Action directly.
|
||||
if SCons.Action.print_actions:
|
||||
cmdstr = env.subst(self.cmdstr, SCons.Subst.SUBST_RAW, target,
|
||||
source) if self.cmdstr is not None else ''
|
||||
# Print our message only if XXXCOMSTR returns an empty string
|
||||
if len(cmdstr) == 0 :
|
||||
cmdstr = ("Using tempfile "+native_tmp+" for command line:\n"+
|
||||
str(cmd[0]) + " " + " ".join(args))
|
||||
self._print_cmd_str(target, source, env, cmdstr)
|
||||
|
||||
# Store the temporary file command list into the target Node.attributes
|
||||
# to avoid creating two temporary files one for print and one for execute.
|
||||
cmdlist = [ cmd[0], prefix + native_tmp + '\n' + rm, native_tmp ]
|
||||
if node is not None:
|
||||
try :
|
||||
setattr(node.attributes, 'tempfile_cmdlist', cmdlist)
|
||||
except AttributeError:
|
||||
pass
|
||||
return cmdlist
|
||||
|
||||
def _print_cmd_str(self, target, source, env, cmdstr):
|
||||
# check if the user has specified a cmd line print function
|
||||
print_func = None
|
||||
try:
|
||||
get = env.get
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
print_func = get('PRINT_CMD_LINE_FUNC')
|
||||
|
||||
# use the default action cmd line print if user did not supply one
|
||||
if not print_func:
|
||||
action = SCons.Action._ActionAction()
|
||||
action.print_cmd_line(cmdstr, target, source, env)
|
||||
else:
|
||||
print_func(cmdstr, target, source, env)
|
||||
|
||||
|
||||
def Platform(name = platform_default()):
|
||||
"""Select a canned Platform specification.
|
||||
"""
|
||||
module = platform_module(name)
|
||||
spec = PlatformSpec(name, module.generate)
|
||||
return spec
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
86
scons/scons-local-4.0.1/SCons/Platform/aix.py
Normal file
86
scons/scons-local-4.0.1/SCons/Platform/aix.py
Normal file
|
@ -0,0 +1,86 @@
|
|||
"""SCons.Platform.aix
|
||||
|
||||
Platform-specific initialization for IBM AIX systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from . import posix
|
||||
|
||||
import SCons.Util
|
||||
import SCons.Action
|
||||
|
||||
def get_xlc(env, xlc=None, packages=[]):
|
||||
# Use the AIX package installer tool lslpp to figure out where a
|
||||
# given xl* compiler is installed and what version it is.
|
||||
xlcPath = None
|
||||
xlcVersion = None
|
||||
|
||||
if xlc is None:
|
||||
xlc = env.get('CC', 'xlc')
|
||||
if SCons.Util.is_List(xlc):
|
||||
xlc = xlc[0]
|
||||
for package in packages:
|
||||
# find the installed filename, which may be a symlink as well
|
||||
pipe = SCons.Action._subproc(env, ['lslpp', '-fc', package],
|
||||
stdin = 'devnull',
|
||||
stderr = 'devnull',
|
||||
universal_newlines=True,
|
||||
stdout = subprocess.PIPE)
|
||||
# output of lslpp is something like this:
|
||||
# #Path:Fileset:File
|
||||
# /usr/lib/objrepos:vac.C 6.0.0.0:/usr/vac/exe/xlCcpp
|
||||
# /usr/lib/objrepos:vac.C 6.0.0.0:/usr/vac/bin/xlc_r -> /usr/vac/bin/xlc
|
||||
for line in pipe.stdout:
|
||||
if xlcPath:
|
||||
continue # read everything to let lslpp terminate
|
||||
fileset, filename = line.split(':')[1:3]
|
||||
filename = filename.split()[0]
|
||||
if ('/' in xlc and filename == xlc) \
|
||||
or ('/' not in xlc and filename.endswith('/' + xlc)):
|
||||
xlcVersion = fileset.split()[1]
|
||||
xlcPath, sep, xlc = filename.rpartition('/')
|
||||
pass
|
||||
pass
|
||||
return (xlcPath, xlc, xlcVersion)
|
||||
|
||||
def generate(env):
|
||||
posix.generate(env)
|
||||
#Based on AIX 5.2: ARG_MAX=24576 - 3000 for environment expansion
|
||||
env['MAXLINELENGTH'] = 21576
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
64
scons/scons-local-4.0.1/SCons/Platform/cygwin.py
Normal file
64
scons/scons-local-4.0.1/SCons/Platform/cygwin.py
Normal file
|
@ -0,0 +1,64 @@
|
|||
"""SCons.Platform.cygwin
|
||||
|
||||
Platform-specific initialization for Cygwin systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import sys
|
||||
|
||||
from . import posix
|
||||
from SCons.Platform import TempFileMunge
|
||||
|
||||
CYGWIN_DEFAULT_PATHS = []
|
||||
if sys.platform == 'win32':
|
||||
CYGWIN_DEFAULT_PATHS = [
|
||||
r'C:\cygwin64\bin',
|
||||
r'C:\cygwin\bin'
|
||||
]
|
||||
|
||||
def generate(env):
|
||||
posix.generate(env)
|
||||
|
||||
env['PROGPREFIX'] = ''
|
||||
env['PROGSUFFIX'] = '.exe'
|
||||
env['SHLIBPREFIX'] = ''
|
||||
env['SHLIBSUFFIX'] = '.dll'
|
||||
env['LIBPREFIXES'] = [ '$LIBPREFIX', '$SHLIBPREFIX', '$IMPLIBPREFIX' ]
|
||||
env['LIBSUFFIXES'] = [ '$LIBSUFFIX', '$SHLIBSUFFIX', '$IMPLIBSUFFIX' ]
|
||||
env['TEMPFILE'] = TempFileMunge
|
||||
env['TEMPFILEPREFIX'] = '@'
|
||||
env['MAXLINELENGTH'] = 2048
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
73
scons/scons-local-4.0.1/SCons/Platform/darwin.py
Normal file
73
scons/scons-local-4.0.1/SCons/Platform/darwin.py
Normal file
|
@ -0,0 +1,73 @@
|
|||
"""SCons.Platform.darwin
|
||||
|
||||
Platform-specific initialization for Mac OS X systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
from . import posix
|
||||
import os
|
||||
|
||||
def generate(env):
|
||||
posix.generate(env)
|
||||
env['SHLIBSUFFIX'] = '.dylib'
|
||||
# put macports paths at front to override Apple's versions, fink path is after
|
||||
# For now let people who want Macports or Fink tools specify it!
|
||||
# env['ENV']['PATH'] = '/opt/local/bin:/opt/local/sbin:' + env['ENV']['PATH'] + ':/sw/bin'
|
||||
|
||||
# Store extra system paths in env['ENV']['PATHOSX']
|
||||
|
||||
filelist = ['/etc/paths',]
|
||||
# make sure this works on Macs with Tiger or earlier
|
||||
try:
|
||||
dirlist = os.listdir('/etc/paths.d')
|
||||
except:
|
||||
dirlist = []
|
||||
|
||||
for file in dirlist:
|
||||
filelist.append('/etc/paths.d/'+file)
|
||||
|
||||
for file in filelist:
|
||||
if os.path.isfile(file):
|
||||
with open(file, 'r') as f:
|
||||
lines = f.readlines()
|
||||
for line in lines:
|
||||
if line:
|
||||
env.AppendENVPath('PATHOSX', line.strip('\n'))
|
||||
|
||||
# Not sure why this wasn't the case all along?
|
||||
if env['ENV'].get('PATHOSX', False) and os.environ.get('SCONS_USE_MAC_PATHS', False):
|
||||
env.AppendENVPath('PATH',env['ENV']['PATHOSX'])
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
46
scons/scons-local-4.0.1/SCons/Platform/hpux.py
Normal file
46
scons/scons-local-4.0.1/SCons/Platform/hpux.py
Normal file
|
@ -0,0 +1,46 @@
|
|||
"""SCons.Platform.hpux
|
||||
|
||||
Platform-specific initialization for HP-UX systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
from . import posix
|
||||
|
||||
def generate(env):
|
||||
posix.generate(env)
|
||||
#Based on HP-UX11i: ARG_MAX=2048000 - 3000 for environment expansion
|
||||
env['MAXLINELENGTH'] = 2045000
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
44
scons/scons-local-4.0.1/SCons/Platform/irix.py
Normal file
44
scons/scons-local-4.0.1/SCons/Platform/irix.py
Normal file
|
@ -0,0 +1,44 @@
|
|||
"""SCons.Platform.irix
|
||||
|
||||
Platform-specific initialization for SGI IRIX systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
from . import posix
|
||||
|
||||
def generate(env):
|
||||
posix.generate(env)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
39
scons/scons-local-4.0.1/SCons/Platform/mingw.py
Normal file
39
scons/scons-local-4.0.1/SCons/Platform/mingw.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
"""SCons.Platform.mingw
|
||||
|
||||
Platform-specific initialization for the MinGW system.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import sys
|
||||
|
||||
MINGW_DEFAULT_PATHS = []
|
||||
if sys.platform == 'win32':
|
||||
MINGW_DEFAULT_PATHS = [
|
||||
r'C:\msys64',
|
||||
r'C:\msys'
|
||||
]
|
58
scons/scons-local-4.0.1/SCons/Platform/os2.py
Normal file
58
scons/scons-local-4.0.1/SCons/Platform/os2.py
Normal file
|
@ -0,0 +1,58 @@
|
|||
"""SCons.Platform.os2
|
||||
|
||||
Platform-specific initialization for OS/2 systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
from . import win32
|
||||
|
||||
def generate(env):
|
||||
if 'ENV' not in env:
|
||||
env['ENV'] = {}
|
||||
env['OBJPREFIX'] = ''
|
||||
env['OBJSUFFIX'] = '.obj'
|
||||
env['SHOBJPREFIX'] = '$OBJPREFIX'
|
||||
env['SHOBJSUFFIX'] = '$OBJSUFFIX'
|
||||
env['PROGPREFIX'] = ''
|
||||
env['PROGSUFFIX'] = '.exe'
|
||||
env['LIBPREFIX'] = ''
|
||||
env['LIBSUFFIX'] = '.lib'
|
||||
env['SHLIBPREFIX'] = ''
|
||||
env['SHLIBSUFFIX'] = '.dll'
|
||||
env['LIBPREFIXES'] = '$LIBPREFIX'
|
||||
env['LIBSUFFIXES'] = [ '$LIBSUFFIX', '$SHLIBSUFFIX' ]
|
||||
env['HOST_OS'] = 'os2'
|
||||
env['HOST_ARCH'] = win32.get_architecture().arch
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
131
scons/scons-local-4.0.1/SCons/Platform/posix.py
Normal file
131
scons/scons-local-4.0.1/SCons/Platform/posix.py
Normal file
|
@ -0,0 +1,131 @@
|
|||
"""SCons.Platform.posix
|
||||
|
||||
Platform-specific initialization for POSIX (Linux, UNIX, etc.) systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import errno
|
||||
import os
|
||||
import os.path
|
||||
import subprocess
|
||||
import sys
|
||||
import select
|
||||
|
||||
import SCons.Util
|
||||
from SCons.Platform import TempFileMunge
|
||||
from SCons.Platform.virtualenv import ImportVirtualenv
|
||||
from SCons.Platform.virtualenv import ignore_virtualenv, enable_virtualenv
|
||||
|
||||
exitvalmap = {
|
||||
2 : 127,
|
||||
13 : 126,
|
||||
}
|
||||
|
||||
def escape(arg):
|
||||
"""escape shell special characters"""
|
||||
slash = '\\'
|
||||
special = '"$'
|
||||
|
||||
arg = arg.replace(slash, slash+slash)
|
||||
for c in special:
|
||||
arg = arg.replace(c, slash+c)
|
||||
|
||||
# print("ESCAPE RESULT: %s" % arg)
|
||||
return '"' + arg + '"'
|
||||
|
||||
|
||||
def exec_subprocess(l, env):
|
||||
proc = subprocess.Popen(l, env = env, close_fds = True)
|
||||
return proc.wait()
|
||||
|
||||
def subprocess_spawn(sh, escape, cmd, args, env):
|
||||
return exec_subprocess([sh, '-c', ' '.join(args)], env)
|
||||
|
||||
def exec_popen3(l, env, stdout, stderr):
|
||||
proc = subprocess.Popen(l, env = env, close_fds = True,
|
||||
stdout = stdout,
|
||||
stderr = stderr)
|
||||
return proc.wait()
|
||||
|
||||
def piped_env_spawn(sh, escape, cmd, args, env, stdout, stderr):
|
||||
# spawn using Popen3 combined with the env command
|
||||
# the command name and the command's stdout is written to stdout
|
||||
# the command's stderr is written to stderr
|
||||
return exec_popen3([sh, '-c', ' '.join(args)],
|
||||
env, stdout, stderr)
|
||||
|
||||
|
||||
def generate(env):
|
||||
# Bearing in mind we have python 2.4 as a baseline, we can just do this:
|
||||
spawn = subprocess_spawn
|
||||
pspawn = piped_env_spawn
|
||||
# Note that this means that 'escape' is no longer used
|
||||
|
||||
if 'ENV' not in env:
|
||||
env['ENV'] = {}
|
||||
env['ENV']['PATH'] = '/usr/local/bin:/opt/bin:/bin:/usr/bin'
|
||||
env['OBJPREFIX'] = ''
|
||||
env['OBJSUFFIX'] = '.o'
|
||||
env['SHOBJPREFIX'] = '$OBJPREFIX'
|
||||
env['SHOBJSUFFIX'] = '$OBJSUFFIX'
|
||||
env['PROGPREFIX'] = ''
|
||||
env['PROGSUFFIX'] = ''
|
||||
env['LIBPREFIX'] = 'lib'
|
||||
env['LIBSUFFIX'] = '.a'
|
||||
env['SHLIBPREFIX'] = '$LIBPREFIX'
|
||||
env['SHLIBSUFFIX'] = '.so'
|
||||
env['LIBPREFIXES'] = [ '$LIBPREFIX' ]
|
||||
env['LIBSUFFIXES'] = [ '$LIBSUFFIX', '$SHLIBSUFFIX' ]
|
||||
env['PSPAWN'] = pspawn
|
||||
env['SPAWN'] = spawn
|
||||
env['SHELL'] = 'sh'
|
||||
env['ESCAPE'] = escape
|
||||
env['TEMPFILE'] = TempFileMunge
|
||||
env['TEMPFILEPREFIX'] = '@'
|
||||
#Based on LINUX: ARG_MAX=ARG_MAX=131072 - 3000 for environment expansion
|
||||
#Note: specific platforms might rise or lower this value
|
||||
env['MAXLINELENGTH'] = 128072
|
||||
|
||||
# This platform supports RPATH specifications.
|
||||
env['__RPATH'] = '$_RPATH'
|
||||
|
||||
# GDC is GCC family, but DMD and LDC have different options.
|
||||
# Must be able to have GCC and DMD work in the same build, so:
|
||||
env['__DRPATH'] = '$_DRPATH'
|
||||
|
||||
if enable_virtualenv and not ignore_virtualenv:
|
||||
ImportVirtualenv(env)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
50
scons/scons-local-4.0.1/SCons/Platform/sunos.py
Normal file
50
scons/scons-local-4.0.1/SCons/Platform/sunos.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
"""SCons.Platform.sunos
|
||||
|
||||
Platform-specific initialization for Sun systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
from . import posix
|
||||
|
||||
def generate(env):
|
||||
posix.generate(env)
|
||||
# Based on sunSparc 8:32bit
|
||||
# ARG_MAX=1048320 - 3000 for environment expansion
|
||||
env['MAXLINELENGTH'] = 1045320
|
||||
env['PKGINFO'] = 'pkginfo'
|
||||
env['PKGCHK'] = '/usr/sbin/pkgchk'
|
||||
env['ENV']['PATH'] = env['ENV']['PATH'] + ':/opt/SUNWspro/bin:/usr/ccs/bin'
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
120
scons/scons-local-4.0.1/SCons/Platform/virtualenv.py
Normal file
120
scons/scons-local-4.0.1/SCons/Platform/virtualenv.py
Normal file
|
@ -0,0 +1,120 @@
|
|||
"""SCons.Platform.virtualenv
|
||||
|
||||
Support for virtualenv.
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import os
|
||||
import sys
|
||||
import SCons.Util
|
||||
|
||||
|
||||
virtualenv_enabled_by_default = False
|
||||
|
||||
|
||||
def _enable_virtualenv_default():
|
||||
return SCons.Util.get_os_env_bool('SCONS_ENABLE_VIRTUALENV', virtualenv_enabled_by_default)
|
||||
|
||||
|
||||
def _ignore_virtualenv_default():
|
||||
return SCons.Util.get_os_env_bool('SCONS_IGNORE_VIRTUALENV', False)
|
||||
|
||||
|
||||
enable_virtualenv = _enable_virtualenv_default()
|
||||
ignore_virtualenv = _ignore_virtualenv_default()
|
||||
virtualenv_variables = ['VIRTUAL_ENV', 'PIPENV_ACTIVE']
|
||||
|
||||
|
||||
def _running_in_virtualenv():
|
||||
"""Returns True, if scons is executed within a virtualenv"""
|
||||
# see https://stackoverflow.com/a/42580137
|
||||
return (hasattr(sys, 'real_prefix') or
|
||||
(hasattr(sys, 'base_prefix') and sys.base_prefix != sys.prefix))
|
||||
|
||||
|
||||
def _is_path_in(path, base):
|
||||
"""Returns true, if **path** is located under the **base** directory."""
|
||||
if not path or not base: # empty path may happen, base too
|
||||
return False
|
||||
rp = os.path.relpath(path, base)
|
||||
return (not rp.startswith(os.path.pardir)) and (not rp == os.path.curdir)
|
||||
|
||||
|
||||
def _inject_venv_variables(env):
|
||||
if 'ENV' not in env:
|
||||
env['ENV'] = {}
|
||||
ENV = env['ENV']
|
||||
for name in virtualenv_variables:
|
||||
try:
|
||||
ENV[name] = os.environ[name]
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
def _inject_venv_path(env, path_list=None):
|
||||
"""Modify environment such that SCons will take into account its virtualenv
|
||||
when running external tools."""
|
||||
if path_list is None:
|
||||
path_list = os.getenv('PATH')
|
||||
env.PrependENVPath('PATH', select_paths_in_venv(path_list))
|
||||
|
||||
|
||||
def select_paths_in_venv(path_list):
|
||||
"""Returns a list of paths from **path_list** which are under virtualenv's
|
||||
home directory."""
|
||||
if SCons.Util.is_String(path_list):
|
||||
path_list = path_list.split(os.path.pathsep)
|
||||
# Find in path_list the paths under the virtualenv's home
|
||||
return [path for path in path_list if IsInVirtualenv(path)]
|
||||
|
||||
|
||||
def ImportVirtualenv(env):
|
||||
"""Copies virtualenv-related environment variables from OS environment
|
||||
to ``env['ENV']`` and prepends virtualenv's PATH to ``env['ENV']['PATH']``.
|
||||
"""
|
||||
_inject_venv_variables(env)
|
||||
_inject_venv_path(env)
|
||||
|
||||
|
||||
def Virtualenv():
|
||||
"""Returns path to the virtualenv home if scons is executing within a
|
||||
virtualenv or None, if not."""
|
||||
if _running_in_virtualenv():
|
||||
return sys.prefix
|
||||
return None
|
||||
|
||||
|
||||
def IsInVirtualenv(path):
|
||||
"""Returns True, if **path** is under virtualenv's home directory. If not,
|
||||
or if we don't use virtualenv, returns False."""
|
||||
return _is_path_in(path, Virtualenv())
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
449
scons/scons-local-4.0.1/SCons/Platform/win32.py
Normal file
449
scons/scons-local-4.0.1/SCons/Platform/win32.py
Normal file
|
@ -0,0 +1,449 @@
|
|||
"""SCons.Platform.win32
|
||||
|
||||
Platform-specific initialization for Win32 systems.
|
||||
|
||||
There normally shouldn't be any need to import this module directly. It
|
||||
will usually be imported through the generic SCons.Platform.Platform()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
from SCons.Platform.posix import exitvalmap
|
||||
from SCons.Platform import TempFileMunge
|
||||
from SCons.Platform.virtualenv import ImportVirtualenv
|
||||
from SCons.Platform.virtualenv import ignore_virtualenv, enable_virtualenv
|
||||
import SCons.Util
|
||||
|
||||
CHOCO_DEFAULT_PATH = [
|
||||
r'C:\ProgramData\chocolatey\bin'
|
||||
]
|
||||
|
||||
try:
|
||||
import msvcrt
|
||||
import win32api
|
||||
import win32con
|
||||
except ImportError:
|
||||
parallel_msg = \
|
||||
"you do not seem to have the pywin32 extensions installed;\n" + \
|
||||
"\tparallel (-j) builds may not work reliably with open Python files."
|
||||
except AttributeError:
|
||||
parallel_msg = \
|
||||
"your pywin32 extensions do not support file handle operations;\n" + \
|
||||
"\tparallel (-j) builds may not work reliably with open Python files."
|
||||
else:
|
||||
parallel_msg = None
|
||||
|
||||
|
||||
if False:
|
||||
# Now swap out shutil.filecopy and filecopy2 for win32 api native CopyFile
|
||||
try:
|
||||
from ctypes import windll
|
||||
import shutil
|
||||
|
||||
CopyFile = windll.kernel32.CopyFileA
|
||||
SetFileTime = windll.kernel32.SetFileTime
|
||||
|
||||
_shutil_copy = shutil.copy
|
||||
_shutil_copy2 = shutil.copy2
|
||||
|
||||
shutil.copy2 = CopyFile
|
||||
|
||||
def win_api_copyfile(src,dst):
|
||||
CopyFile(src,dst)
|
||||
os.utime(dst)
|
||||
|
||||
shutil.copy = win_api_copyfile
|
||||
|
||||
except AttributeError:
|
||||
parallel_msg = \
|
||||
"Couldn't override shutil.copy or shutil.copy2 falling back to shutil defaults"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
try:
|
||||
import threading
|
||||
spawn_lock = threading.Lock()
|
||||
|
||||
# This locked version of spawnve works around a Windows
|
||||
# MSVCRT bug, because its spawnve is not thread-safe.
|
||||
# Without this, python can randomly crash while using -jN.
|
||||
# See the python bug at http://bugs.python.org/issue6476
|
||||
# and SCons issue at
|
||||
# https://github.com/SCons/scons/issues/2449
|
||||
def spawnve(mode, file, args, env):
|
||||
spawn_lock.acquire()
|
||||
try:
|
||||
if mode == os.P_WAIT:
|
||||
ret = os.spawnve(os.P_NOWAIT, file, args, env)
|
||||
else:
|
||||
ret = os.spawnve(mode, file, args, env)
|
||||
finally:
|
||||
spawn_lock.release()
|
||||
if mode == os.P_WAIT:
|
||||
pid, status = os.waitpid(ret, 0)
|
||||
ret = status >> 8
|
||||
return ret
|
||||
except ImportError:
|
||||
# Use the unsafe method of spawnve.
|
||||
# Please, don't try to optimize this try-except block
|
||||
# away by assuming that the threading module is always present.
|
||||
# In the test test/option-j.py we intentionally call SCons with
|
||||
# a fake threading.py that raises an import exception right away,
|
||||
# simulating a non-existent package.
|
||||
def spawnve(mode, file, args, env):
|
||||
return os.spawnve(mode, file, args, env)
|
||||
|
||||
# The upshot of all this is that, if you are using Python 1.5.2,
|
||||
# you had better have cmd or command.com in your PATH when you run
|
||||
# scons.
|
||||
|
||||
|
||||
def piped_spawn(sh, escape, cmd, args, env, stdout, stderr):
|
||||
# There is no direct way to do that in python. What we do
|
||||
# here should work for most cases:
|
||||
# In case stdout (stderr) is not redirected to a file,
|
||||
# we redirect it into a temporary file tmpFileStdout
|
||||
# (tmpFileStderr) and copy the contents of this file
|
||||
# to stdout (stderr) given in the argument
|
||||
# Note that because this will paste shell redirection syntax
|
||||
# into the cmdline, we have to call a shell to run the command,
|
||||
# even though that's a bit of a performance hit.
|
||||
if not sh:
|
||||
sys.stderr.write("scons: Could not find command interpreter, is it in your PATH?\n")
|
||||
return 127
|
||||
|
||||
# one temporary file for stdout and stderr
|
||||
tmpFileStdout, tmpFileStdoutName = tempfile.mkstemp(text=True)
|
||||
os.close(tmpFileStdout) # don't need open until the subproc is done
|
||||
tmpFileStderr, tmpFileStderrName = tempfile.mkstemp(text=True)
|
||||
os.close(tmpFileStderr)
|
||||
|
||||
# check if output is redirected
|
||||
stdoutRedirected = False
|
||||
stderrRedirected = False
|
||||
for arg in args:
|
||||
# are there more possibilities to redirect stdout ?
|
||||
if arg.find(">", 0, 1) != -1 or arg.find("1>", 0, 2) != -1:
|
||||
stdoutRedirected = True
|
||||
# are there more possibilities to redirect stderr ?
|
||||
if arg.find("2>", 0, 2) != -1:
|
||||
stderrRedirected = True
|
||||
|
||||
# redirect output of non-redirected streams to our tempfiles
|
||||
if not stdoutRedirected:
|
||||
args.append(">" + tmpFileStdoutName)
|
||||
if not stderrRedirected:
|
||||
args.append("2>" + tmpFileStderrName)
|
||||
|
||||
# actually do the spawn
|
||||
try:
|
||||
args = [sh, '/C', escape(' '.join(args))]
|
||||
ret = spawnve(os.P_WAIT, sh, args, env)
|
||||
except OSError as e:
|
||||
# catch any error
|
||||
try:
|
||||
ret = exitvalmap[e.errno]
|
||||
except KeyError:
|
||||
sys.stderr.write("scons: unknown OSError exception code %d - %s: %s\n" % (e.errno, cmd, e.strerror))
|
||||
if stderr is not None:
|
||||
stderr.write("scons: %s: %s\n" % (cmd, e.strerror))
|
||||
|
||||
# copy child output from tempfiles to our streams
|
||||
# and do clean up stuff
|
||||
if stdout is not None and not stdoutRedirected:
|
||||
try:
|
||||
with open(tmpFileStdoutName, "r") as tmpFileStdout:
|
||||
stdout.write(tmpFileStdout.read())
|
||||
os.remove(tmpFileStdoutName)
|
||||
except (IOError, OSError):
|
||||
pass
|
||||
|
||||
if stderr is not None and not stderrRedirected:
|
||||
try:
|
||||
with open(tmpFileStderrName, "r") as tmpFileStderr:
|
||||
stderr.write(tmpFileStderr.read())
|
||||
os.remove(tmpFileStderrName)
|
||||
except (IOError, OSError):
|
||||
pass
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def exec_spawn(l, env):
|
||||
try:
|
||||
result = spawnve(os.P_WAIT, l[0], l, env)
|
||||
except (OSError, EnvironmentError) as e:
|
||||
try:
|
||||
result = exitvalmap[e.errno]
|
||||
sys.stderr.write("scons: %s: %s\n" % (l[0], e.strerror))
|
||||
except KeyError:
|
||||
result = 127
|
||||
if len(l) > 2:
|
||||
if len(l[2]) < 1000:
|
||||
command = ' '.join(l[0:3])
|
||||
else:
|
||||
command = l[0]
|
||||
else:
|
||||
command = l[0]
|
||||
sys.stderr.write("scons: unknown OSError exception code %d - '%s': %s\n" % (e.errno, command, e.strerror))
|
||||
return result
|
||||
|
||||
|
||||
def spawn(sh, escape, cmd, args, env):
|
||||
if not sh:
|
||||
sys.stderr.write("scons: Could not find command interpreter, is it in your PATH?\n")
|
||||
return 127
|
||||
return exec_spawn([sh, '/C', escape(' '.join(args))], env)
|
||||
|
||||
# Windows does not allow special characters in file names anyway, so no
|
||||
# need for a complex escape function, we will just quote the arg, except
|
||||
# that "cmd /c" requires that if an argument ends with a backslash it
|
||||
# needs to be escaped so as not to interfere with closing double quote
|
||||
# that we add.
|
||||
def escape(x):
|
||||
if x[-1] == '\\':
|
||||
x = x + '\\'
|
||||
return '"' + x + '"'
|
||||
|
||||
# Get the windows system directory name
|
||||
_system_root = None
|
||||
|
||||
|
||||
def get_system_root():
|
||||
global _system_root
|
||||
if _system_root is not None:
|
||||
return _system_root
|
||||
|
||||
# A resonable default if we can't read the registry
|
||||
val = os.environ.get('SystemRoot', "C:\\WINDOWS")
|
||||
|
||||
if SCons.Util.can_read_reg:
|
||||
try:
|
||||
# Look for Windows NT system root
|
||||
k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
|
||||
'Software\\Microsoft\\Windows NT\\CurrentVersion')
|
||||
val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot')
|
||||
except SCons.Util.RegError:
|
||||
try:
|
||||
# Okay, try the Windows 9x system root
|
||||
k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
|
||||
'Software\\Microsoft\\Windows\\CurrentVersion')
|
||||
val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot')
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except:
|
||||
pass
|
||||
|
||||
_system_root = val
|
||||
return val
|
||||
|
||||
|
||||
def get_program_files_dir():
|
||||
"""
|
||||
Get the location of the program files directory
|
||||
Returns
|
||||
-------
|
||||
|
||||
"""
|
||||
# Now see if we can look in the registry...
|
||||
val = ''
|
||||
if SCons.Util.can_read_reg:
|
||||
try:
|
||||
# Look for Windows Program Files directory
|
||||
k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
|
||||
'Software\\Microsoft\\Windows\\CurrentVersion')
|
||||
val, tok = SCons.Util.RegQueryValueEx(k, 'ProgramFilesDir')
|
||||
except SCons.Util.RegError:
|
||||
val = ''
|
||||
pass
|
||||
|
||||
if val == '':
|
||||
# A reasonable default if we can't read the registry
|
||||
# (Actually, it's pretty reasonable even if we can :-)
|
||||
val = os.path.join(os.path.dirname(get_system_root()),"Program Files")
|
||||
|
||||
return val
|
||||
|
||||
|
||||
class ArchDefinition:
|
||||
"""
|
||||
Determine which windows CPU were running on.
|
||||
A class for defining architecture-specific settings and logic.
|
||||
"""
|
||||
def __init__(self, arch, synonyms=[]):
|
||||
self.arch = arch
|
||||
self.synonyms = synonyms
|
||||
|
||||
SupportedArchitectureList = [
|
||||
ArchDefinition(
|
||||
'x86',
|
||||
['i386', 'i486', 'i586', 'i686'],
|
||||
),
|
||||
|
||||
ArchDefinition(
|
||||
'x86_64',
|
||||
['AMD64', 'amd64', 'em64t', 'EM64T', 'x86_64'],
|
||||
),
|
||||
|
||||
ArchDefinition(
|
||||
'ia64',
|
||||
['IA64'],
|
||||
),
|
||||
]
|
||||
|
||||
SupportedArchitectureMap = {}
|
||||
for a in SupportedArchitectureList:
|
||||
SupportedArchitectureMap[a.arch] = a
|
||||
for s in a.synonyms:
|
||||
SupportedArchitectureMap[s] = a
|
||||
|
||||
|
||||
def get_architecture(arch=None):
|
||||
"""Returns the definition for the specified architecture string.
|
||||
|
||||
If no string is specified, the system default is returned (as defined
|
||||
by the PROCESSOR_ARCHITEW6432 or PROCESSOR_ARCHITECTURE environment
|
||||
variables).
|
||||
"""
|
||||
if arch is None:
|
||||
arch = os.environ.get('PROCESSOR_ARCHITEW6432')
|
||||
if not arch:
|
||||
arch = os.environ.get('PROCESSOR_ARCHITECTURE')
|
||||
return SupportedArchitectureMap.get(arch, ArchDefinition('', ['']))
|
||||
|
||||
|
||||
def generate(env):
|
||||
# Attempt to find cmd.exe (for WinNT/2k/XP) or
|
||||
# command.com for Win9x
|
||||
cmd_interp = ''
|
||||
# First see if we can look in the registry...
|
||||
if SCons.Util.can_read_reg:
|
||||
try:
|
||||
# Look for Windows NT system root
|
||||
k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
|
||||
'Software\\Microsoft\\Windows NT\\CurrentVersion')
|
||||
val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot')
|
||||
cmd_interp = os.path.join(val, 'System32\\cmd.exe')
|
||||
except SCons.Util.RegError:
|
||||
try:
|
||||
# Okay, try the Windows 9x system root
|
||||
k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
|
||||
'Software\\Microsoft\\Windows\\CurrentVersion')
|
||||
val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot')
|
||||
cmd_interp = os.path.join(val, 'command.com')
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except:
|
||||
pass
|
||||
|
||||
# For the special case of not having access to the registry, we
|
||||
# use a temporary path and pathext to attempt to find the command
|
||||
# interpreter. If we fail, we try to find the interpreter through
|
||||
# the env's PATH. The problem with that is that it might not
|
||||
# contain an ENV and a PATH.
|
||||
if not cmd_interp:
|
||||
systemroot = get_system_root()
|
||||
tmp_path = systemroot + os.pathsep + \
|
||||
os.path.join(systemroot,'System32')
|
||||
tmp_pathext = '.com;.exe;.bat;.cmd'
|
||||
if 'PATHEXT' in os.environ:
|
||||
tmp_pathext = os.environ['PATHEXT']
|
||||
cmd_interp = SCons.Util.WhereIs('cmd', tmp_path, tmp_pathext)
|
||||
if not cmd_interp:
|
||||
cmd_interp = SCons.Util.WhereIs('command', tmp_path, tmp_pathext)
|
||||
|
||||
if not cmd_interp:
|
||||
cmd_interp = env.Detect('cmd')
|
||||
if not cmd_interp:
|
||||
cmd_interp = env.Detect('command')
|
||||
|
||||
if 'ENV' not in env:
|
||||
env['ENV'] = {}
|
||||
|
||||
# Import things from the external environment to the construction
|
||||
# environment's ENV. This is a potential slippery slope, because we
|
||||
# *don't* want to make builds dependent on the user's environment by
|
||||
# default. We're doing this for SystemRoot, though, because it's
|
||||
# needed for anything that uses sockets, and seldom changes, and
|
||||
# for SystemDrive because it's related.
|
||||
#
|
||||
# Weigh the impact carefully before adding other variables to this list.
|
||||
import_env = ['SystemDrive', 'SystemRoot', 'TEMP', 'TMP' ]
|
||||
for var in import_env:
|
||||
v = os.environ.get(var)
|
||||
if v:
|
||||
env['ENV'][var] = v
|
||||
|
||||
if 'COMSPEC' not in env['ENV']:
|
||||
v = os.environ.get("COMSPEC")
|
||||
if v:
|
||||
env['ENV']['COMSPEC'] = v
|
||||
|
||||
env.AppendENVPath('PATH', get_system_root() + '\\System32')
|
||||
|
||||
env['ENV']['PATHEXT'] = '.COM;.EXE;.BAT;.CMD'
|
||||
env['OBJPREFIX'] = ''
|
||||
env['OBJSUFFIX'] = '.obj'
|
||||
env['SHOBJPREFIX'] = '$OBJPREFIX'
|
||||
env['SHOBJSUFFIX'] = '$OBJSUFFIX'
|
||||
env['PROGPREFIX'] = ''
|
||||
env['PROGSUFFIX'] = '.exe'
|
||||
env['LIBPREFIX'] = ''
|
||||
env['LIBSUFFIX'] = '.lib'
|
||||
env['SHLIBPREFIX'] = ''
|
||||
env['SHLIBSUFFIX'] = '.dll'
|
||||
env['LIBPREFIXES'] = [ '$LIBPREFIX' ]
|
||||
env['LIBSUFFIXES'] = [ '$LIBSUFFIX' ]
|
||||
env['PSPAWN'] = piped_spawn
|
||||
env['SPAWN'] = spawn
|
||||
env['SHELL'] = cmd_interp
|
||||
env['TEMPFILE'] = TempFileMunge
|
||||
env['TEMPFILEPREFIX'] = '@'
|
||||
env['MAXLINELENGTH'] = 2048
|
||||
env['ESCAPE'] = escape
|
||||
|
||||
env['HOST_OS'] = 'win32'
|
||||
env['HOST_ARCH'] = get_architecture().arch
|
||||
|
||||
if enable_virtualenv and not ignore_virtualenv:
|
||||
ImportVirtualenv(env)
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
1112
scons/scons-local-4.0.1/SCons/SConf.py
Normal file
1112
scons/scons-local-4.0.1/SCons/SConf.py
Normal file
File diff suppressed because it is too large
Load diff
430
scons/scons-local-4.0.1/SCons/SConsign.py
Normal file
430
scons/scons-local-4.0.1/SCons/SConsign.py
Normal file
|
@ -0,0 +1,430 @@
|
|||
"""SCons.SConsign
|
||||
|
||||
Writing and reading information to the .sconsign file or files.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import SCons.compat
|
||||
|
||||
import os
|
||||
import pickle
|
||||
|
||||
import SCons.dblite
|
||||
import SCons.Warnings
|
||||
|
||||
from SCons.compat import PICKLE_PROTOCOL
|
||||
|
||||
|
||||
def corrupt_dblite_warning(filename):
|
||||
SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
|
||||
"Ignoring corrupt .sconsign file: %s"%filename)
|
||||
|
||||
SCons.dblite.ignore_corrupt_dbfiles = 1
|
||||
SCons.dblite.corruption_warning = corrupt_dblite_warning
|
||||
|
||||
# XXX Get rid of the global array so this becomes re-entrant.
|
||||
sig_files = []
|
||||
|
||||
# Info for the database SConsign implementation (now the default):
|
||||
# "DataBase" is a dictionary that maps top-level SConstruct directories
|
||||
# to open database handles.
|
||||
# "DB_Module" is the Python database module to create the handles.
|
||||
# "DB_Name" is the base name of the database file (minus any
|
||||
# extension the underlying DB module will add).
|
||||
DataBase = {}
|
||||
DB_Module = SCons.dblite
|
||||
DB_Name = ".sconsign"
|
||||
DB_sync_list = []
|
||||
|
||||
|
||||
def Get_DataBase(dir):
|
||||
global DataBase, DB_Module, DB_Name
|
||||
top = dir.fs.Top
|
||||
if not os.path.isabs(DB_Name) and top.repositories:
|
||||
mode = "c"
|
||||
for d in [top] + top.repositories:
|
||||
if dir.is_under(d):
|
||||
try:
|
||||
return DataBase[d], mode
|
||||
except KeyError:
|
||||
path = d.entry_abspath(DB_Name)
|
||||
try: db = DataBase[d] = DB_Module.open(path, mode)
|
||||
except (IOError, OSError):
|
||||
pass
|
||||
else:
|
||||
if mode != "r":
|
||||
DB_sync_list.append(db)
|
||||
return db, mode
|
||||
mode = "r"
|
||||
try:
|
||||
return DataBase[top], "c"
|
||||
except KeyError:
|
||||
db = DataBase[top] = DB_Module.open(DB_Name, "c")
|
||||
DB_sync_list.append(db)
|
||||
return db, "c"
|
||||
except TypeError:
|
||||
print("DataBase =", DataBase)
|
||||
raise
|
||||
|
||||
|
||||
def Reset():
|
||||
"""Reset global state. Used by unit tests that end up using
|
||||
SConsign multiple times to get a clean slate for each test."""
|
||||
global sig_files, DB_sync_list
|
||||
sig_files = []
|
||||
DB_sync_list = []
|
||||
|
||||
normcase = os.path.normcase
|
||||
|
||||
|
||||
def write():
|
||||
global sig_files
|
||||
for sig_file in sig_files:
|
||||
sig_file.write(sync=0)
|
||||
for db in DB_sync_list:
|
||||
try:
|
||||
syncmethod = db.sync
|
||||
except AttributeError:
|
||||
pass # Not all dbm modules have sync() methods.
|
||||
else:
|
||||
syncmethod()
|
||||
try:
|
||||
closemethod = db.close
|
||||
except AttributeError:
|
||||
pass # Not all dbm modules have close() methods.
|
||||
else:
|
||||
closemethod()
|
||||
|
||||
|
||||
class SConsignEntry:
|
||||
"""
|
||||
Wrapper class for the generic entry in a .sconsign file.
|
||||
The Node subclass populates it with attributes as it pleases.
|
||||
|
||||
XXX As coded below, we do expect a '.binfo' attribute to be added,
|
||||
but we'll probably generalize this in the next refactorings.
|
||||
"""
|
||||
__slots__ = ("binfo", "ninfo", "__weakref__")
|
||||
current_version_id = 2
|
||||
|
||||
def __init__(self):
|
||||
# Create an object attribute from the class attribute so it ends up
|
||||
# in the pickled data in the .sconsign file.
|
||||
#_version_id = self.current_version_id
|
||||
pass
|
||||
|
||||
def convert_to_sconsign(self):
|
||||
self.binfo.convert_to_sconsign()
|
||||
|
||||
def convert_from_sconsign(self, dir, name):
|
||||
self.binfo.convert_from_sconsign(dir, name)
|
||||
|
||||
def __getstate__(self):
|
||||
state = getattr(self, '__dict__', {}).copy()
|
||||
for obj in type(self).mro():
|
||||
for name in getattr(obj,'__slots__',()):
|
||||
if hasattr(self, name):
|
||||
state[name] = getattr(self, name)
|
||||
|
||||
state['_version_id'] = self.current_version_id
|
||||
try:
|
||||
del state['__weakref__']
|
||||
except KeyError:
|
||||
pass
|
||||
return state
|
||||
|
||||
def __setstate__(self, state):
|
||||
for key, value in state.items():
|
||||
if key not in ('_version_id','__weakref__'):
|
||||
setattr(self, key, value)
|
||||
|
||||
|
||||
class Base:
|
||||
"""
|
||||
This is the controlling class for the signatures for the collection of
|
||||
entries associated with a specific directory. The actual directory
|
||||
association will be maintained by a subclass that is specific to
|
||||
the underlying storage method. This class provides a common set of
|
||||
methods for fetching and storing the individual bits of information
|
||||
that make up signature entry.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.entries = {}
|
||||
self.dirty = False
|
||||
self.to_be_merged = {}
|
||||
|
||||
def get_entry(self, filename):
|
||||
"""
|
||||
Fetch the specified entry attribute.
|
||||
"""
|
||||
return self.entries[filename]
|
||||
|
||||
def set_entry(self, filename, obj):
|
||||
"""
|
||||
Set the entry.
|
||||
"""
|
||||
self.entries[filename] = obj
|
||||
self.dirty = True
|
||||
|
||||
def do_not_set_entry(self, filename, obj):
|
||||
pass
|
||||
|
||||
def store_info(self, filename, node):
|
||||
entry = node.get_stored_info()
|
||||
entry.binfo.merge(node.get_binfo())
|
||||
self.to_be_merged[filename] = node
|
||||
self.dirty = True
|
||||
|
||||
def do_not_store_info(self, filename, node):
|
||||
pass
|
||||
|
||||
def merge(self):
|
||||
for key, node in self.to_be_merged.items():
|
||||
entry = node.get_stored_info()
|
||||
try:
|
||||
ninfo = entry.ninfo
|
||||
except AttributeError:
|
||||
# This happens with SConf Nodes, because the configuration
|
||||
# subsystem takes direct control over how the build decision
|
||||
# is made and its information stored.
|
||||
pass
|
||||
else:
|
||||
ninfo.merge(node.get_ninfo())
|
||||
self.entries[key] = entry
|
||||
self.to_be_merged = {}
|
||||
|
||||
|
||||
class DB(Base):
|
||||
"""
|
||||
A Base subclass that reads and writes signature information
|
||||
from a global .sconsign.db* file--the actual file suffix is
|
||||
determined by the database module.
|
||||
"""
|
||||
def __init__(self, dir):
|
||||
Base.__init__(self)
|
||||
|
||||
self.dir = dir
|
||||
|
||||
db, mode = Get_DataBase(dir)
|
||||
|
||||
# Read using the path relative to the top of the Repository
|
||||
# (self.dir.tpath) from which we're fetching the signature
|
||||
# information.
|
||||
path = normcase(dir.get_tpath())
|
||||
try:
|
||||
rawentries = db[path]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
try:
|
||||
self.entries = pickle.loads(rawentries)
|
||||
if not isinstance(self.entries, dict):
|
||||
self.entries = {}
|
||||
raise TypeError
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except Exception as e:
|
||||
SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
|
||||
"Ignoring corrupt sconsign entry : %s (%s)\n"%(self.dir.get_tpath(), e))
|
||||
for key, entry in self.entries.items():
|
||||
entry.convert_from_sconsign(dir, key)
|
||||
|
||||
if mode == "r":
|
||||
# This directory is actually under a repository, which means
|
||||
# likely they're reaching in directly for a dependency on
|
||||
# a file there. Don't actually set any entry info, so we
|
||||
# won't try to write to that .sconsign.dblite file.
|
||||
self.set_entry = self.do_not_set_entry
|
||||
self.store_info = self.do_not_store_info
|
||||
|
||||
global sig_files
|
||||
sig_files.append(self)
|
||||
|
||||
def write(self, sync=1):
|
||||
if not self.dirty:
|
||||
return
|
||||
|
||||
self.merge()
|
||||
|
||||
db, mode = Get_DataBase(self.dir)
|
||||
|
||||
# Write using the path relative to the top of the SConstruct
|
||||
# directory (self.dir.path), not relative to the top of
|
||||
# the Repository; we only write to our own .sconsign file,
|
||||
# not to .sconsign files in Repositories.
|
||||
path = normcase(self.dir.get_internal_path())
|
||||
for key, entry in self.entries.items():
|
||||
entry.convert_to_sconsign()
|
||||
db[path] = pickle.dumps(self.entries, PICKLE_PROTOCOL)
|
||||
|
||||
if sync:
|
||||
try:
|
||||
syncmethod = db.sync
|
||||
except AttributeError:
|
||||
# Not all anydbm modules have sync() methods.
|
||||
pass
|
||||
else:
|
||||
syncmethod()
|
||||
|
||||
|
||||
class Dir(Base):
|
||||
def __init__(self, fp=None, dir=None):
|
||||
"""
|
||||
fp - file pointer to read entries from
|
||||
"""
|
||||
Base.__init__(self)
|
||||
|
||||
if not fp:
|
||||
return
|
||||
|
||||
self.entries = pickle.load(fp)
|
||||
if not isinstance(self.entries, dict):
|
||||
self.entries = {}
|
||||
raise TypeError
|
||||
|
||||
if dir:
|
||||
for key, entry in self.entries.items():
|
||||
entry.convert_from_sconsign(dir, key)
|
||||
|
||||
|
||||
class DirFile(Dir):
|
||||
"""
|
||||
Encapsulates reading and writing a per-directory .sconsign file.
|
||||
"""
|
||||
def __init__(self, dir):
|
||||
"""
|
||||
dir - the directory for the file
|
||||
"""
|
||||
|
||||
self.dir = dir
|
||||
self.sconsign = os.path.join(dir.get_internal_path(), '.sconsign')
|
||||
|
||||
try:
|
||||
fp = open(self.sconsign, 'rb')
|
||||
except IOError:
|
||||
fp = None
|
||||
|
||||
try:
|
||||
Dir.__init__(self, fp, dir)
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except Exception:
|
||||
SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning,
|
||||
"Ignoring corrupt .sconsign file: %s"%self.sconsign)
|
||||
|
||||
try:
|
||||
fp.close()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
global sig_files
|
||||
sig_files.append(self)
|
||||
|
||||
def write(self, sync=1):
|
||||
"""
|
||||
Write the .sconsign file to disk.
|
||||
|
||||
Try to write to a temporary file first, and rename it if we
|
||||
succeed. If we can't write to the temporary file, it's
|
||||
probably because the directory isn't writable (and if so,
|
||||
how did we build anything in this directory, anyway?), so
|
||||
try to write directly to the .sconsign file as a backup.
|
||||
If we can't rename, try to copy the temporary contents back
|
||||
to the .sconsign file. Either way, always try to remove
|
||||
the temporary file at the end.
|
||||
"""
|
||||
if not self.dirty:
|
||||
return
|
||||
|
||||
self.merge()
|
||||
|
||||
temp = os.path.join(self.dir.get_internal_path(), '.scons%d' % os.getpid())
|
||||
try:
|
||||
file = open(temp, 'wb')
|
||||
fname = temp
|
||||
except IOError:
|
||||
try:
|
||||
file = open(self.sconsign, 'wb')
|
||||
fname = self.sconsign
|
||||
except IOError:
|
||||
return
|
||||
for key, entry in self.entries.items():
|
||||
entry.convert_to_sconsign()
|
||||
pickle.dump(self.entries, file, PICKLE_PROTOCOL)
|
||||
file.close()
|
||||
if fname != self.sconsign:
|
||||
try:
|
||||
mode = os.stat(self.sconsign)[0]
|
||||
os.chmod(self.sconsign, 0o666)
|
||||
os.unlink(self.sconsign)
|
||||
except (IOError, OSError):
|
||||
# Try to carry on in the face of either OSError
|
||||
# (things like permission issues) or IOError (disk
|
||||
# or network issues). If there's a really dangerous
|
||||
# issue, it should get re-raised by the calls below.
|
||||
pass
|
||||
try:
|
||||
os.rename(fname, self.sconsign)
|
||||
except OSError:
|
||||
# An OSError failure to rename may indicate something
|
||||
# like the directory has no write permission, but
|
||||
# the .sconsign file itself might still be writable,
|
||||
# so try writing on top of it directly. An IOError
|
||||
# here, or in any of the following calls, would get
|
||||
# raised, indicating something like a potentially
|
||||
# serious disk or network issue.
|
||||
with open(self.sconsign, 'wb') as f, open(fname, 'rb') as f2:
|
||||
f.write(f2.read())
|
||||
os.chmod(self.sconsign, mode)
|
||||
try:
|
||||
os.unlink(temp)
|
||||
except (IOError, OSError):
|
||||
pass
|
||||
|
||||
ForDirectory = DB
|
||||
|
||||
|
||||
def File(name, dbm_module=None):
|
||||
"""
|
||||
Arrange for all signatures to be stored in a global .sconsign.db*
|
||||
file.
|
||||
"""
|
||||
global ForDirectory, DB_Name, DB_Module
|
||||
if name is None:
|
||||
ForDirectory = DirFile
|
||||
DB_Module = None
|
||||
else:
|
||||
ForDirectory = DB
|
||||
DB_Name = name
|
||||
if dbm_module is not None:
|
||||
DB_Module = dbm_module
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
225
scons/scons-local-4.0.1/SCons/Scanner/C.py
Normal file
225
scons/scons-local-4.0.1/SCons/Scanner/C.py
Normal file
|
@ -0,0 +1,225 @@
|
|||
"""SCons.Scanner.C
|
||||
|
||||
This module implements the dependency scanner for C/C++ code.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
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:
|
||||
"""
|
||||
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
|
||||
|
||||
|
||||
#
|
||||
# ConditionalScanner
|
||||
#
|
||||
|
||||
|
||||
class SConsCPPConditionalScanner(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 = []
|
||||
self._known_paths = []
|
||||
|
||||
def initialize_result(self, fname):
|
||||
self.result = SCons.Util.UniqueList([fname])
|
||||
|
||||
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:
|
||||
"""
|
||||
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=(), 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 SConsCPPConditionalScannerWrapper("CConditionalScanner", "CPPPATH")
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
73
scons/scons-local-4.0.1/SCons/Scanner/D.py
Normal file
73
scons/scons-local-4.0.1/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__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
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 = r'(?: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/scons-local-4.0.1/SCons/Scanner/Dir.py
Normal file
109
scons/scons-local-4.0.1/SCons/Scanner/Dir.py
Normal file
|
@ -0,0 +1,109 @@
|
|||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
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:
|
324
scons/scons-local-4.0.1/SCons/Scanner/Fortran.py
Normal file
324
scons/scons-local-4.0.1/SCons/Scanner/Fortran.py
Normal file
|
@ -0,0 +1,324 @@
|
|||
"""SCons.Scanner.Fortran
|
||||
|
||||
This module implements the dependency scanner for Fortran code.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
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 is not 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 = r"(?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 = r"""(?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
|
||||
# MODULE SUBROUTINE subroutine_name
|
||||
# MODULE FUNCTION function_name
|
||||
# MODULE PURE SUBROUTINE|FUNCTION subroutine_name|function_name
|
||||
# MODULE ELEMENTAL SUBROUTINE|FUNCTION subroutine_name|function_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|SUBROUTINE|FUNCTION|PURE|ELEMENTAL)
|
||||
# : but *don't* match if the next word
|
||||
# matches PROCEDURE, SUBROUTINE,
|
||||
# FUNCTION, PURE or ELEMENTAL (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 = r"""(?i)^\s*MODULE\s+(?!PROCEDURE|SUBROUTINE|FUNCTION|PURE|ELEMENTAL)(\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/scons-local-4.0.1/SCons/Scanner/IDL.py
Normal file
48
scons/scons-local-4.0.1/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__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
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:
|
429
scons/scons-local-4.0.1/SCons/Scanner/LaTeX.py
Normal file
429
scons/scons-local-4.0.1/SCons/Scanner/LaTeX.py
Normal file
|
@ -0,0 +1,429 @@
|
|||
"""SCons.Scanner.LaTeX
|
||||
|
||||
This module implements the dependency scanner for LaTeX code.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
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:
|
||||
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:
|
||||
"""
|
||||
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):
|
||||
regex = r'''
|
||||
\\(
|
||||
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:
|
||||
"""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:
|
||||
"""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:
|
||||
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(r'\s*\[.*$')
|
||||
if node.includes is not 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 inc in inc_list:
|
||||
split_includes.append((inc_type, inc_subdir, inc))
|
||||
|
||||
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/scons-local-4.0.1/SCons/Scanner/Prog.py
Normal file
116
scons/scons-local-4.0.1/SCons/Scanner/Prog.py
Normal file
|
@ -0,0 +1,116 @@
|
|||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
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:
|
171
scons/scons-local-4.0.1/SCons/Scanner/Python.py
Normal file
171
scons/scons-local-4.0.1/SCons/Scanner/Python.py
Normal file
|
@ -0,0 +1,171 @@
|
|||
"""SCons.Scanner.Python
|
||||
|
||||
This module implements the dependency scanner for Python code.
|
||||
|
||||
One important note about the design is that this does not take any dependencies
|
||||
upon packages or binaries in the Python installation unless they are listed in
|
||||
PYTHONPATH. To do otherwise would have required code to determine where the
|
||||
Python installation is, which is outside of the scope of a scanner like this.
|
||||
If consumers want to pick up dependencies upon these packages, they must put
|
||||
those directories in PYTHONPATH.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import itertools
|
||||
import os
|
||||
import re
|
||||
import SCons.Scanner
|
||||
|
||||
# Capture python "from a import b" and "import a" statements.
|
||||
from_cre = re.compile(r'^\s*from\s+([^\s]+)\s+import\s+(.*)', re.M)
|
||||
import_cre = re.compile(r'^\s*import\s+([^\s]+)', re.M)
|
||||
|
||||
|
||||
def path_function(env, dir=None, target=None, source=None, argument=None):
|
||||
"""Retrieves a tuple with all search paths."""
|
||||
paths = env['ENV'].get('PYTHONPATH', '').split(os.pathsep)
|
||||
if source:
|
||||
paths.append(source[0].dir.abspath)
|
||||
return tuple(paths)
|
||||
|
||||
|
||||
def find_include_names(node):
|
||||
"""
|
||||
Scans the node for all imports.
|
||||
|
||||
Returns a list of tuples. Each tuple has two elements:
|
||||
1. The main import (e.g. module, module.file, module.module2)
|
||||
2. Additional optional imports that could be functions or files
|
||||
in the case of a "from X import Y" statement. In the case of a
|
||||
normal "import" statement, this is None.
|
||||
"""
|
||||
text = node.get_text_contents()
|
||||
all_matches = []
|
||||
matches = from_cre.findall(text)
|
||||
if matches:
|
||||
for match in matches:
|
||||
imports = [i.strip() for i in match[1].split(',')]
|
||||
|
||||
# Add some custom logic to strip out "as" because the regex
|
||||
# includes it.
|
||||
last_import_split = imports[-1].split()
|
||||
if len(last_import_split) > 1:
|
||||
imports[-1] = last_import_split[0]
|
||||
|
||||
all_matches.append((match[0], imports))
|
||||
|
||||
matches = import_cre.findall(text)
|
||||
if matches:
|
||||
for match in matches:
|
||||
all_matches.append((match, None))
|
||||
|
||||
return all_matches
|
||||
|
||||
|
||||
def scan(node, env, path=()):
|
||||
# cache the includes list in node so we only scan it once:
|
||||
if node.includes is not None:
|
||||
includes = node.includes
|
||||
else:
|
||||
includes = 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))
|
||||
|
||||
# XXX TODO: Sort?
|
||||
nodes = []
|
||||
if callable(path):
|
||||
path = path()
|
||||
for module, imports in includes:
|
||||
is_relative = module.startswith('.')
|
||||
if is_relative:
|
||||
# This is a relative include, so we must ignore PYTHONPATH.
|
||||
module_lstripped = module.lstrip('.')
|
||||
# One dot is current directory, two is parent, three is
|
||||
# grandparent, etc.
|
||||
num_parents = len(module) - len(module_lstripped) - 1
|
||||
current_dir = node.get_dir()
|
||||
for i in itertools.repeat(None, num_parents):
|
||||
current_dir = current_dir.up()
|
||||
|
||||
search_paths = [current_dir.abspath]
|
||||
search_string = module_lstripped
|
||||
else:
|
||||
search_paths = path
|
||||
search_string = module
|
||||
|
||||
module_components = search_string.split('.')
|
||||
for search_path in search_paths:
|
||||
candidate_path = os.path.join(search_path, *module_components)
|
||||
# The import stored in "module" could refer to a directory or file.
|
||||
import_dirs = []
|
||||
if os.path.isdir(candidate_path):
|
||||
import_dirs = module_components
|
||||
|
||||
# Because this resolved to a directory, there is a chance that
|
||||
# additional imports (e.g. from module import A, B) could refer
|
||||
# to files to import.
|
||||
if imports:
|
||||
for imp in imports:
|
||||
file = os.path.join(candidate_path, imp + '.py')
|
||||
if os.path.isfile(file):
|
||||
nodes.append(file)
|
||||
elif os.path.isfile(candidate_path + '.py'):
|
||||
nodes.append(candidate_path + '.py')
|
||||
import_dirs = module_components[:-1]
|
||||
|
||||
# We can ignore imports because this resolved to a file. Any
|
||||
# additional imports (e.g. from module.file import A, B) would
|
||||
# only refer to functions in this file.
|
||||
|
||||
# Take a dependency on all __init__.py files from all imported
|
||||
# packages unless it's a relative import. If it's a relative
|
||||
# import, we don't need to take the dependency because Python
|
||||
# requires that all referenced packages have already been imported,
|
||||
# which means that the dependency has already been established.
|
||||
if import_dirs and not is_relative:
|
||||
for i in range(len(import_dirs)):
|
||||
init_components = module_components[:i+1] + ['__init__.py']
|
||||
init_path = os.path.join(search_path, *(init_components))
|
||||
if os.path.isfile(init_path):
|
||||
nodes.append(init_path)
|
||||
break
|
||||
|
||||
return sorted(nodes)
|
||||
|
||||
|
||||
PythonSuffixes = ['.py']
|
||||
PythonScanner = SCons.Scanner.Base(scan, name='PythonScanner',
|
||||
skeys=PythonSuffixes,
|
||||
path_function=path_function, recursive=1)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
66
scons/scons-local-4.0.1/SCons/Scanner/RC.py
Normal file
66
scons/scons-local-4.0.1/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__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
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)|' \
|
||||
r'.*?\s+(?:ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)' \
|
||||
r'\s*.*?)' \
|
||||
r'\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/scons-local-4.0.1/SCons/Scanner/SWIG.py
Normal file
45
scons/scons-local-4.0.1/SCons/Scanner/SWIG.py
Normal file
|
@ -0,0 +1,45 @@
|
|||
"""SCons.Scanner.SWIG
|
||||
|
||||
This module implements the dependency scanner for SWIG code.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import SCons.Scanner
|
||||
|
||||
SWIGSuffixes = [ '.i' ]
|
||||
|
||||
def SWIGScanner():
|
||||
expr = r'^[ \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/scons-local-4.0.1/SCons/Scanner/__init__.py
Normal file
421
scons/scons-local-4.0.1/SCons/Scanner/__init__.py
Normal file
|
@ -0,0 +1,421 @@
|
|||
"""SCons.Scanner
|
||||
|
||||
The Scanner package for the SCons software construction utility.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import re
|
||||
|
||||
import SCons.Node.FS
|
||||
import SCons.Util
|
||||
|
||||
|
||||
class _Null:
|
||||
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:
|
||||
"""
|
||||
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:
|
||||
"""
|
||||
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 self.argument is not _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:
|
374
scons/scons-local-4.0.1/SCons/Script/Interactive.py
Normal file
374
scons/scons-local-4.0.1/SCons/Script/Interactive.py
Normal file
|
@ -0,0 +1,374 @@
|
|||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
__doc__ = """
|
||||
SCons interactive mode
|
||||
"""
|
||||
|
||||
# TODO:
|
||||
#
|
||||
# This has the potential to grow into something with a really big life
|
||||
# of its own, which might or might not be a good thing. Nevertheless,
|
||||
# here are some enhancements that will probably be requested some day
|
||||
# and are worth keeping in mind (assuming this takes off):
|
||||
#
|
||||
# - A command to re-read / re-load the SConscript files. This may
|
||||
# involve allowing people to specify command-line options (e.g. -f,
|
||||
# -I, --no-site-dir) that affect how the SConscript files are read.
|
||||
#
|
||||
# - Additional command-line options on the "build" command.
|
||||
#
|
||||
# Of the supported options that seemed to make sense (after a quick
|
||||
# pass through the list), the ones that seemed likely enough to be
|
||||
# used are listed in the man page and have explicit test scripts.
|
||||
#
|
||||
# These had code changed in Script/Main.py to support them, but didn't
|
||||
# seem likely to be used regularly, so had no test scripts added:
|
||||
#
|
||||
# build --diskcheck=*
|
||||
# build --implicit-cache=*
|
||||
# build --implicit-deps-changed=*
|
||||
# build --implicit-deps-unchanged=*
|
||||
#
|
||||
# These look like they should "just work" with no changes to the
|
||||
# existing code, but like those above, look unlikely to be used and
|
||||
# therefore had no test scripts added:
|
||||
#
|
||||
# build --random
|
||||
#
|
||||
# These I'm not sure about. They might be useful for individual
|
||||
# "build" commands, and may even work, but they seem unlikely enough
|
||||
# that we'll wait until they're requested before spending any time on
|
||||
# writing test scripts for them, or investigating whether they work.
|
||||
#
|
||||
# build -q [??? is there a useful analog to the exit status?]
|
||||
# build --duplicate=
|
||||
# build --profile=
|
||||
# build --max-drift=
|
||||
# build --warn=*
|
||||
# build --Y
|
||||
#
|
||||
# - Most of the SCons command-line options that the "build" command
|
||||
# supports should be settable as default options that apply to all
|
||||
# subsequent "build" commands. Maybe a "set {option}" command that
|
||||
# maps to "SetOption('{option}')".
|
||||
#
|
||||
# - Need something in the 'help' command that prints the -h output.
|
||||
#
|
||||
# - A command to run the configure subsystem separately (must see how
|
||||
# this interacts with the new automake model).
|
||||
#
|
||||
# - Command-line completion of target names; maybe even of SCons options?
|
||||
# Completion is something that's supported by the Python cmd module,
|
||||
# so this should be doable without too much trouble.
|
||||
#
|
||||
|
||||
import cmd
|
||||
import copy
|
||||
import os
|
||||
import re
|
||||
import shlex
|
||||
import sys
|
||||
|
||||
try:
|
||||
import readline
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
class SConsInteractiveCmd(cmd.Cmd):
|
||||
"""\
|
||||
|
||||
build [TARGETS] Build the specified TARGETS and their dependencies. 'b' is a synonym.
|
||||
clean [TARGETS] Clean (remove) the specified TARGETS and their dependencies. 'c' is a synonym.
|
||||
exit Exit SCons interactive mode.
|
||||
help [COMMAND] Prints help for the specified COMMAND. 'h' and '?' are synonyms.
|
||||
shell [COMMANDLINE] Execute COMMANDLINE in a subshell. 'sh' and '!' are synonyms.
|
||||
version Prints SCons version information.
|
||||
"""
|
||||
|
||||
synonyms = {
|
||||
'b' : 'build',
|
||||
'c' : 'clean',
|
||||
'h' : 'help',
|
||||
'scons' : 'build',
|
||||
'sh' : 'shell',
|
||||
}
|
||||
|
||||
def __init__(self, **kw):
|
||||
cmd.Cmd.__init__(self)
|
||||
for key, val in kw.items():
|
||||
setattr(self, key, val)
|
||||
|
||||
if sys.platform == 'win32':
|
||||
self.shell_variable = 'COMSPEC'
|
||||
else:
|
||||
self.shell_variable = 'SHELL'
|
||||
|
||||
def default(self, argv):
|
||||
print("*** Unknown command: %s" % argv[0])
|
||||
|
||||
def onecmd(self, line):
|
||||
line = line.strip()
|
||||
if not line:
|
||||
print(self.lastcmd)
|
||||
return self.emptyline()
|
||||
self.lastcmd = line
|
||||
if line[0] == '!':
|
||||
line = 'shell ' + line[1:]
|
||||
elif line[0] == '?':
|
||||
line = 'help ' + line[1:]
|
||||
if os.sep == '\\':
|
||||
line = line.replace('\\', '\\\\')
|
||||
argv = shlex.split(line)
|
||||
argv[0] = self.synonyms.get(argv[0], argv[0])
|
||||
if not argv[0]:
|
||||
return self.default(line)
|
||||
else:
|
||||
try:
|
||||
func = getattr(self, 'do_' + argv[0])
|
||||
except AttributeError:
|
||||
return self.default(argv)
|
||||
return func(argv)
|
||||
|
||||
def do_build(self, argv):
|
||||
"""\
|
||||
build [TARGETS] Build the specified TARGETS and their
|
||||
dependencies. 'b' is a synonym.
|
||||
"""
|
||||
import SCons.Node
|
||||
import SCons.SConsign
|
||||
import SCons.Script.Main
|
||||
|
||||
options = copy.deepcopy(self.options)
|
||||
|
||||
options, targets = self.parser.parse_args(argv[1:], values=options)
|
||||
|
||||
SCons.Script.COMMAND_LINE_TARGETS = targets
|
||||
|
||||
if targets:
|
||||
SCons.Script.BUILD_TARGETS = targets
|
||||
else:
|
||||
# If the user didn't specify any targets on the command line,
|
||||
# use the list of default targets.
|
||||
SCons.Script.BUILD_TARGETS = SCons.Script._build_plus_default
|
||||
|
||||
nodes = SCons.Script.Main._build_targets(self.fs,
|
||||
options,
|
||||
targets,
|
||||
self.target_top)
|
||||
|
||||
if not nodes:
|
||||
return
|
||||
|
||||
# Call each of the Node's alter_targets() methods, which may
|
||||
# provide additional targets that ended up as part of the build
|
||||
# (the canonical example being a VariantDir() when we're building
|
||||
# from a source directory) and which we therefore need their
|
||||
# state cleared, too.
|
||||
x = []
|
||||
for n in nodes:
|
||||
x.extend(n.alter_targets()[0])
|
||||
nodes.extend(x)
|
||||
|
||||
# Clean up so that we can perform the next build correctly.
|
||||
#
|
||||
# We do this by walking over all the children of the targets,
|
||||
# and clearing their state.
|
||||
#
|
||||
# We currently have to re-scan each node to find their
|
||||
# children, because built nodes have already been partially
|
||||
# cleared and don't remember their children. (In scons
|
||||
# 0.96.1 and earlier, this wasn't the case, and we didn't
|
||||
# have to re-scan the nodes.)
|
||||
#
|
||||
# Because we have to re-scan each node, we can't clear the
|
||||
# nodes as we walk over them, because we may end up rescanning
|
||||
# a cleared node as we scan a later node. Therefore, only
|
||||
# store the list of nodes that need to be cleared as we walk
|
||||
# the tree, and clear them in a separate pass.
|
||||
#
|
||||
# XXX: Someone more familiar with the inner workings of scons
|
||||
# may be able to point out a more efficient way to do this.
|
||||
|
||||
SCons.Script.Main.progress_display("scons: Clearing cached node information ...")
|
||||
|
||||
seen_nodes = {}
|
||||
|
||||
def get_unseen_children(node, parent, seen_nodes=seen_nodes):
|
||||
def is_unseen(node, seen_nodes=seen_nodes):
|
||||
return node not in seen_nodes
|
||||
return [child for child in node.children(scan=1) if is_unseen(child)]
|
||||
|
||||
def add_to_seen_nodes(node, parent, seen_nodes=seen_nodes):
|
||||
seen_nodes[node] = 1
|
||||
|
||||
# If this file is in a VariantDir and has a
|
||||
# corresponding source file in the source tree, remember the
|
||||
# node in the source tree, too. This is needed in
|
||||
# particular to clear cached implicit dependencies on the
|
||||
# source file, since the scanner will scan it if the
|
||||
# VariantDir was created with duplicate=0.
|
||||
try:
|
||||
rfile_method = node.rfile
|
||||
except AttributeError:
|
||||
return
|
||||
else:
|
||||
rfile = rfile_method()
|
||||
if rfile != node:
|
||||
seen_nodes[rfile] = 1
|
||||
|
||||
for node in nodes:
|
||||
walker = SCons.Node.Walker(node,
|
||||
kids_func=get_unseen_children,
|
||||
eval_func=add_to_seen_nodes)
|
||||
n = walker.get_next()
|
||||
while n:
|
||||
n = walker.get_next()
|
||||
|
||||
for node in seen_nodes.keys():
|
||||
# Call node.clear() to clear most of the state
|
||||
node.clear()
|
||||
# node.clear() doesn't reset node.state, so call
|
||||
# node.set_state() to reset it manually
|
||||
node.set_state(SCons.Node.no_state)
|
||||
node.implicit = None
|
||||
|
||||
# Debug: Uncomment to verify that all Taskmaster reference
|
||||
# counts have been reset to zero.
|
||||
#if node.ref_count != 0:
|
||||
# from SCons.Debug import Trace
|
||||
# Trace('node %s, ref_count %s !!!\n' % (node, node.ref_count))
|
||||
|
||||
SCons.SConsign.Reset()
|
||||
SCons.Script.Main.progress_display("scons: done clearing node information.")
|
||||
|
||||
def do_clean(self, argv):
|
||||
"""\
|
||||
clean [TARGETS] Clean (remove) the specified TARGETS
|
||||
and their dependencies. 'c' is a synonym.
|
||||
"""
|
||||
return self.do_build(['build', '--clean'] + argv[1:])
|
||||
|
||||
def do_EOF(self, argv):
|
||||
print()
|
||||
self.do_exit(argv)
|
||||
|
||||
def _do_one_help(self, arg):
|
||||
try:
|
||||
# If help_<arg>() exists, then call it.
|
||||
func = getattr(self, 'help_' + arg)
|
||||
except AttributeError:
|
||||
try:
|
||||
func = getattr(self, 'do_' + arg)
|
||||
except AttributeError:
|
||||
doc = None
|
||||
else:
|
||||
doc = self._doc_to_help(func)
|
||||
if doc:
|
||||
sys.stdout.write(doc + '\n')
|
||||
sys.stdout.flush()
|
||||
else:
|
||||
doc = self.strip_initial_spaces(func())
|
||||
if doc:
|
||||
sys.stdout.write(doc + '\n')
|
||||
sys.stdout.flush()
|
||||
|
||||
def _doc_to_help(self, obj):
|
||||
doc = obj.__doc__
|
||||
if doc is None:
|
||||
return ''
|
||||
return self._strip_initial_spaces(doc)
|
||||
|
||||
def _strip_initial_spaces(self, s):
|
||||
lines = s.split('\n')
|
||||
spaces = re.match(' *', lines[0]).group(0)
|
||||
def strip_spaces(l, spaces=spaces):
|
||||
if l[:len(spaces)] == spaces:
|
||||
l = l[len(spaces):]
|
||||
return l
|
||||
lines = list(map(strip_spaces, lines))
|
||||
return '\n'.join(lines)
|
||||
|
||||
def do_exit(self, argv):
|
||||
"""\
|
||||
exit Exit SCons interactive mode.
|
||||
"""
|
||||
sys.exit(0)
|
||||
|
||||
def do_help(self, argv):
|
||||
"""\
|
||||
help [COMMAND] Prints help for the specified COMMAND. 'h'
|
||||
and '?' are synonyms.
|
||||
"""
|
||||
if argv[1:]:
|
||||
for arg in argv[1:]:
|
||||
if self._do_one_help(arg):
|
||||
break
|
||||
else:
|
||||
# If bare 'help' is called, print this class's doc
|
||||
# string (if it has one).
|
||||
doc = self._doc_to_help(self.__class__)
|
||||
if doc:
|
||||
sys.stdout.write(doc + '\n')
|
||||
sys.stdout.flush()
|
||||
|
||||
def do_shell(self, argv):
|
||||
"""\
|
||||
shell [COMMANDLINE] Execute COMMANDLINE in a subshell. 'sh' and
|
||||
'!' are synonyms.
|
||||
"""
|
||||
import subprocess
|
||||
argv = argv[1:]
|
||||
if not argv:
|
||||
argv = os.environ[self.shell_variable]
|
||||
try:
|
||||
# Per "[Python-Dev] subprocess insufficiently platform-independent?"
|
||||
# http://mail.python.org/pipermail/python-dev/2008-August/081979.html "+
|
||||
# Doing the right thing with an argument list currently
|
||||
# requires different shell= values on Windows and Linux.
|
||||
p = subprocess.Popen(argv, shell=(sys.platform=='win32'))
|
||||
except EnvironmentError as e:
|
||||
sys.stderr.write('scons: %s: %s\n' % (argv[0], e.strerror))
|
||||
else:
|
||||
p.wait()
|
||||
|
||||
def do_version(self, argv):
|
||||
"""\
|
||||
version Prints SCons version information.
|
||||
"""
|
||||
sys.stdout.write(self.parser.version + '\n')
|
||||
|
||||
def interact(fs, parser, options, targets, target_top):
|
||||
c = SConsInteractiveCmd(prompt = 'scons>>> ',
|
||||
fs = fs,
|
||||
parser = parser,
|
||||
options = options,
|
||||
targets = targets,
|
||||
target_top = target_top)
|
||||
c.cmdloop()
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
1457
scons/scons-local-4.0.1/SCons/Script/Main.py
Normal file
1457
scons/scons-local-4.0.1/SCons/Script/Main.py
Normal file
File diff suppressed because it is too large
Load diff
985
scons/scons-local-4.0.1/SCons/Script/SConsOptions.py
Normal file
985
scons/scons-local-4.0.1/SCons/Script/SConsOptions.py
Normal file
|
@ -0,0 +1,985 @@
|
|||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import optparse
|
||||
import re
|
||||
import sys
|
||||
import textwrap
|
||||
|
||||
no_hyphen_re = re.compile(r'(\s+|(?<=[\w!\"\'&.,?])-{2,}(?=\w))')
|
||||
|
||||
try:
|
||||
from gettext import gettext
|
||||
except ImportError:
|
||||
def gettext(message):
|
||||
return message
|
||||
_ = gettext
|
||||
|
||||
import SCons.Node.FS
|
||||
import SCons.Platform.virtualenv
|
||||
import SCons.Warnings
|
||||
|
||||
OptionValueError = optparse.OptionValueError
|
||||
SUPPRESS_HELP = optparse.SUPPRESS_HELP
|
||||
|
||||
diskcheck_all = SCons.Node.FS.diskcheck_types()
|
||||
|
||||
def diskcheck_convert(value):
|
||||
if value is None:
|
||||
return []
|
||||
if not SCons.Util.is_List(value):
|
||||
value = value.split(',')
|
||||
result = []
|
||||
for v in value:
|
||||
v = v.lower()
|
||||
if v == 'all':
|
||||
result = diskcheck_all
|
||||
elif v == 'none':
|
||||
result = []
|
||||
elif v in diskcheck_all:
|
||||
result.append(v)
|
||||
else:
|
||||
raise ValueError(v)
|
||||
return result
|
||||
|
||||
|
||||
class SConsValues(optparse.Values):
|
||||
"""
|
||||
Holder class for uniform access to SCons options, regardless
|
||||
of whether or not they can be set on the command line or in the
|
||||
SConscript files (using the SetOption() function).
|
||||
|
||||
A SCons option value can originate three different ways:
|
||||
|
||||
1) set on the command line;
|
||||
2) set in an SConscript file;
|
||||
3) the default setting (from the the op.add_option()
|
||||
calls in the Parser() function, below).
|
||||
|
||||
The command line always overrides a value set in a SConscript file,
|
||||
which in turn always overrides default settings. Because we want
|
||||
to support user-specified options in the SConscript file itself,
|
||||
though, we may not know about all of the options when the command
|
||||
line is first parsed, so we can't make all the necessary precedence
|
||||
decisions at the time the option is configured.
|
||||
|
||||
The solution implemented in this class is to keep these different sets
|
||||
of settings separate (command line, SConscript file, and default)
|
||||
and to override the __getattr__() method to check them in turn.
|
||||
This should allow the rest of the code to just fetch values as
|
||||
attributes of an instance of this class, without having to worry
|
||||
about where they came from.
|
||||
|
||||
Note that not all command line options are settable from SConscript
|
||||
files, and the ones that are must be explicitly added to the
|
||||
"settable" list in this class, and optionally validated and coerced
|
||||
in the set_option() method.
|
||||
"""
|
||||
|
||||
def __init__(self, defaults):
|
||||
self.__dict__['__defaults__'] = defaults
|
||||
self.__dict__['__SConscript_settings__'] = {}
|
||||
|
||||
def __getattr__(self, attr):
|
||||
"""
|
||||
Fetches an options value, checking first for explicit settings
|
||||
from the command line (which are direct attributes), then the
|
||||
SConscript file settings, then the default values.
|
||||
"""
|
||||
try:
|
||||
return self.__dict__[attr]
|
||||
except KeyError:
|
||||
try:
|
||||
return self.__dict__['__SConscript_settings__'][attr]
|
||||
except KeyError:
|
||||
try:
|
||||
return getattr(self.__dict__['__defaults__'], attr)
|
||||
except KeyError:
|
||||
# Added because with py3 this is a new class,
|
||||
# not a classic class, and due to the way
|
||||
# In that case it will create an object without
|
||||
# __defaults__, and then query for __setstate__
|
||||
# which will throw an exception of KeyError
|
||||
# deepcopy() is expecting AttributeError if __setstate__
|
||||
# is not available.
|
||||
raise AttributeError(attr)
|
||||
|
||||
|
||||
settable = [
|
||||
'clean',
|
||||
'diskcheck',
|
||||
'duplicate',
|
||||
'help',
|
||||
'implicit_cache',
|
||||
'max_drift',
|
||||
'md5_chunksize',
|
||||
'no_exec',
|
||||
'num_jobs',
|
||||
'random',
|
||||
'stack_size',
|
||||
'warn',
|
||||
'silent',
|
||||
'no_progress'
|
||||
]
|
||||
|
||||
def set_option(self, name, value):
|
||||
"""
|
||||
Sets an option from an SConscript file.
|
||||
"""
|
||||
if name not in self.settable:
|
||||
raise SCons.Errors.UserError("This option is not settable from a SConscript file: %s"%name)
|
||||
|
||||
if name == 'num_jobs':
|
||||
try:
|
||||
value = int(value)
|
||||
if value < 1:
|
||||
raise ValueError
|
||||
except ValueError:
|
||||
raise SCons.Errors.UserError("A positive integer is required: %s"%repr(value))
|
||||
elif name == 'max_drift':
|
||||
try:
|
||||
value = int(value)
|
||||
except ValueError:
|
||||
raise SCons.Errors.UserError("An integer is required: %s"%repr(value))
|
||||
elif name == 'duplicate':
|
||||
try:
|
||||
value = str(value)
|
||||
except ValueError:
|
||||
raise SCons.Errors.UserError("A string is required: %s"%repr(value))
|
||||
if value not in SCons.Node.FS.Valid_Duplicates:
|
||||
raise SCons.Errors.UserError("Not a valid duplication style: %s" % value)
|
||||
# Set the duplicate style right away so it can affect linking
|
||||
# of SConscript files.
|
||||
SCons.Node.FS.set_duplicate(value)
|
||||
elif name == 'diskcheck':
|
||||
try:
|
||||
value = diskcheck_convert(value)
|
||||
except ValueError as v:
|
||||
raise SCons.Errors.UserError("Not a valid diskcheck value: %s"%v)
|
||||
if 'diskcheck' not in self.__dict__:
|
||||
# No --diskcheck= option was specified on the command line.
|
||||
# Set this right away so it can affect the rest of the
|
||||
# file/Node lookups while processing the SConscript files.
|
||||
SCons.Node.FS.set_diskcheck(value)
|
||||
elif name == 'stack_size':
|
||||
try:
|
||||
value = int(value)
|
||||
except ValueError:
|
||||
raise SCons.Errors.UserError("An integer is required: %s"%repr(value))
|
||||
elif name == 'md5_chunksize':
|
||||
try:
|
||||
value = int(value)
|
||||
except ValueError:
|
||||
raise SCons.Errors.UserError("An integer is required: %s"%repr(value))
|
||||
elif name == 'warn':
|
||||
if SCons.Util.is_String(value):
|
||||
value = [value]
|
||||
value = self.__SConscript_settings__.get(name, []) + value
|
||||
SCons.Warnings.process_warn_strings(value)
|
||||
elif name == 'no_progress':
|
||||
SCons.Script.Main.progress_display.set_mode(False)
|
||||
|
||||
|
||||
self.__SConscript_settings__[name] = value
|
||||
|
||||
|
||||
class SConsOption(optparse.Option):
|
||||
def convert_value(self, opt, value):
|
||||
if value is not None:
|
||||
if self.nargs in (1, '?'):
|
||||
return self.check_value(opt, value)
|
||||
else:
|
||||
return tuple([self.check_value(opt, v) for v in value])
|
||||
|
||||
def process(self, opt, value, values, parser):
|
||||
|
||||
# First, convert the value(s) to the right type. Howl if any
|
||||
# value(s) are bogus.
|
||||
value = self.convert_value(opt, value)
|
||||
|
||||
# And then take whatever action is expected of us.
|
||||
# This is a separate method to make life easier for
|
||||
# subclasses to add new actions.
|
||||
return self.take_action(
|
||||
self.action, self.dest, opt, value, values, parser)
|
||||
|
||||
def _check_nargs_optional(self):
|
||||
if self.nargs == '?' and self._short_opts:
|
||||
fmt = "option %s: nargs='?' is incompatible with short options"
|
||||
raise SCons.Errors.UserError(fmt % self._short_opts[0])
|
||||
|
||||
CHECK_METHODS = optparse.Option.CHECK_METHODS + [_check_nargs_optional]
|
||||
CONST_ACTIONS = optparse.Option.CONST_ACTIONS + optparse.Option.TYPED_ACTIONS
|
||||
|
||||
class SConsOptionGroup(optparse.OptionGroup):
|
||||
"""
|
||||
A subclass for SCons-specific option groups.
|
||||
|
||||
The only difference between this and the base class is that we print
|
||||
the group's help text flush left, underneath their own title but
|
||||
lined up with the normal "SCons Options".
|
||||
"""
|
||||
def format_help(self, formatter):
|
||||
"""
|
||||
Format an option group's help text, outdenting the title so it's
|
||||
flush with the "SCons Options" title we print at the top.
|
||||
"""
|
||||
formatter.dedent()
|
||||
result = formatter.format_heading(self.title)
|
||||
formatter.indent()
|
||||
result = result + optparse.OptionContainer.format_help(self, formatter)
|
||||
return result
|
||||
|
||||
class SConsOptionParser(optparse.OptionParser):
|
||||
preserve_unknown_options = False
|
||||
|
||||
def error(self, msg):
|
||||
# overridden OptionValueError exception handler
|
||||
self.print_usage(sys.stderr)
|
||||
sys.stderr.write("SCons Error: %s\n" % msg)
|
||||
sys.exit(2)
|
||||
|
||||
def _process_long_opt(self, rargs, values):
|
||||
"""
|
||||
SCons-specific processing of long options.
|
||||
|
||||
This is copied directly from the normal
|
||||
optparse._process_long_opt() method, except that, if configured
|
||||
to do so, we catch the exception thrown when an unknown option
|
||||
is encountered and just stick it back on the "leftover" arguments
|
||||
for later (re-)processing.
|
||||
"""
|
||||
arg = rargs.pop(0)
|
||||
|
||||
# Value explicitly attached to arg? Pretend it's the next
|
||||
# argument.
|
||||
if "=" in arg:
|
||||
(opt, next_arg) = arg.split("=", 1)
|
||||
rargs.insert(0, next_arg)
|
||||
had_explicit_value = True
|
||||
else:
|
||||
opt = arg
|
||||
had_explicit_value = False
|
||||
|
||||
try:
|
||||
opt = self._match_long_opt(opt)
|
||||
except optparse.BadOptionError:
|
||||
if self.preserve_unknown_options:
|
||||
# SCons-specific: if requested, add unknown options to
|
||||
# the "leftover arguments" list for later processing.
|
||||
self.largs.append(arg)
|
||||
if had_explicit_value:
|
||||
# The unknown option will be re-processed later,
|
||||
# so undo the insertion of the explicit value.
|
||||
rargs.pop(0)
|
||||
return
|
||||
raise
|
||||
|
||||
option = self._long_opt[opt]
|
||||
if option.takes_value():
|
||||
nargs = option.nargs
|
||||
if nargs == '?':
|
||||
if had_explicit_value:
|
||||
value = rargs.pop(0)
|
||||
else:
|
||||
value = option.const
|
||||
elif len(rargs) < nargs:
|
||||
if nargs == 1:
|
||||
if not option.choices:
|
||||
self.error(_("%s option requires an argument") % opt)
|
||||
else:
|
||||
msg = _("%s option requires an argument " % opt)
|
||||
msg += _("(choose from %s)"
|
||||
% ', '.join(option.choices))
|
||||
self.error(msg)
|
||||
else:
|
||||
self.error(_("%s option requires %d arguments")
|
||||
% (opt, nargs))
|
||||
elif nargs == 1:
|
||||
value = rargs.pop(0)
|
||||
else:
|
||||
value = tuple(rargs[0:nargs])
|
||||
del rargs[0:nargs]
|
||||
|
||||
elif had_explicit_value:
|
||||
self.error(_("%s option does not take a value") % opt)
|
||||
|
||||
else:
|
||||
value = None
|
||||
|
||||
option.process(opt, value, values, self)
|
||||
|
||||
def reparse_local_options(self):
|
||||
""" Re-parse the leftover command-line options.
|
||||
|
||||
Parse options stored in `self.largs`, so that any value
|
||||
overridden on the command line is immediately available
|
||||
if the user turns around and does a :func:`GetOption` right away.
|
||||
|
||||
We mimic the processing of the single args
|
||||
in the original OptionParser :func:`_process_args`, but here we
|
||||
allow exact matches for long-opts only (no partial argument names!).
|
||||
Otherwise there could be problems in :func:`add_local_option`
|
||||
below. When called from there, we try to reparse the
|
||||
command-line arguments that
|
||||
|
||||
1. haven't been processed so far (`self.largs`), but
|
||||
2. are possibly not added to the list of options yet.
|
||||
|
||||
So, when we only have a value for "--myargument" so far,
|
||||
a command-line argument of "--myarg=test" would set it,
|
||||
per the behaviour of :func:`_match_long_opt`,
|
||||
which allows for partial matches of the option name,
|
||||
as long as the common prefix appears to be unique.
|
||||
This would lead to further confusion, because we might want
|
||||
to add another option "--myarg" later on (see issue #2929).
|
||||
|
||||
"""
|
||||
rargs = []
|
||||
largs_restore = []
|
||||
# Loop over all remaining arguments
|
||||
skip = False
|
||||
for l in self.largs:
|
||||
if skip:
|
||||
# Accept all remaining arguments as they are
|
||||
largs_restore.append(l)
|
||||
else:
|
||||
if len(l) > 2 and l[0:2] == "--":
|
||||
# Check long option
|
||||
lopt = (l,)
|
||||
if "=" in l:
|
||||
# Split into option and value
|
||||
lopt = l.split("=", 1)
|
||||
|
||||
if lopt[0] in self._long_opt:
|
||||
# Argument is already known
|
||||
rargs.append('='.join(lopt))
|
||||
else:
|
||||
# Not known yet, so reject for now
|
||||
largs_restore.append('='.join(lopt))
|
||||
else:
|
||||
if l == "--" or l == "-":
|
||||
# Stop normal processing and don't
|
||||
# process the rest of the command-line opts
|
||||
largs_restore.append(l)
|
||||
skip = True
|
||||
else:
|
||||
rargs.append(l)
|
||||
|
||||
# Parse the filtered list
|
||||
self.parse_args(rargs, self.values)
|
||||
# Restore the list of remaining arguments for the
|
||||
# next call of AddOption/add_local_option...
|
||||
self.largs = self.largs + largs_restore
|
||||
|
||||
def add_local_option(self, *args, **kw):
|
||||
"""
|
||||
Adds a local option to the parser.
|
||||
|
||||
This is initiated by a SetOption() call to add a user-defined
|
||||
command-line option. We add the option to a separate option
|
||||
group for the local options, creating the group if necessary.
|
||||
"""
|
||||
try:
|
||||
group = self.local_option_group
|
||||
except AttributeError:
|
||||
group = SConsOptionGroup(self, 'Local Options')
|
||||
group = self.add_option_group(group)
|
||||
self.local_option_group = group
|
||||
|
||||
result = group.add_option(*args, **kw)
|
||||
|
||||
if result:
|
||||
# The option was added successfully. We now have to add the
|
||||
# default value to our object that holds the default values
|
||||
# (so that an attempt to fetch the option's attribute will
|
||||
# yield the default value when not overridden) and then
|
||||
# we re-parse the leftover command-line options, so that
|
||||
# any value overridden on the command line is immediately
|
||||
# available if the user turns around and does a GetOption()
|
||||
# right away.
|
||||
setattr(self.values.__defaults__, result.dest, result.default)
|
||||
self.reparse_local_options()
|
||||
|
||||
return result
|
||||
|
||||
class SConsIndentedHelpFormatter(optparse.IndentedHelpFormatter):
|
||||
def format_usage(self, usage):
|
||||
return "usage: %s\n" % usage
|
||||
|
||||
def format_heading(self, heading):
|
||||
"""
|
||||
This translates any heading of "options" or "Options" into
|
||||
"SCons Options." Unfortunately, we have to do this here,
|
||||
because those titles are hard-coded in the optparse calls.
|
||||
"""
|
||||
if heading == 'Options':
|
||||
heading = "SCons Options"
|
||||
return optparse.IndentedHelpFormatter.format_heading(self, heading)
|
||||
|
||||
def format_option(self, option):
|
||||
"""
|
||||
A copy of the normal optparse.IndentedHelpFormatter.format_option()
|
||||
method. This has been snarfed so we can modify text wrapping to
|
||||
out liking:
|
||||
|
||||
-- add our own regular expression that doesn't break on hyphens
|
||||
(so things like --no-print-directory don't get broken);
|
||||
|
||||
-- wrap the list of options themselves when it's too long
|
||||
(the wrapper.fill(opts) call below);
|
||||
|
||||
-- set the subsequent_indent when wrapping the help_text.
|
||||
"""
|
||||
# The help for each option consists of two parts:
|
||||
# * the opt strings and metavars
|
||||
# eg. ("-x", or "-fFILENAME, --file=FILENAME")
|
||||
# * the user-supplied help string
|
||||
# eg. ("turn on expert mode", "read data from FILENAME")
|
||||
#
|
||||
# If possible, we write both of these on the same line:
|
||||
# -x turn on expert mode
|
||||
#
|
||||
# But if the opt string list is too long, we put the help
|
||||
# string on a second line, indented to the same column it would
|
||||
# start in if it fit on the first line.
|
||||
# -fFILENAME, --file=FILENAME
|
||||
# read data from FILENAME
|
||||
result = []
|
||||
|
||||
opts = self.option_strings[option]
|
||||
opt_width = self.help_position - self.current_indent - 2
|
||||
if len(opts) > opt_width:
|
||||
wrapper = textwrap.TextWrapper(width=self.width,
|
||||
initial_indent = ' ',
|
||||
subsequent_indent = ' ')
|
||||
wrapper.wordsep_re = no_hyphen_re
|
||||
opts = wrapper.fill(opts) + '\n'
|
||||
indent_first = self.help_position
|
||||
else: # start help on same line as opts
|
||||
opts = "%*s%-*s " % (self.current_indent, "", opt_width, opts)
|
||||
indent_first = 0
|
||||
result.append(opts)
|
||||
if option.help:
|
||||
|
||||
help_text = self.expand_default(option)
|
||||
|
||||
# SCons: indent every line of the help text but the first.
|
||||
wrapper = textwrap.TextWrapper(width=self.help_width,
|
||||
subsequent_indent = ' ')
|
||||
wrapper.wordsep_re = no_hyphen_re
|
||||
help_lines = wrapper.wrap(help_text)
|
||||
result.append("%*s%s\n" % (indent_first, "", help_lines[0]))
|
||||
for line in help_lines[1:]:
|
||||
result.append("%*s%s\n" % (self.help_position, "", line))
|
||||
elif opts[-1] != "\n":
|
||||
result.append("\n")
|
||||
return "".join(result)
|
||||
|
||||
def Parser(version):
|
||||
"""
|
||||
Returns an options parser object initialized with the standard
|
||||
SCons options.
|
||||
"""
|
||||
|
||||
formatter = SConsIndentedHelpFormatter(max_help_position=30)
|
||||
|
||||
op = SConsOptionParser(option_class=SConsOption,
|
||||
add_help_option=False,
|
||||
formatter=formatter,
|
||||
usage="usage: scons [OPTION] [TARGET] ...",)
|
||||
|
||||
op.preserve_unknown_options = True
|
||||
op.version = version
|
||||
|
||||
# Add the options to the parser we just created.
|
||||
#
|
||||
# These are in the order we want them to show up in the -H help
|
||||
# text, basically alphabetical. Each op.add_option() call below
|
||||
# should have a consistent format:
|
||||
#
|
||||
# op.add_option("-L", "--long-option-name",
|
||||
# nargs=1, type="string",
|
||||
# dest="long_option_name", default='foo',
|
||||
# action="callback", callback=opt_long_option,
|
||||
# help="help text goes here",
|
||||
# metavar="VAR")
|
||||
#
|
||||
# Even though the optparse module constructs reasonable default
|
||||
# destination names from the long option names, we're going to be
|
||||
# explicit about each one for easier readability and so this code
|
||||
# will at least show up when grepping the source for option attribute
|
||||
# names, or otherwise browsing the source code.
|
||||
|
||||
# options ignored for compatibility
|
||||
def opt_ignore(option, opt, value, parser):
|
||||
sys.stderr.write("Warning: ignoring %s option\n" % opt)
|
||||
op.add_option("-b", "-d", "-e", "-m", "-S", "-t", "-w",
|
||||
"--environment-overrides",
|
||||
"--no-keep-going",
|
||||
"--no-print-directory",
|
||||
"--print-directory",
|
||||
"--stop",
|
||||
"--touch",
|
||||
action="callback", callback=opt_ignore,
|
||||
help="Ignored for compatibility.")
|
||||
|
||||
op.add_option('-c', '--clean', '--remove',
|
||||
dest="clean", default=False,
|
||||
action="store_true",
|
||||
help="Remove specified targets and dependencies.")
|
||||
|
||||
op.add_option('-C', '--directory',
|
||||
nargs=1, type="string",
|
||||
dest="directory", default=[],
|
||||
action="append",
|
||||
help="Change to DIR before doing anything.",
|
||||
metavar="DIR")
|
||||
|
||||
op.add_option('--cache-debug',
|
||||
nargs=1,
|
||||
dest="cache_debug", default=None,
|
||||
action="store",
|
||||
help="Print CacheDir debug info to FILE.",
|
||||
metavar="FILE")
|
||||
|
||||
op.add_option('--cache-disable', '--no-cache',
|
||||
dest='cache_disable', default=False,
|
||||
action="store_true",
|
||||
help="Do not retrieve built targets from CacheDir.")
|
||||
|
||||
op.add_option('--cache-force', '--cache-populate',
|
||||
dest='cache_force', default=False,
|
||||
action="store_true",
|
||||
help="Copy already-built targets into the CacheDir.")
|
||||
|
||||
op.add_option('--cache-readonly',
|
||||
dest='cache_readonly', default=False,
|
||||
action="store_true",
|
||||
help="Do not update CacheDir with built targets.")
|
||||
|
||||
op.add_option('--cache-show',
|
||||
dest='cache_show', default=False,
|
||||
action="store_true",
|
||||
help="Print build actions for files from CacheDir.")
|
||||
|
||||
def opt_invalid(group, value, options):
|
||||
"""report an invalid option from a group"""
|
||||
errmsg = "`%s' is not a valid %s option type, try:\n" % (value, group)
|
||||
return errmsg + " %s" % ", ".join(options)
|
||||
|
||||
def opt_invalid_rm(group, value, msg):
|
||||
"""report an invalid option from a group: recognized but removed"""
|
||||
errmsg = "`%s' is not a valid %s option type " % (value, group)
|
||||
return errmsg + msg
|
||||
|
||||
config_options = ["auto", "force" ,"cache"]
|
||||
|
||||
opt_config_help = "Controls Configure subsystem: %s." \
|
||||
% ", ".join(config_options)
|
||||
|
||||
op.add_option('--config',
|
||||
nargs=1, choices=config_options,
|
||||
dest="config", default="auto",
|
||||
help = opt_config_help,
|
||||
metavar="MODE")
|
||||
|
||||
op.add_option('-D',
|
||||
dest="climb_up", default=None,
|
||||
action="store_const", const=2,
|
||||
help="Search up directory tree for SConstruct, "
|
||||
"build all Default() targets.")
|
||||
|
||||
deprecated_debug_options = {}
|
||||
|
||||
removed_debug_options = {
|
||||
"dtree" : '; please use --tree=derived instead',
|
||||
"nomemoizer" : '; there is no replacement',
|
||||
"stree" : '; please use --tree=all,status instead',
|
||||
"tree" : '; please use --tree=all instead',
|
||||
}
|
||||
|
||||
debug_options = ["count", "duplicate", "explain", "findlibs",
|
||||
"includes", "memoizer", "memory", "objects",
|
||||
"pdb", "prepare", "presub", "stacktrace",
|
||||
"time", "action-timestamps"]
|
||||
|
||||
def opt_debug(option, opt, value__, parser,
|
||||
debug_options=debug_options,
|
||||
deprecated_debug_options=deprecated_debug_options,
|
||||
removed_debug_options=removed_debug_options):
|
||||
for value in value__.split(','):
|
||||
if value in debug_options:
|
||||
parser.values.debug.append(value)
|
||||
elif value in deprecated_debug_options:
|
||||
parser.values.debug.append(value)
|
||||
try:
|
||||
parser.values.delayed_warnings
|
||||
except AttributeError:
|
||||
parser.values.delayed_warnings = []
|
||||
msg = deprecated_debug_options[value]
|
||||
w = "The --debug=%s option is deprecated%s." % (value, msg)
|
||||
t = (SCons.Warnings.DeprecatedDebugOptionsWarning, w)
|
||||
parser.values.delayed_warnings.append(t)
|
||||
elif value in removed_debug_options:
|
||||
msg = removed_debug_options[value]
|
||||
raise OptionValueError(opt_invalid_rm('debug', value, msg))
|
||||
else:
|
||||
raise OptionValueError(opt_invalid('debug', value, debug_options))
|
||||
|
||||
opt_debug_help = "Print various types of debugging information: %s." \
|
||||
% ", ".join(debug_options)
|
||||
op.add_option('--debug',
|
||||
nargs=1, type="string",
|
||||
dest="debug", default=[],
|
||||
action="callback", callback=opt_debug,
|
||||
help=opt_debug_help,
|
||||
metavar="TYPE")
|
||||
|
||||
def opt_diskcheck(option, opt, value, parser):
|
||||
try:
|
||||
diskcheck_value = diskcheck_convert(value)
|
||||
except ValueError as e:
|
||||
raise OptionValueError("`%s' is not a valid diskcheck type" % e)
|
||||
setattr(parser.values, option.dest, diskcheck_value)
|
||||
|
||||
op.add_option('--diskcheck',
|
||||
nargs=1, type="string",
|
||||
dest='diskcheck', default=None,
|
||||
action="callback", callback=opt_diskcheck,
|
||||
help="Enable specific on-disk checks.",
|
||||
metavar="TYPE")
|
||||
|
||||
def opt_duplicate(option, opt, value, parser):
|
||||
if value not in SCons.Node.FS.Valid_Duplicates:
|
||||
raise OptionValueError(opt_invalid('duplication', value,
|
||||
SCons.Node.FS.Valid_Duplicates))
|
||||
setattr(parser.values, option.dest, value)
|
||||
# Set the duplicate style right away so it can affect linking
|
||||
# of SConscript files.
|
||||
SCons.Node.FS.set_duplicate(value)
|
||||
|
||||
opt_duplicate_help = "Set the preferred duplication methods. Must be one of " \
|
||||
+ ", ".join(SCons.Node.FS.Valid_Duplicates)
|
||||
|
||||
op.add_option('--duplicate',
|
||||
nargs=1, type="string",
|
||||
dest="duplicate", default='hard-soft-copy',
|
||||
action="callback", callback=opt_duplicate,
|
||||
help=opt_duplicate_help)
|
||||
|
||||
if not SCons.Platform.virtualenv.virtualenv_enabled_by_default:
|
||||
op.add_option('--enable-virtualenv',
|
||||
dest="enable_virtualenv",
|
||||
action="store_true",
|
||||
help="Import certain virtualenv variables to SCons")
|
||||
|
||||
op.add_option('-f', '--file', '--makefile', '--sconstruct',
|
||||
nargs=1, type="string",
|
||||
dest="file", default=[],
|
||||
action="append",
|
||||
help="Read FILE as the top-level SConstruct file.")
|
||||
|
||||
op.add_option('-h', '--help',
|
||||
dest="help", default=False,
|
||||
action="store_true",
|
||||
help="Print defined help message, or this one.")
|
||||
|
||||
op.add_option("-H", "--help-options",
|
||||
action="help",
|
||||
help="Print this message and exit.")
|
||||
|
||||
op.add_option('-i', '--ignore-errors',
|
||||
dest='ignore_errors', default=False,
|
||||
action="store_true",
|
||||
help="Ignore errors from build actions.")
|
||||
|
||||
op.add_option('-I', '--include-dir',
|
||||
nargs=1,
|
||||
dest='include_dir', default=[],
|
||||
action="append",
|
||||
help="Search DIR for imported Python modules.",
|
||||
metavar="DIR")
|
||||
|
||||
op.add_option('--ignore-virtualenv',
|
||||
dest="ignore_virtualenv",
|
||||
action="store_true",
|
||||
help="Do not import virtualenv variables to SCons")
|
||||
|
||||
op.add_option('--implicit-cache',
|
||||
dest='implicit_cache', default=False,
|
||||
action="store_true",
|
||||
help="Cache implicit dependencies")
|
||||
|
||||
def opt_implicit_deps(option, opt, value, parser):
|
||||
setattr(parser.values, 'implicit_cache', True)
|
||||
setattr(parser.values, option.dest, True)
|
||||
|
||||
op.add_option('--implicit-deps-changed',
|
||||
dest="implicit_deps_changed", default=False,
|
||||
action="callback", callback=opt_implicit_deps,
|
||||
help="Ignore cached implicit dependencies.")
|
||||
|
||||
op.add_option('--implicit-deps-unchanged',
|
||||
dest="implicit_deps_unchanged", default=False,
|
||||
action="callback", callback=opt_implicit_deps,
|
||||
help="Ignore changes in implicit dependencies.")
|
||||
|
||||
op.add_option('--interact', '--interactive',
|
||||
dest='interactive', default=False,
|
||||
action="store_true",
|
||||
help="Run in interactive mode.")
|
||||
|
||||
op.add_option('-j', '--jobs',
|
||||
nargs=1, type="int",
|
||||
dest="num_jobs", default=1,
|
||||
action="store",
|
||||
help="Allow N jobs at once.",
|
||||
metavar="N")
|
||||
|
||||
op.add_option('-k', '--keep-going',
|
||||
dest='keep_going', default=False,
|
||||
action="store_true",
|
||||
help="Keep going when a target can't be made.")
|
||||
|
||||
op.add_option('--max-drift',
|
||||
nargs=1, type="int",
|
||||
dest='max_drift', default=SCons.Node.FS.default_max_drift,
|
||||
action="store",
|
||||
help="Set maximum system clock drift to N seconds.",
|
||||
metavar="N")
|
||||
|
||||
op.add_option('--md5-chunksize',
|
||||
nargs=1, type="int",
|
||||
dest='md5_chunksize', default=SCons.Node.FS.File.md5_chunksize,
|
||||
action="store",
|
||||
help="Set chunk-size for MD5 signature computation to N kilobytes.",
|
||||
metavar="N")
|
||||
|
||||
op.add_option('-n', '--no-exec', '--just-print', '--dry-run', '--recon',
|
||||
dest='no_exec', default=False,
|
||||
action="store_true",
|
||||
help="Don't build; just print commands.")
|
||||
|
||||
op.add_option('--no-site-dir',
|
||||
dest='no_site_dir', default=False,
|
||||
action="store_true",
|
||||
help="Don't search or use the usual site_scons dir.")
|
||||
|
||||
op.add_option('--profile',
|
||||
nargs=1,
|
||||
dest="profile_file", default=None,
|
||||
action="store",
|
||||
help="Profile SCons and put results in FILE.",
|
||||
metavar="FILE")
|
||||
|
||||
op.add_option('-q', '--question',
|
||||
dest="question", default=False,
|
||||
action="store_true",
|
||||
help="Don't build; exit status says if up to date.")
|
||||
|
||||
op.add_option('-Q',
|
||||
dest='no_progress', default=False,
|
||||
action="store_true",
|
||||
help="Suppress \"Reading/Building\" progress messages.")
|
||||
|
||||
op.add_option('--random',
|
||||
dest="random", default=False,
|
||||
action="store_true",
|
||||
help="Build dependencies in random order.")
|
||||
|
||||
op.add_option('-s', '--silent', '--quiet',
|
||||
dest="silent", default=False,
|
||||
action="store_true",
|
||||
help="Don't print commands.")
|
||||
|
||||
op.add_option('--site-dir',
|
||||
nargs=1,
|
||||
dest='site_dir', default=None,
|
||||
action="store",
|
||||
help="Use DIR instead of the usual site_scons dir.",
|
||||
metavar="DIR")
|
||||
|
||||
op.add_option('--stack-size',
|
||||
nargs=1, type="int",
|
||||
dest='stack_size',
|
||||
action="store",
|
||||
help="Set the stack size of the threads used to run jobs to N kilobytes.",
|
||||
metavar="N")
|
||||
|
||||
op.add_option('--taskmastertrace',
|
||||
nargs=1,
|
||||
dest="taskmastertrace_file", default=None,
|
||||
action="store",
|
||||
help="Trace Node evaluation to FILE.",
|
||||
metavar="FILE")
|
||||
|
||||
tree_options = ["all", "derived", "prune", "status", "linedraw"]
|
||||
|
||||
def opt_tree(option, opt, value, parser, tree_options=tree_options):
|
||||
from . import Main
|
||||
tp = Main.TreePrinter()
|
||||
for o in value.split(','):
|
||||
if o == 'all':
|
||||
tp.derived = False
|
||||
elif o == 'derived':
|
||||
tp.derived = True
|
||||
elif o == 'prune':
|
||||
tp.prune = True
|
||||
elif o == 'status':
|
||||
tp.status = True
|
||||
elif o == 'linedraw':
|
||||
tp.sLineDraw = True
|
||||
else:
|
||||
raise OptionValueError(opt_invalid('--tree', o, tree_options))
|
||||
parser.values.tree_printers.append(tp)
|
||||
|
||||
opt_tree_help = "Print a dependency tree in various formats: %s." \
|
||||
% ", ".join(tree_options)
|
||||
|
||||
op.add_option('--tree',
|
||||
nargs=1, type="string",
|
||||
dest="tree_printers", default=[],
|
||||
action="callback", callback=opt_tree,
|
||||
help=opt_tree_help,
|
||||
metavar="OPTIONS")
|
||||
|
||||
op.add_option('-u', '--up', '--search-up',
|
||||
dest="climb_up", default=0,
|
||||
action="store_const", const=1,
|
||||
help="Search up directory tree for SConstruct, "
|
||||
"build targets at or below current directory.")
|
||||
|
||||
op.add_option('-U',
|
||||
dest="climb_up", default=0,
|
||||
action="store_const", const=3,
|
||||
help="Search up directory tree for SConstruct, "
|
||||
"build Default() targets from local SConscript.")
|
||||
|
||||
def opt_version(option, opt, value, parser):
|
||||
sys.stdout.write(parser.version + '\n')
|
||||
sys.exit(0)
|
||||
op.add_option("-v", "--version",
|
||||
action="callback", callback=opt_version,
|
||||
help="Print the SCons version number and exit.")
|
||||
|
||||
def opt_warn(option, opt, value, parser, tree_options=tree_options):
|
||||
if SCons.Util.is_String(value):
|
||||
value = value.split(',')
|
||||
parser.values.warn.extend(value)
|
||||
|
||||
op.add_option('--warn', '--warning',
|
||||
nargs=1, type="string",
|
||||
dest="warn", default=[],
|
||||
action="callback", callback=opt_warn,
|
||||
help="Enable or disable warnings.",
|
||||
metavar="WARNING-SPEC")
|
||||
|
||||
op.add_option('-Y', '--repository', '--srcdir',
|
||||
nargs=1,
|
||||
dest="repository", default=[],
|
||||
action="append",
|
||||
help="Search REPOSITORY for source and target files.")
|
||||
|
||||
|
||||
# Options from Make and Cons classic that we do not yet support,
|
||||
# but which we may support someday and whose (potential) meanings
|
||||
# we don't want to change. These all get a "the -X option is not
|
||||
# yet implemented" message and don't show up in the help output.
|
||||
|
||||
def opt_not_yet(option, opt, value, parser):
|
||||
msg = "Warning: the %s option is not yet implemented\n" % opt
|
||||
sys.stderr.write(msg)
|
||||
|
||||
op.add_option('-l', '--load-average', '--max-load',
|
||||
nargs=1, type="float",
|
||||
dest="load_average", default=0,
|
||||
action="callback", callback=opt_not_yet,
|
||||
# action="store",
|
||||
# help="Don't start multiple jobs unless load is below "
|
||||
# "LOAD-AVERAGE."
|
||||
help=SUPPRESS_HELP)
|
||||
op.add_option('--list-actions',
|
||||
dest="list_actions",
|
||||
action="callback", callback=opt_not_yet,
|
||||
# help="Don't build; list files and build actions."
|
||||
help=SUPPRESS_HELP)
|
||||
op.add_option('--list-derived',
|
||||
dest="list_derived",
|
||||
action="callback", callback=opt_not_yet,
|
||||
# help="Don't build; list files that would be built."
|
||||
help=SUPPRESS_HELP)
|
||||
op.add_option('--list-where',
|
||||
dest="list_where",
|
||||
action="callback", callback=opt_not_yet,
|
||||
# help="Don't build; list files and where defined."
|
||||
help=SUPPRESS_HELP)
|
||||
op.add_option('-o', '--old-file', '--assume-old',
|
||||
nargs=1, type="string",
|
||||
dest="old_file", default=[],
|
||||
action="callback", callback=opt_not_yet,
|
||||
# action="append",
|
||||
# help = "Consider FILE to be old; don't rebuild it."
|
||||
help=SUPPRESS_HELP)
|
||||
op.add_option('--override',
|
||||
nargs=1, type="string",
|
||||
action="callback", callback=opt_not_yet,
|
||||
dest="override",
|
||||
# help="Override variables as specified in FILE."
|
||||
help=SUPPRESS_HELP)
|
||||
op.add_option('-p',
|
||||
action="callback", callback=opt_not_yet,
|
||||
dest="p",
|
||||
# help="Print internal environments/objects."
|
||||
help=SUPPRESS_HELP)
|
||||
op.add_option('-r', '-R', '--no-builtin-rules', '--no-builtin-variables',
|
||||
action="callback", callback=opt_not_yet,
|
||||
dest="no_builtin_rules",
|
||||
# help="Clear default environments and variables."
|
||||
help=SUPPRESS_HELP)
|
||||
op.add_option('--write-filenames',
|
||||
nargs=1, type="string",
|
||||
dest="write_filenames",
|
||||
action="callback", callback=opt_not_yet,
|
||||
# help="Write all filenames examined into FILE."
|
||||
help=SUPPRESS_HELP)
|
||||
op.add_option('-W', '--new-file', '--assume-new', '--what-if',
|
||||
nargs=1, type="string",
|
||||
dest="new_file",
|
||||
action="callback", callback=opt_not_yet,
|
||||
# help="Consider FILE to be changed."
|
||||
help=SUPPRESS_HELP)
|
||||
op.add_option('--warn-undefined-variables',
|
||||
dest="warn_undefined_variables",
|
||||
action="callback", callback=opt_not_yet,
|
||||
# help="Warn when an undefined variable is referenced."
|
||||
help=SUPPRESS_HELP)
|
||||
return op
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
687
scons/scons-local-4.0.1/SCons/Script/SConscript.py
Normal file
687
scons/scons-local-4.0.1/SCons/Script/SConscript.py
Normal file
|
@ -0,0 +1,687 @@
|
|||
"""SCons.Script.SConscript
|
||||
|
||||
This module defines the Python API provided to SConscript and SConstruct
|
||||
files.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import SCons
|
||||
import SCons.Action
|
||||
import SCons.Builder
|
||||
import SCons.Defaults
|
||||
import SCons.Environment
|
||||
import SCons.Errors
|
||||
import SCons.Node
|
||||
import SCons.Node.Alias
|
||||
import SCons.Node.FS
|
||||
import SCons.Platform
|
||||
import SCons.SConf
|
||||
import SCons.Script.Main
|
||||
import SCons.Tool
|
||||
from SCons.Util import is_List, is_String, is_Dict, flatten
|
||||
from SCons.Node import SConscriptNodes
|
||||
from . import Main
|
||||
|
||||
import collections
|
||||
import os
|
||||
import os.path
|
||||
import re
|
||||
import sys
|
||||
import traceback
|
||||
import time
|
||||
|
||||
class SConscriptReturn(Exception):
|
||||
pass
|
||||
|
||||
launch_dir = os.path.abspath(os.curdir)
|
||||
|
||||
GlobalDict = None
|
||||
|
||||
# global exports set by Export():
|
||||
global_exports = {}
|
||||
|
||||
# chdir flag
|
||||
sconscript_chdir = 1
|
||||
|
||||
def get_calling_namespaces():
|
||||
"""Return the locals and globals for the function that called
|
||||
into this module in the current call stack."""
|
||||
try: 1//0
|
||||
except ZeroDivisionError:
|
||||
# Don't start iterating with the current stack-frame to
|
||||
# prevent creating reference cycles (f_back is safe).
|
||||
frame = sys.exc_info()[2].tb_frame.f_back
|
||||
|
||||
# Find the first frame that *isn't* from this file. This means
|
||||
# that we expect all of the SCons frames that implement an Export()
|
||||
# or SConscript() call to be in this file, so that we can identify
|
||||
# the first non-Script.SConscript frame as the user's local calling
|
||||
# environment, and the locals and globals dictionaries from that
|
||||
# frame as the calling namespaces. See the comment below preceding
|
||||
# the DefaultEnvironmentCall block for even more explanation.
|
||||
while frame.f_globals.get("__name__") == __name__:
|
||||
frame = frame.f_back
|
||||
|
||||
return frame.f_locals, frame.f_globals
|
||||
|
||||
|
||||
def compute_exports(exports):
|
||||
"""Compute a dictionary of exports given one of the parameters
|
||||
to the Export() function or the exports argument to SConscript()."""
|
||||
|
||||
loc, glob = get_calling_namespaces()
|
||||
|
||||
retval = {}
|
||||
try:
|
||||
for export in exports:
|
||||
if is_Dict(export):
|
||||
retval.update(export)
|
||||
else:
|
||||
try:
|
||||
retval[export] = loc[export]
|
||||
except KeyError:
|
||||
retval[export] = glob[export]
|
||||
except KeyError as x:
|
||||
raise SCons.Errors.UserError("Export of non-existent variable '%s'"%x)
|
||||
|
||||
return retval
|
||||
|
||||
class Frame:
|
||||
"""A frame on the SConstruct/SConscript call stack"""
|
||||
def __init__(self, fs, exports, sconscript):
|
||||
self.globals = BuildDefaultGlobals()
|
||||
self.retval = None
|
||||
self.prev_dir = fs.getcwd()
|
||||
self.exports = compute_exports(exports) # exports from the calling SConscript
|
||||
# make sure the sconscript attr is a Node.
|
||||
if isinstance(sconscript, SCons.Node.Node):
|
||||
self.sconscript = sconscript
|
||||
elif sconscript == '-':
|
||||
self.sconscript = None
|
||||
else:
|
||||
self.sconscript = fs.File(str(sconscript))
|
||||
|
||||
# the SConstruct/SConscript call stack:
|
||||
call_stack = []
|
||||
|
||||
# For documentation on the methods in this file, see the scons man-page
|
||||
|
||||
def Return(*vars, **kw):
|
||||
retval = []
|
||||
try:
|
||||
fvars = flatten(vars)
|
||||
for var in fvars:
|
||||
for v in var.split():
|
||||
retval.append(call_stack[-1].globals[v])
|
||||
except KeyError as x:
|
||||
raise SCons.Errors.UserError("Return of non-existent variable '%s'"%x)
|
||||
|
||||
if len(retval) == 1:
|
||||
call_stack[-1].retval = retval[0]
|
||||
else:
|
||||
call_stack[-1].retval = tuple(retval)
|
||||
|
||||
stop = kw.get('stop', True)
|
||||
|
||||
if stop:
|
||||
raise SConscriptReturn
|
||||
|
||||
|
||||
stack_bottom = '% Stack boTTom %' # hard to define a variable w/this name :)
|
||||
|
||||
def handle_missing_SConscript(f, must_exist=None):
|
||||
"""Take appropriate action on missing file in SConscript() call.
|
||||
|
||||
Print a warning or raise an exception on missing file.
|
||||
On first warning, print a deprecation message.
|
||||
|
||||
Args:
|
||||
f (str): path of missing configuration file
|
||||
must_exist (bool): raise exception if file does not exist
|
||||
|
||||
Raises:
|
||||
UserError if 'must_exist' is True or if global
|
||||
SCons.Script._no_missing_sconscript is True.
|
||||
"""
|
||||
|
||||
if must_exist or (SCons.Script._no_missing_sconscript and must_exist is not False):
|
||||
msg = "Fatal: missing SConscript '%s'" % f.get_internal_path()
|
||||
raise SCons.Errors.UserError(msg)
|
||||
|
||||
if SCons.Script._warn_missing_sconscript_deprecated:
|
||||
msg = "Calling missing SConscript without error is deprecated.\n" + \
|
||||
"Transition by adding must_exist=0 to SConscript calls.\n" + \
|
||||
"Missing SConscript '%s'" % f.get_internal_path()
|
||||
SCons.Warnings.warn(SCons.Warnings.MissingSConscriptWarning, msg)
|
||||
SCons.Script._warn_missing_sconscript_deprecated = False
|
||||
else:
|
||||
msg = "Ignoring missing SConscript '%s'" % f.get_internal_path()
|
||||
SCons.Warnings.warn(SCons.Warnings.MissingSConscriptWarning, msg)
|
||||
|
||||
def _SConscript(fs, *files, **kw):
|
||||
top = fs.Top
|
||||
sd = fs.SConstruct_dir.rdir()
|
||||
exports = kw.get('exports', [])
|
||||
|
||||
# evaluate each SConscript file
|
||||
results = []
|
||||
for fn in files:
|
||||
call_stack.append(Frame(fs, exports, fn))
|
||||
old_sys_path = sys.path
|
||||
try:
|
||||
SCons.Script.sconscript_reading = SCons.Script.sconscript_reading + 1
|
||||
if fn == "-":
|
||||
exec(sys.stdin.read(), call_stack[-1].globals)
|
||||
else:
|
||||
if isinstance(fn, SCons.Node.Node):
|
||||
f = fn
|
||||
else:
|
||||
f = fs.File(str(fn))
|
||||
_file_ = None
|
||||
SConscriptNodes.add(f)
|
||||
|
||||
# Change directory to the top of the source
|
||||
# tree to make sure the os's cwd and the cwd of
|
||||
# fs match so we can open the SConscript.
|
||||
fs.chdir(top, change_os_dir=1)
|
||||
if f.rexists():
|
||||
actual = f.rfile()
|
||||
_file_ = open(actual.get_abspath(), "rb")
|
||||
elif f.srcnode().rexists():
|
||||
actual = f.srcnode().rfile()
|
||||
_file_ = open(actual.get_abspath(), "rb")
|
||||
elif f.has_src_builder():
|
||||
# The SConscript file apparently exists in a source
|
||||
# code management system. Build it, but then clear
|
||||
# the builder so that it doesn't get built *again*
|
||||
# during the actual build phase.
|
||||
f.build()
|
||||
f.built()
|
||||
f.builder_set(None)
|
||||
if f.exists():
|
||||
_file_ = open(f.get_abspath(), "rb")
|
||||
if _file_:
|
||||
# Chdir to the SConscript directory. Use a path
|
||||
# name relative to the SConstruct file so that if
|
||||
# we're using the -f option, we're essentially
|
||||
# creating a parallel SConscript directory structure
|
||||
# in our local directory tree.
|
||||
#
|
||||
# XXX This is broken for multiple-repository cases
|
||||
# where the SConstruct and SConscript files might be
|
||||
# in different Repositories. For now, cross that
|
||||
# bridge when someone comes to it.
|
||||
try:
|
||||
src_dir = kw['src_dir']
|
||||
except KeyError:
|
||||
ldir = fs.Dir(f.dir.get_path(sd))
|
||||
else:
|
||||
ldir = fs.Dir(src_dir)
|
||||
if not ldir.is_under(f.dir):
|
||||
# They specified a source directory, but
|
||||
# it's above the SConscript directory.
|
||||
# Do the sensible thing and just use the
|
||||
# SConcript directory.
|
||||
ldir = fs.Dir(f.dir.get_path(sd))
|
||||
try:
|
||||
fs.chdir(ldir, change_os_dir=sconscript_chdir)
|
||||
except OSError:
|
||||
# There was no local directory, so we should be
|
||||
# able to chdir to the Repository directory.
|
||||
# Note that we do this directly, not through
|
||||
# fs.chdir(), because we still need to
|
||||
# interpret the stuff within the SConscript file
|
||||
# relative to where we are logically.
|
||||
fs.chdir(ldir, change_os_dir=0)
|
||||
os.chdir(actual.dir.get_abspath())
|
||||
|
||||
# Append the SConscript directory to the beginning
|
||||
# of sys.path so Python modules in the SConscript
|
||||
# directory can be easily imported.
|
||||
sys.path = [ f.dir.get_abspath() ] + sys.path
|
||||
|
||||
# This is the magic line that actually reads up
|
||||
# and executes the stuff in the SConscript file.
|
||||
# The locals for this frame contain the special
|
||||
# bottom-of-the-stack marker so that any
|
||||
# exceptions that occur when processing this
|
||||
# SConscript can base the printed frames at this
|
||||
# level and not show SCons internals as well.
|
||||
call_stack[-1].globals.update({stack_bottom:1})
|
||||
old_file = call_stack[-1].globals.get('__file__')
|
||||
try:
|
||||
del call_stack[-1].globals['__file__']
|
||||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
try:
|
||||
if Main.print_time:
|
||||
time1 = time.time()
|
||||
scriptdata = _file_.read()
|
||||
scriptname = _file_.name
|
||||
_file_.close()
|
||||
exec(compile(scriptdata, scriptname, 'exec'), call_stack[-1].globals)
|
||||
except SConscriptReturn:
|
||||
pass
|
||||
finally:
|
||||
if Main.print_time:
|
||||
time2 = time.time()
|
||||
print('SConscript:%s took %0.3f ms' % (f.get_abspath(), (time2 - time1) * 1000.0))
|
||||
|
||||
if old_file is not None:
|
||||
call_stack[-1].globals.update({__file__:old_file})
|
||||
else:
|
||||
handle_missing_SConscript(f, kw.get('must_exist', None))
|
||||
|
||||
finally:
|
||||
SCons.Script.sconscript_reading = SCons.Script.sconscript_reading - 1
|
||||
sys.path = old_sys_path
|
||||
frame = call_stack.pop()
|
||||
try:
|
||||
fs.chdir(frame.prev_dir, change_os_dir=sconscript_chdir)
|
||||
except OSError:
|
||||
# There was no local directory, so chdir to the
|
||||
# Repository directory. Like above, we do this
|
||||
# directly.
|
||||
fs.chdir(frame.prev_dir, change_os_dir=0)
|
||||
rdir = frame.prev_dir.rdir()
|
||||
rdir._create() # Make sure there's a directory there.
|
||||
try:
|
||||
os.chdir(rdir.get_abspath())
|
||||
except OSError as e:
|
||||
# We still couldn't chdir there, so raise the error,
|
||||
# but only if actions are being executed.
|
||||
#
|
||||
# If the -n option was used, the directory would *not*
|
||||
# have been created and we should just carry on and
|
||||
# let things muddle through. This isn't guaranteed
|
||||
# to work if the SConscript files are reading things
|
||||
# from disk (for example), but it should work well
|
||||
# enough for most configurations.
|
||||
if SCons.Action.execute_actions:
|
||||
raise e
|
||||
|
||||
results.append(frame.retval)
|
||||
|
||||
# if we only have one script, don't return a tuple
|
||||
if len(results) == 1:
|
||||
return results[0]
|
||||
else:
|
||||
return tuple(results)
|
||||
|
||||
def SConscript_exception(file=sys.stderr):
|
||||
"""Print an exception stack trace just for the SConscript file(s).
|
||||
This will show users who have Python errors where the problem is,
|
||||
without cluttering the output with all of the internal calls leading
|
||||
up to where we exec the SConscript."""
|
||||
exc_type, exc_value, exc_tb = sys.exc_info()
|
||||
tb = exc_tb
|
||||
while tb and stack_bottom not in tb.tb_frame.f_locals:
|
||||
tb = tb.tb_next
|
||||
if not tb:
|
||||
# We did not find our exec statement, so this was actually a bug
|
||||
# in SCons itself. Show the whole stack.
|
||||
tb = exc_tb
|
||||
stack = traceback.extract_tb(tb)
|
||||
try:
|
||||
type = exc_type.__name__
|
||||
except AttributeError:
|
||||
type = str(exc_type)
|
||||
if type[:11] == "exceptions.":
|
||||
type = type[11:]
|
||||
file.write('%s: %s:\n' % (type, exc_value))
|
||||
for fname, line, func, text in stack:
|
||||
file.write(' File "%s", line %d:\n' % (fname, line))
|
||||
file.write(' %s\n' % text)
|
||||
|
||||
def annotate(node):
|
||||
"""Annotate a node with the stack frame describing the
|
||||
SConscript file and line number that created it."""
|
||||
tb = sys.exc_info()[2]
|
||||
while tb and stack_bottom not in tb.tb_frame.f_locals:
|
||||
tb = tb.tb_next
|
||||
if not tb:
|
||||
# We did not find any exec of an SConscript file: what?!
|
||||
raise SCons.Errors.InternalError("could not find SConscript stack frame")
|
||||
node.creator = traceback.extract_stack(tb)[0]
|
||||
|
||||
# The following line would cause each Node to be annotated using the
|
||||
# above function. Unfortunately, this is a *huge* performance hit, so
|
||||
# leave this disabled until we find a more efficient mechanism.
|
||||
#SCons.Node.Annotate = annotate
|
||||
|
||||
class SConsEnvironment(SCons.Environment.Base):
|
||||
"""An Environment subclass that contains all of the methods that
|
||||
are particular to the wrapper SCons interface and which aren't
|
||||
(or shouldn't be) part of the build engine itself.
|
||||
|
||||
Note that not all of the methods of this class have corresponding
|
||||
global functions, there are some private methods.
|
||||
"""
|
||||
|
||||
#
|
||||
# Private methods of an SConsEnvironment.
|
||||
#
|
||||
def _exceeds_version(self, major, minor, v_major, v_minor):
|
||||
"""Return 1 if 'major' and 'minor' are greater than the version
|
||||
in 'v_major' and 'v_minor', and 0 otherwise."""
|
||||
return (major > v_major or (major == v_major and minor > v_minor))
|
||||
|
||||
def _get_major_minor_revision(self, version_string):
|
||||
"""Split a version string into major, minor and (optionally)
|
||||
revision parts.
|
||||
|
||||
This is complicated by the fact that a version string can be
|
||||
something like 3.2b1."""
|
||||
version = version_string.split(' ')[0].split('.')
|
||||
v_major = int(version[0])
|
||||
v_minor = int(re.match(r'\d+', version[1]).group())
|
||||
if len(version) >= 3:
|
||||
v_revision = int(re.match(r'\d+', version[2]).group())
|
||||
else:
|
||||
v_revision = 0
|
||||
return v_major, v_minor, v_revision
|
||||
|
||||
def _get_SConscript_filenames(self, ls, kw):
|
||||
"""
|
||||
Convert the parameters passed to SConscript() calls into a list
|
||||
of files and export variables. If the parameters are invalid,
|
||||
throws SCons.Errors.UserError. Returns a tuple (l, e) where l
|
||||
is a list of SConscript filenames and e is a list of exports.
|
||||
"""
|
||||
exports = []
|
||||
|
||||
if len(ls) == 0:
|
||||
try:
|
||||
dirs = kw["dirs"]
|
||||
except KeyError:
|
||||
raise SCons.Errors.UserError("Invalid SConscript usage - no parameters")
|
||||
|
||||
if not is_List(dirs):
|
||||
dirs = [ dirs ]
|
||||
dirs = list(map(str, dirs))
|
||||
|
||||
name = kw.get('name', 'SConscript')
|
||||
|
||||
files = [os.path.join(n, name) for n in dirs]
|
||||
|
||||
elif len(ls) == 1:
|
||||
|
||||
files = ls[0]
|
||||
|
||||
elif len(ls) == 2:
|
||||
|
||||
files = ls[0]
|
||||
exports = self.Split(ls[1])
|
||||
|
||||
else:
|
||||
|
||||
raise SCons.Errors.UserError("Invalid SConscript() usage - too many arguments")
|
||||
|
||||
if not is_List(files):
|
||||
files = [ files ]
|
||||
|
||||
if kw.get('exports'):
|
||||
exports.extend(self.Split(kw['exports']))
|
||||
|
||||
variant_dir = kw.get('variant_dir')
|
||||
if variant_dir:
|
||||
if len(files) != 1:
|
||||
raise SCons.Errors.UserError("Invalid SConscript() usage - can only specify one SConscript with a variant_dir")
|
||||
duplicate = kw.get('duplicate', 1)
|
||||
src_dir = kw.get('src_dir')
|
||||
if not src_dir:
|
||||
src_dir, fname = os.path.split(str(files[0]))
|
||||
files = [os.path.join(str(variant_dir), fname)]
|
||||
else:
|
||||
if not isinstance(src_dir, SCons.Node.Node):
|
||||
src_dir = self.fs.Dir(src_dir)
|
||||
fn = files[0]
|
||||
if not isinstance(fn, SCons.Node.Node):
|
||||
fn = self.fs.File(fn)
|
||||
if fn.is_under(src_dir):
|
||||
# Get path relative to the source directory.
|
||||
fname = fn.get_path(src_dir)
|
||||
files = [os.path.join(str(variant_dir), fname)]
|
||||
else:
|
||||
files = [fn.get_abspath()]
|
||||
kw['src_dir'] = variant_dir
|
||||
self.fs.VariantDir(variant_dir, src_dir, duplicate)
|
||||
|
||||
return (files, exports)
|
||||
|
||||
#
|
||||
# Public methods of an SConsEnvironment. These get
|
||||
# entry points in the global namespace so they can be called
|
||||
# as global functions.
|
||||
#
|
||||
|
||||
def Configure(self, *args, **kw):
|
||||
if not SCons.Script.sconscript_reading:
|
||||
raise SCons.Errors.UserError("Calling Configure from Builders is not supported.")
|
||||
kw['_depth'] = kw.get('_depth', 0) + 1
|
||||
return SCons.Environment.Base.Configure(self, *args, **kw)
|
||||
|
||||
def Default(self, *targets):
|
||||
SCons.Script._Set_Default_Targets(self, targets)
|
||||
|
||||
def EnsureSConsVersion(self, major, minor, revision=0):
|
||||
"""Exit abnormally if the SCons version is not late enough."""
|
||||
# split string to avoid replacement during build process
|
||||
if SCons.__version__ == '__' + 'VERSION__':
|
||||
SCons.Warnings.warn(SCons.Warnings.DevelopmentVersionWarning,
|
||||
"EnsureSConsVersion is ignored for development version")
|
||||
return
|
||||
scons_ver = self._get_major_minor_revision(SCons.__version__)
|
||||
if scons_ver < (major, minor, revision):
|
||||
if revision:
|
||||
scons_ver_string = '%d.%d.%d' % (major, minor, revision)
|
||||
else:
|
||||
scons_ver_string = '%d.%d' % (major, minor)
|
||||
print("SCons %s or greater required, but you have SCons %s" % \
|
||||
(scons_ver_string, SCons.__version__))
|
||||
sys.exit(2)
|
||||
|
||||
def EnsurePythonVersion(self, major, minor):
|
||||
"""Exit abnormally if the Python version is not late enough."""
|
||||
if sys.version_info < (major, minor):
|
||||
v = sys.version.split()[0]
|
||||
print("Python %d.%d or greater required, but you have Python %s" %(major,minor,v))
|
||||
sys.exit(2)
|
||||
|
||||
def Exit(self, value=0):
|
||||
sys.exit(value)
|
||||
|
||||
def Export(self, *vars, **kw):
|
||||
for var in vars:
|
||||
global_exports.update(compute_exports(self.Split(var)))
|
||||
global_exports.update(kw)
|
||||
|
||||
def GetLaunchDir(self):
|
||||
global launch_dir
|
||||
return launch_dir
|
||||
|
||||
def GetOption(self, name):
|
||||
name = self.subst(name)
|
||||
return SCons.Script.Main.GetOption(name)
|
||||
|
||||
def Help(self, text, append=False):
|
||||
text = self.subst(text, raw=1)
|
||||
SCons.Script.HelpFunction(text, append=append)
|
||||
|
||||
def Import(self, *vars):
|
||||
try:
|
||||
frame = call_stack[-1]
|
||||
globals = frame.globals
|
||||
exports = frame.exports
|
||||
for var in vars:
|
||||
var = self.Split(var)
|
||||
for v in var:
|
||||
if v == '*':
|
||||
globals.update(global_exports)
|
||||
globals.update(exports)
|
||||
else:
|
||||
if v in exports:
|
||||
globals[v] = exports[v]
|
||||
else:
|
||||
globals[v] = global_exports[v]
|
||||
except KeyError as x:
|
||||
raise SCons.Errors.UserError("Import of non-existent variable '%s'"%x)
|
||||
|
||||
def SConscript(self, *ls, **kw):
|
||||
"""Execute SCons configuration files.
|
||||
|
||||
Parameters:
|
||||
*ls (str or list): configuration file(s) to execute.
|
||||
|
||||
Keyword arguments:
|
||||
dirs (list): execute SConscript in each listed directory.
|
||||
name (str): execute script 'name' (used only with 'dirs').
|
||||
exports (list or dict): locally export variables the
|
||||
called script(s) can import.
|
||||
variant_dir (str): mirror sources needed for the build in
|
||||
a variant directory to allow building in it.
|
||||
duplicate (bool): physically duplicate sources instead of just
|
||||
adjusting paths of derived files (used only with 'variant_dir')
|
||||
(default is True).
|
||||
must_exist (bool): fail if a requested script is missing
|
||||
(default is False, default is deprecated).
|
||||
|
||||
Returns:
|
||||
list of variables returned by the called script
|
||||
|
||||
Raises:
|
||||
UserError: a script is not found and such exceptions are enabled.
|
||||
"""
|
||||
|
||||
def subst_element(x, subst=self.subst):
|
||||
if SCons.Util.is_List(x):
|
||||
x = list(map(subst, x))
|
||||
else:
|
||||
x = subst(x)
|
||||
return x
|
||||
ls = list(map(subst_element, ls))
|
||||
subst_kw = {}
|
||||
for key, val in kw.items():
|
||||
if is_String(val):
|
||||
val = self.subst(val)
|
||||
elif SCons.Util.is_List(val):
|
||||
val = [self.subst(v) if is_String(v) else v for v in val]
|
||||
subst_kw[key] = val
|
||||
|
||||
files, exports = self._get_SConscript_filenames(ls, subst_kw)
|
||||
subst_kw['exports'] = exports
|
||||
return _SConscript(self.fs, *files, **subst_kw)
|
||||
|
||||
def SConscriptChdir(self, flag):
|
||||
global sconscript_chdir
|
||||
sconscript_chdir = flag
|
||||
|
||||
def SetOption(self, name, value):
|
||||
name = self.subst(name)
|
||||
SCons.Script.Main.SetOption(name, value)
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
SCons.Environment.Environment = SConsEnvironment
|
||||
|
||||
def Configure(*args, **kw):
|
||||
if not SCons.Script.sconscript_reading:
|
||||
raise SCons.Errors.UserError("Calling Configure from Builders is not supported.")
|
||||
kw['_depth'] = 1
|
||||
return SCons.SConf.SConf(*args, **kw)
|
||||
|
||||
# It's very important that the DefaultEnvironmentCall() class stay in this
|
||||
# file, with the get_calling_namespaces() function, the compute_exports()
|
||||
# function, the Frame class and the SConsEnvironment.Export() method.
|
||||
# These things make up the calling stack leading up to the actual global
|
||||
# Export() or SConscript() call that the user issued. We want to allow
|
||||
# users to export local variables that they define, like so:
|
||||
#
|
||||
# def func():
|
||||
# x = 1
|
||||
# Export('x')
|
||||
#
|
||||
# To support this, the get_calling_namespaces() function assumes that
|
||||
# the *first* stack frame that's not from this file is the local frame
|
||||
# for the Export() or SConscript() call.
|
||||
|
||||
_DefaultEnvironmentProxy = None
|
||||
|
||||
def get_DefaultEnvironmentProxy():
|
||||
global _DefaultEnvironmentProxy
|
||||
if not _DefaultEnvironmentProxy:
|
||||
default_env = SCons.Defaults.DefaultEnvironment()
|
||||
_DefaultEnvironmentProxy = SCons.Environment.NoSubstitutionProxy(default_env)
|
||||
return _DefaultEnvironmentProxy
|
||||
|
||||
class DefaultEnvironmentCall:
|
||||
"""A class that implements "global function" calls of
|
||||
Environment methods by fetching the specified method from the
|
||||
DefaultEnvironment's class. Note that this uses an intermediate
|
||||
proxy class instead of calling the DefaultEnvironment method
|
||||
directly so that the proxy can override the subst() method and
|
||||
thereby prevent expansion of construction variables (since from
|
||||
the user's point of view this was called as a global function,
|
||||
with no associated construction environment)."""
|
||||
def __init__(self, method_name, subst=0):
|
||||
self.method_name = method_name
|
||||
if subst:
|
||||
self.factory = SCons.Defaults.DefaultEnvironment
|
||||
else:
|
||||
self.factory = get_DefaultEnvironmentProxy
|
||||
def __call__(self, *args, **kw):
|
||||
env = self.factory()
|
||||
method = getattr(env, self.method_name)
|
||||
return method(*args, **kw)
|
||||
|
||||
|
||||
def BuildDefaultGlobals():
|
||||
"""
|
||||
Create a dictionary containing all the default globals for
|
||||
SConstruct and SConscript files.
|
||||
"""
|
||||
|
||||
global GlobalDict
|
||||
if GlobalDict is None:
|
||||
GlobalDict = {}
|
||||
|
||||
import SCons.Script
|
||||
d = SCons.Script.__dict__
|
||||
def not_a_module(m, d=d, mtype=type(SCons.Script)):
|
||||
return not isinstance(d[m], mtype)
|
||||
for m in filter(not_a_module, dir(SCons.Script)):
|
||||
GlobalDict[m] = d[m]
|
||||
|
||||
return GlobalDict.copy()
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
430
scons/scons-local-4.0.1/SCons/Script/__init__.py
Normal file
430
scons/scons-local-4.0.1/SCons/Script/__init__.py
Normal file
|
@ -0,0 +1,430 @@
|
|||
"""SCons.Script
|
||||
|
||||
This file implements the main() function used by the scons script.
|
||||
|
||||
Architecturally, this *is* the scons script, and will likely only be
|
||||
called from the external "scons" wrapper. Consequently, anything here
|
||||
should not be, or be considered, part of the build engine. If it's
|
||||
something that we expect other software to want to use, it should go in
|
||||
some other module. If it's specific to the "scons" script invocation,
|
||||
it goes here.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import time
|
||||
start_time = time.time()
|
||||
|
||||
import collections
|
||||
import os
|
||||
|
||||
try:
|
||||
from StringIO import StringIO
|
||||
except ImportError:
|
||||
from io import StringIO
|
||||
|
||||
import sys
|
||||
|
||||
# Special chicken-and-egg handling of the "--debug=memoizer" flag:
|
||||
#
|
||||
# SCons.Memoize contains a metaclass implementation that affects how
|
||||
# the other classes are instantiated. The Memoizer may add shim methods
|
||||
# to classes that have methods that cache computed values in order to
|
||||
# count and report the hits and misses.
|
||||
#
|
||||
# If we wait to enable the Memoization until after we've parsed the
|
||||
# command line options normally, it will be too late, because the Memoizer
|
||||
# will have already analyzed the classes that it's Memoizing and decided
|
||||
# to not add the shims. So we use a special-case, up-front check for
|
||||
# the "--debug=memoizer" flag and enable Memoizer before we import any
|
||||
# of the other modules that use it.
|
||||
|
||||
_args = sys.argv + os.environ.get('SCONSFLAGS', '').split()
|
||||
if "--debug=memoizer" in _args:
|
||||
import SCons.Memoize
|
||||
import SCons.Warnings
|
||||
try:
|
||||
SCons.Memoize.EnableMemoization()
|
||||
except SCons.Warnings.Warning:
|
||||
# Some warning was thrown. Arrange for it to be displayed
|
||||
# or not after warnings are configured.
|
||||
from . import Main
|
||||
exc_type, exc_value, tb = sys.exc_info()
|
||||
Main.delayed_warnings.append((exc_type, exc_value))
|
||||
del _args
|
||||
|
||||
import SCons.Action
|
||||
import SCons.Builder
|
||||
import SCons.Environment
|
||||
import SCons.Node.FS
|
||||
import SCons.Platform
|
||||
import SCons.Platform.virtualenv
|
||||
import SCons.Scanner
|
||||
import SCons.SConf
|
||||
import SCons.Subst
|
||||
import SCons.Tool
|
||||
import SCons.Util
|
||||
import SCons.Variables
|
||||
import SCons.Defaults
|
||||
|
||||
from . import Main
|
||||
|
||||
main = Main.main
|
||||
|
||||
# The following are global class definitions and variables that used to
|
||||
# live directly in this module back before 0.96.90, when it contained
|
||||
# a lot of code. Some SConscript files in widely-distributed packages
|
||||
# (Blender is the specific example) actually reached into SCons.Script
|
||||
# directly to use some of these. Rather than break those SConscript
|
||||
# files, we're going to propagate these names into the SCons.Script
|
||||
# namespace here.
|
||||
#
|
||||
# Some of these are commented out because it's *really* unlikely anyone
|
||||
# used them, but we're going to leave the comment here to try to make
|
||||
# it obvious what to do if the situation arises.
|
||||
BuildTask = Main.BuildTask
|
||||
CleanTask = Main.CleanTask
|
||||
QuestionTask = Main.QuestionTask
|
||||
#PrintHelp = Main.PrintHelp
|
||||
#SConscriptSettableOptions = Main.SConscriptSettableOptions
|
||||
|
||||
AddOption = Main.AddOption
|
||||
PrintHelp = Main.PrintHelp
|
||||
GetOption = Main.GetOption
|
||||
SetOption = Main.SetOption
|
||||
Progress = Main.Progress
|
||||
GetBuildFailures = Main.GetBuildFailures
|
||||
|
||||
#keep_going_on_error = Main.keep_going_on_error
|
||||
#print_dtree = Main.print_dtree
|
||||
#print_explanations = Main.print_explanations
|
||||
#print_includes = Main.print_includes
|
||||
#print_objects = Main.print_objects
|
||||
#print_time = Main.print_time
|
||||
#print_tree = Main.print_tree
|
||||
#memory_stats = Main.memory_stats
|
||||
#ignore_errors = Main.ignore_errors
|
||||
#sconscript_time = Main.sconscript_time
|
||||
#command_time = Main.command_time
|
||||
#exit_status = Main.exit_status
|
||||
#profiling = Main.profiling
|
||||
#repositories = Main.repositories
|
||||
|
||||
#
|
||||
from . import SConscript
|
||||
_SConscript = SConscript
|
||||
|
||||
call_stack = _SConscript.call_stack
|
||||
|
||||
#
|
||||
Action = SCons.Action.Action
|
||||
AddMethod = SCons.Util.AddMethod
|
||||
AllowSubstExceptions = SCons.Subst.SetAllowableExceptions
|
||||
Builder = SCons.Builder.Builder
|
||||
Configure = _SConscript.Configure
|
||||
Environment = SCons.Environment.Environment
|
||||
#OptParser = SCons.SConsOptions.OptParser
|
||||
FindPathDirs = SCons.Scanner.FindPathDirs
|
||||
Platform = SCons.Platform.Platform
|
||||
Virtualenv = SCons.Platform.virtualenv.Virtualenv
|
||||
Return = _SConscript.Return
|
||||
Scanner = SCons.Scanner.Base
|
||||
Tool = SCons.Tool.Tool
|
||||
WhereIs = SCons.Util.WhereIs
|
||||
|
||||
#
|
||||
BoolVariable = SCons.Variables.BoolVariable
|
||||
EnumVariable = SCons.Variables.EnumVariable
|
||||
ListVariable = SCons.Variables.ListVariable
|
||||
PackageVariable = SCons.Variables.PackageVariable
|
||||
PathVariable = SCons.Variables.PathVariable
|
||||
|
||||
|
||||
# Action factories.
|
||||
Chmod = SCons.Defaults.Chmod
|
||||
Copy = SCons.Defaults.Copy
|
||||
Delete = SCons.Defaults.Delete
|
||||
Mkdir = SCons.Defaults.Mkdir
|
||||
Move = SCons.Defaults.Move
|
||||
Touch = SCons.Defaults.Touch
|
||||
|
||||
# Pre-made, public scanners.
|
||||
CScanner = SCons.Tool.CScanner
|
||||
DScanner = SCons.Tool.DScanner
|
||||
DirScanner = SCons.Defaults.DirScanner
|
||||
ProgramScanner = SCons.Tool.ProgramScanner
|
||||
SourceFileScanner = SCons.Tool.SourceFileScanner
|
||||
|
||||
# Functions we might still convert to Environment methods.
|
||||
CScan = SCons.Defaults.CScan
|
||||
DefaultEnvironment = SCons.Defaults.DefaultEnvironment
|
||||
|
||||
# Other variables we provide.
|
||||
class TargetList(collections.UserList):
|
||||
def _do_nothing(self, *args, **kw):
|
||||
pass
|
||||
def _add_Default(self, list):
|
||||
self.extend(list)
|
||||
def _clear(self):
|
||||
del self[:]
|
||||
|
||||
ARGUMENTS = {}
|
||||
ARGLIST = []
|
||||
BUILD_TARGETS = TargetList()
|
||||
COMMAND_LINE_TARGETS = []
|
||||
DEFAULT_TARGETS = []
|
||||
|
||||
# BUILD_TARGETS can be modified in the SConscript files. If so, we
|
||||
# want to treat the modified BUILD_TARGETS list as if they specified
|
||||
# targets on the command line. To do that, though, we need to know if
|
||||
# BUILD_TARGETS was modified through "official" APIs or by hand. We do
|
||||
# this by updating two lists in parallel, the documented BUILD_TARGETS
|
||||
# list, above, and this internal _build_plus_default targets list which
|
||||
# should only have "official" API changes. Then Script/Main.py can
|
||||
# compare these two afterwards to figure out if the user added their
|
||||
# own targets to BUILD_TARGETS.
|
||||
_build_plus_default = TargetList()
|
||||
|
||||
def _Add_Arguments(alist):
|
||||
for arg in alist:
|
||||
a, b = arg.split('=', 1)
|
||||
ARGUMENTS[a] = b
|
||||
ARGLIST.append((a, b))
|
||||
|
||||
def _Add_Targets(tlist):
|
||||
if tlist:
|
||||
COMMAND_LINE_TARGETS.extend(tlist)
|
||||
BUILD_TARGETS.extend(tlist)
|
||||
BUILD_TARGETS._add_Default = BUILD_TARGETS._do_nothing
|
||||
BUILD_TARGETS._clear = BUILD_TARGETS._do_nothing
|
||||
_build_plus_default.extend(tlist)
|
||||
_build_plus_default._add_Default = _build_plus_default._do_nothing
|
||||
_build_plus_default._clear = _build_plus_default._do_nothing
|
||||
|
||||
def _Set_Default_Targets_Has_Been_Called(d, fs):
|
||||
return DEFAULT_TARGETS
|
||||
|
||||
def _Set_Default_Targets_Has_Not_Been_Called(d, fs):
|
||||
if d is None:
|
||||
d = [fs.Dir('.')]
|
||||
return d
|
||||
|
||||
_Get_Default_Targets = _Set_Default_Targets_Has_Not_Been_Called
|
||||
|
||||
def _Set_Default_Targets(env, tlist):
|
||||
global DEFAULT_TARGETS
|
||||
global _Get_Default_Targets
|
||||
_Get_Default_Targets = _Set_Default_Targets_Has_Been_Called
|
||||
for t in tlist:
|
||||
if t is None:
|
||||
# Delete the elements from the list in-place, don't
|
||||
# reassign an empty list to DEFAULT_TARGETS, so that the
|
||||
# variables will still point to the same object we point to.
|
||||
del DEFAULT_TARGETS[:]
|
||||
BUILD_TARGETS._clear()
|
||||
_build_plus_default._clear()
|
||||
elif isinstance(t, SCons.Node.Node):
|
||||
DEFAULT_TARGETS.append(t)
|
||||
BUILD_TARGETS._add_Default([t])
|
||||
_build_plus_default._add_Default([t])
|
||||
else:
|
||||
nodes = env.arg2nodes(t, env.fs.Entry)
|
||||
DEFAULT_TARGETS.extend(nodes)
|
||||
BUILD_TARGETS._add_Default(nodes)
|
||||
_build_plus_default._add_Default(nodes)
|
||||
|
||||
#
|
||||
help_text = None
|
||||
|
||||
def HelpFunction(text, append=False):
|
||||
global help_text
|
||||
if help_text is None:
|
||||
if append:
|
||||
s = StringIO()
|
||||
PrintHelp(s)
|
||||
help_text = s.getvalue()
|
||||
s.close()
|
||||
else:
|
||||
help_text = ""
|
||||
|
||||
help_text= help_text + text
|
||||
|
||||
|
||||
#
|
||||
# Will be non-zero if we are reading an SConscript file.
|
||||
sconscript_reading = 0
|
||||
|
||||
_no_missing_sconscript = False
|
||||
_warn_missing_sconscript_deprecated = True
|
||||
|
||||
def set_missing_sconscript_error(flag=1):
|
||||
"""Set behavior on missing file in SConscript() call. Returns previous value"""
|
||||
global _no_missing_sconscript
|
||||
old = _no_missing_sconscript
|
||||
_no_missing_sconscript = flag
|
||||
return old
|
||||
|
||||
|
||||
def Variables(files=None, args=ARGUMENTS):
|
||||
return SCons.Variables.Variables(files, args)
|
||||
|
||||
|
||||
# The list of global functions to add to the SConscript name space
|
||||
# that end up calling corresponding methods or Builders in the
|
||||
# DefaultEnvironment().
|
||||
GlobalDefaultEnvironmentFunctions = [
|
||||
# Methods from the SConsEnvironment class, above.
|
||||
'Default',
|
||||
'EnsurePythonVersion',
|
||||
'EnsureSConsVersion',
|
||||
'Exit',
|
||||
'Export',
|
||||
'GetLaunchDir',
|
||||
'Help',
|
||||
'Import',
|
||||
#'SConscript', is handled separately, below.
|
||||
'SConscriptChdir',
|
||||
|
||||
# Methods from the Environment.Base class.
|
||||
'AddPostAction',
|
||||
'AddPreAction',
|
||||
'Alias',
|
||||
'AlwaysBuild',
|
||||
'CacheDir',
|
||||
'Clean',
|
||||
#The Command() method is handled separately, below.
|
||||
'Decider',
|
||||
'Depends',
|
||||
'Dir',
|
||||
'NoClean',
|
||||
'NoCache',
|
||||
'Entry',
|
||||
'Execute',
|
||||
'File',
|
||||
'FindFile',
|
||||
'FindInstalledFiles',
|
||||
'FindSourceFiles',
|
||||
'Flatten',
|
||||
'GetBuildPath',
|
||||
'Glob',
|
||||
'Ignore',
|
||||
'Install',
|
||||
'InstallAs',
|
||||
'InstallVersionedLib',
|
||||
'Literal',
|
||||
'Local',
|
||||
'ParseDepends',
|
||||
'Precious',
|
||||
'PyPackageDir',
|
||||
'Repository',
|
||||
'Requires',
|
||||
'SConsignFile',
|
||||
'SideEffect',
|
||||
'Split',
|
||||
'Tag',
|
||||
'Value',
|
||||
'VariantDir',
|
||||
]
|
||||
|
||||
GlobalDefaultBuilders = [
|
||||
# Supported builders.
|
||||
'CFile',
|
||||
'CXXFile',
|
||||
'DVI',
|
||||
'Jar',
|
||||
'Java',
|
||||
'JavaH',
|
||||
'Library',
|
||||
'LoadableModule',
|
||||
'M4',
|
||||
'MSVSProject',
|
||||
'Object',
|
||||
'PCH',
|
||||
'PDF',
|
||||
'PostScript',
|
||||
'Program',
|
||||
'RES',
|
||||
'RMIC',
|
||||
'SharedLibrary',
|
||||
'SharedObject',
|
||||
'StaticLibrary',
|
||||
'StaticObject',
|
||||
'Substfile',
|
||||
'Tar',
|
||||
'Textfile',
|
||||
'TypeLibrary',
|
||||
'Zip',
|
||||
'Package',
|
||||
]
|
||||
|
||||
for name in GlobalDefaultEnvironmentFunctions + GlobalDefaultBuilders:
|
||||
exec ("%s = _SConscript.DefaultEnvironmentCall(%s)" % (name, repr(name)))
|
||||
del name
|
||||
|
||||
# There are a handful of variables that used to live in the
|
||||
# Script/SConscript.py module that some SConscript files out there were
|
||||
# accessing directly as SCons.Script.SConscript.*. The problem is that
|
||||
# "SConscript" in this namespace is no longer a module, it's a global
|
||||
# function call--or more precisely, an object that implements a global
|
||||
# function call through the default Environment. Nevertheless, we can
|
||||
# maintain backwards compatibility for SConscripts that were reaching in
|
||||
# this way by hanging some attributes off the "SConscript" object here.
|
||||
SConscript = _SConscript.DefaultEnvironmentCall('SConscript')
|
||||
|
||||
# Make SConscript look enough like the module it used to be so
|
||||
# that pychecker doesn't barf.
|
||||
SConscript.__name__ = 'SConscript'
|
||||
|
||||
SConscript.Arguments = ARGUMENTS
|
||||
SConscript.ArgList = ARGLIST
|
||||
SConscript.BuildTargets = BUILD_TARGETS
|
||||
SConscript.CommandLineTargets = COMMAND_LINE_TARGETS
|
||||
SConscript.DefaultTargets = DEFAULT_TARGETS
|
||||
|
||||
# The global Command() function must be handled differently than the
|
||||
# global functions for other construction environment methods because
|
||||
# we want people to be able to use Actions that must expand $TARGET
|
||||
# and $SOURCE later, when (and if) the Action is invoked to build
|
||||
# the target(s). We do this with the subst=1 argument, which creates
|
||||
# a DefaultEnvironmentCall instance that wraps up a normal default
|
||||
# construction environment that performs variable substitution, not a
|
||||
# proxy that doesn't.
|
||||
#
|
||||
# There's a flaw here, though, because any other $-variables on a command
|
||||
# line will *also* be expanded, each to a null string, but that should
|
||||
# only be a problem in the unusual case where someone was passing a '$'
|
||||
# on a command line and *expected* the $ to get through to the shell
|
||||
# because they were calling Command() and not env.Command()... This is
|
||||
# unlikely enough that we're going to leave this as is and cross that
|
||||
# bridge if someone actually comes to it.
|
||||
Command = _SConscript.DefaultEnvironmentCall('Command', subst=1)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
976
scons/scons-local-4.0.1/SCons/Subst.py
Normal file
976
scons/scons-local-4.0.1/SCons/Subst.py
Normal file
|
@ -0,0 +1,976 @@
|
|||
"""SCons.Subst
|
||||
|
||||
SCons string substitution.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import collections
|
||||
import re
|
||||
from inspect import signature
|
||||
import SCons.Errors
|
||||
|
||||
from SCons.Util import is_String, is_Sequence
|
||||
|
||||
# Indexed by the SUBST_* constants below.
|
||||
_strconv = [SCons.Util.to_String_for_subst,
|
||||
SCons.Util.to_String_for_subst,
|
||||
SCons.Util.to_String_for_signature]
|
||||
|
||||
|
||||
|
||||
AllowableExceptions = (IndexError, NameError)
|
||||
|
||||
def SetAllowableExceptions(*excepts):
|
||||
global AllowableExceptions
|
||||
AllowableExceptions = [_f for _f in excepts if _f]
|
||||
|
||||
def raise_exception(exception, target, s):
|
||||
name = exception.__class__.__name__
|
||||
msg = "%s `%s' trying to evaluate `%s'" % (name, exception, s)
|
||||
if target:
|
||||
raise SCons.Errors.BuildError(target[0], msg)
|
||||
else:
|
||||
raise SCons.Errors.UserError(msg)
|
||||
|
||||
|
||||
|
||||
class Literal:
|
||||
"""A wrapper for a string. If you use this object wrapped
|
||||
around a string, then it will be interpreted as literal.
|
||||
When passed to the command interpreter, all special
|
||||
characters will be escaped."""
|
||||
def __init__(self, lstr):
|
||||
self.lstr = lstr
|
||||
|
||||
def __str__(self):
|
||||
return self.lstr
|
||||
|
||||
def escape(self, escape_func):
|
||||
return escape_func(self.lstr)
|
||||
|
||||
def for_signature(self):
|
||||
return self.lstr
|
||||
|
||||
def is_literal(self):
|
||||
return 1
|
||||
|
||||
def __eq__(self, other):
|
||||
if not isinstance(other, Literal):
|
||||
return False
|
||||
return self.lstr == other.lstr
|
||||
|
||||
def __neq__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.lstr)
|
||||
|
||||
class SpecialAttrWrapper:
|
||||
"""This is a wrapper for what we call a 'Node special attribute.'
|
||||
This is any of the attributes of a Node that we can reference from
|
||||
Environment variable substitution, such as $TARGET.abspath or
|
||||
$SOURCES[1].filebase. We implement the same methods as Literal
|
||||
so we can handle special characters, plus a for_signature method,
|
||||
such that we can return some canonical string during signature
|
||||
calculation to avoid unnecessary rebuilds."""
|
||||
|
||||
def __init__(self, lstr, for_signature=None):
|
||||
"""The for_signature parameter, if supplied, will be the
|
||||
canonical string we return from for_signature(). Else
|
||||
we will simply return lstr."""
|
||||
self.lstr = lstr
|
||||
if for_signature:
|
||||
self.forsig = for_signature
|
||||
else:
|
||||
self.forsig = lstr
|
||||
|
||||
def __str__(self):
|
||||
return self.lstr
|
||||
|
||||
def escape(self, escape_func):
|
||||
return escape_func(self.lstr)
|
||||
|
||||
def for_signature(self):
|
||||
return self.forsig
|
||||
|
||||
def is_literal(self):
|
||||
return 1
|
||||
|
||||
def quote_spaces(arg):
|
||||
"""Generic function for putting double quotes around any string that
|
||||
has white space in it."""
|
||||
if ' ' in arg or '\t' in arg:
|
||||
return '"%s"' % arg
|
||||
else:
|
||||
return str(arg)
|
||||
|
||||
class CmdStringHolder(collections.UserString):
|
||||
"""This is a special class used to hold strings generated by
|
||||
scons_subst() and scons_subst_list(). It defines a special method
|
||||
escape(). When passed a function with an escape algorithm for a
|
||||
particular platform, it will return the contained string with the
|
||||
proper escape sequences inserted.
|
||||
"""
|
||||
def __init__(self, cmd, literal=None):
|
||||
collections.UserString.__init__(self, cmd)
|
||||
self.literal = literal
|
||||
|
||||
def is_literal(self):
|
||||
return self.literal
|
||||
|
||||
def escape(self, escape_func, quote_func=quote_spaces):
|
||||
"""Escape the string with the supplied function. The
|
||||
function is expected to take an arbitrary string, then
|
||||
return it with all special characters escaped and ready
|
||||
for passing to the command interpreter.
|
||||
|
||||
After calling this function, the next call to str() will
|
||||
return the escaped string.
|
||||
"""
|
||||
|
||||
if self.is_literal():
|
||||
return escape_func(self.data)
|
||||
elif ' ' in self.data or '\t' in self.data:
|
||||
return quote_func(self.data)
|
||||
else:
|
||||
return self.data
|
||||
|
||||
def escape_list(mylist, escape_func):
|
||||
"""Escape a list of arguments by running the specified escape_func
|
||||
on every object in the list that has an escape() method."""
|
||||
def escape(obj, escape_func=escape_func):
|
||||
try:
|
||||
e = obj.escape
|
||||
except AttributeError:
|
||||
return obj
|
||||
else:
|
||||
return e(escape_func)
|
||||
return list(map(escape, mylist))
|
||||
|
||||
class NLWrapper:
|
||||
"""A wrapper class that delays turning a list of sources or targets
|
||||
into a NodeList until it's needed. The specified function supplied
|
||||
when the object is initialized is responsible for turning raw nodes
|
||||
into proxies that implement the special attributes like .abspath,
|
||||
.source, etc. This way, we avoid creating those proxies just
|
||||
"in case" someone is going to use $TARGET or the like, and only
|
||||
go through the trouble if we really have to.
|
||||
|
||||
In practice, this might be a wash performance-wise, but it's a little
|
||||
cleaner conceptually...
|
||||
"""
|
||||
|
||||
def __init__(self, list, func):
|
||||
self.list = list
|
||||
self.func = func
|
||||
def _return_nodelist(self):
|
||||
return self.nodelist
|
||||
def _gen_nodelist(self):
|
||||
mylist = self.list
|
||||
if mylist is None:
|
||||
mylist = []
|
||||
elif not is_Sequence(mylist):
|
||||
mylist = [mylist]
|
||||
# The map(self.func) call is what actually turns
|
||||
# a list into appropriate proxies.
|
||||
self.nodelist = SCons.Util.NodeList(list(map(self.func, mylist)))
|
||||
self._create_nodelist = self._return_nodelist
|
||||
return self.nodelist
|
||||
_create_nodelist = _gen_nodelist
|
||||
|
||||
|
||||
class Targets_or_Sources(collections.UserList):
|
||||
"""A class that implements $TARGETS or $SOURCES expansions by in turn
|
||||
wrapping a NLWrapper. This class handles the different methods used
|
||||
to access the list, calling the NLWrapper to create proxies on demand.
|
||||
|
||||
Note that we subclass collections.UserList purely so that the
|
||||
is_Sequence() function will identify an object of this class as
|
||||
a list during variable expansion. We're not really using any
|
||||
collections.UserList methods in practice.
|
||||
"""
|
||||
def __init__(self, nl):
|
||||
self.nl = nl
|
||||
def __getattr__(self, attr):
|
||||
nl = self.nl._create_nodelist()
|
||||
return getattr(nl, attr)
|
||||
def __getitem__(self, i):
|
||||
nl = self.nl._create_nodelist()
|
||||
return nl[i]
|
||||
def __getslice__(self, i, j):
|
||||
nl = self.nl._create_nodelist()
|
||||
i = max(i, 0); j = max(j, 0)
|
||||
return nl[i:j]
|
||||
def __str__(self):
|
||||
nl = self.nl._create_nodelist()
|
||||
return str(nl)
|
||||
def __repr__(self):
|
||||
nl = self.nl._create_nodelist()
|
||||
return repr(nl)
|
||||
|
||||
class Target_or_Source:
|
||||
"""A class that implements $TARGET or $SOURCE expansions by in turn
|
||||
wrapping a NLWrapper. This class handles the different methods used
|
||||
to access an individual proxy Node, calling the NLWrapper to create
|
||||
a proxy on demand.
|
||||
"""
|
||||
def __init__(self, nl):
|
||||
self.nl = nl
|
||||
def __getattr__(self, attr):
|
||||
nl = self.nl._create_nodelist()
|
||||
try:
|
||||
nl0 = nl[0]
|
||||
except IndexError:
|
||||
# If there is nothing in the list, then we have no attributes to
|
||||
# pass through, so raise AttributeError for everything.
|
||||
raise AttributeError("NodeList has no attribute: %s" % attr)
|
||||
return getattr(nl0, attr)
|
||||
def __str__(self):
|
||||
nl = self.nl._create_nodelist()
|
||||
if nl:
|
||||
return str(nl[0])
|
||||
return ''
|
||||
def __repr__(self):
|
||||
nl = self.nl._create_nodelist()
|
||||
if nl:
|
||||
return repr(nl[0])
|
||||
return ''
|
||||
|
||||
class NullNodeList(SCons.Util.NullSeq):
|
||||
def __call__(self, *args, **kwargs): return ''
|
||||
def __str__(self): return ''
|
||||
|
||||
NullNodesList = NullNodeList()
|
||||
|
||||
def subst_dict(target, source):
|
||||
"""Create a dictionary for substitution of special
|
||||
construction variables.
|
||||
|
||||
This translates the following special arguments:
|
||||
|
||||
target - the target (object or array of objects),
|
||||
used to generate the TARGET and TARGETS
|
||||
construction variables
|
||||
|
||||
source - the source (object or array of objects),
|
||||
used to generate the SOURCES and SOURCE
|
||||
construction variables
|
||||
"""
|
||||
dict = {}
|
||||
|
||||
if target:
|
||||
def get_tgt_subst_proxy(thing):
|
||||
try:
|
||||
subst_proxy = thing.get_subst_proxy()
|
||||
except AttributeError:
|
||||
subst_proxy = thing # probably a string, just return it
|
||||
return subst_proxy
|
||||
tnl = NLWrapper(target, get_tgt_subst_proxy)
|
||||
dict['TARGETS'] = Targets_or_Sources(tnl)
|
||||
dict['TARGET'] = Target_or_Source(tnl)
|
||||
|
||||
# This is a total cheat, but hopefully this dictionary goes
|
||||
# away soon anyway. We just let these expand to $TARGETS
|
||||
# because that's "good enough" for the use of ToolSurrogates
|
||||
# (see test/ToolSurrogate.py) to generate documentation.
|
||||
dict['CHANGED_TARGETS'] = '$TARGETS'
|
||||
dict['UNCHANGED_TARGETS'] = '$TARGETS'
|
||||
else:
|
||||
dict['TARGETS'] = NullNodesList
|
||||
dict['TARGET'] = NullNodesList
|
||||
|
||||
if source:
|
||||
def get_src_subst_proxy(node):
|
||||
try:
|
||||
rfile = node.rfile
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
node = rfile()
|
||||
try:
|
||||
return node.get_subst_proxy()
|
||||
except AttributeError:
|
||||
return node # probably a String, just return it
|
||||
snl = NLWrapper(source, get_src_subst_proxy)
|
||||
dict['SOURCES'] = Targets_or_Sources(snl)
|
||||
dict['SOURCE'] = Target_or_Source(snl)
|
||||
|
||||
# This is a total cheat, but hopefully this dictionary goes
|
||||
# away soon anyway. We just let these expand to $TARGETS
|
||||
# because that's "good enough" for the use of ToolSurrogates
|
||||
# (see test/ToolSurrogate.py) to generate documentation.
|
||||
dict['CHANGED_SOURCES'] = '$SOURCES'
|
||||
dict['UNCHANGED_SOURCES'] = '$SOURCES'
|
||||
else:
|
||||
dict['SOURCES'] = NullNodesList
|
||||
dict['SOURCE'] = NullNodesList
|
||||
|
||||
return dict
|
||||
|
||||
|
||||
class StringSubber:
|
||||
"""A class to construct the results of a scons_subst() call.
|
||||
|
||||
This binds a specific construction environment, mode, target and
|
||||
source with two methods (substitute() and expand()) that handle
|
||||
the expansion.
|
||||
"""
|
||||
def __init__(self, env, mode, conv, gvars):
|
||||
self.env = env
|
||||
self.mode = mode
|
||||
self.conv = conv
|
||||
self.gvars = gvars
|
||||
|
||||
def expand(self, s, lvars):
|
||||
"""Expand a single "token" as necessary, returning an
|
||||
appropriate string containing the expansion.
|
||||
|
||||
This handles expanding different types of things (strings,
|
||||
lists, callables) appropriately. It calls the wrapper
|
||||
substitute() method to re-expand things as necessary, so that
|
||||
the results of expansions of side-by-side strings still get
|
||||
re-evaluated separately, not smushed together.
|
||||
"""
|
||||
if is_String(s):
|
||||
try:
|
||||
s0, s1 = s[:2]
|
||||
except (IndexError, ValueError):
|
||||
return s
|
||||
if s0 != '$':
|
||||
return s
|
||||
if s1 == '$':
|
||||
# In this case keep the double $'s which we'll later
|
||||
# swap for a single dollar sign as we need to retain
|
||||
# this information to properly avoid matching "$("" when
|
||||
# the actual text was "$$("" (or "$)"" when "$$)"" )
|
||||
return '$$'
|
||||
elif s1 in '()':
|
||||
return s
|
||||
else:
|
||||
key = s[1:]
|
||||
if key[0] == '{' or '.' in key:
|
||||
if key[0] == '{':
|
||||
key = key[1:-1]
|
||||
|
||||
# Store for error messages if we fail to expand the
|
||||
# value
|
||||
old_s = s
|
||||
s = None
|
||||
if key in lvars:
|
||||
s = lvars[key]
|
||||
elif key in self.gvars:
|
||||
s = self.gvars[key]
|
||||
else:
|
||||
try:
|
||||
s = eval(key, self.gvars, lvars)
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except Exception as e:
|
||||
if e.__class__ in AllowableExceptions:
|
||||
return ''
|
||||
raise_exception(e, lvars['TARGETS'], old_s)
|
||||
|
||||
if s is None and NameError not in AllowableExceptions:
|
||||
raise_exception(NameError(key), lvars['TARGETS'], old_s)
|
||||
elif s is None:
|
||||
return ''
|
||||
|
||||
# Before re-expanding the result, handle
|
||||
# recursive expansion by copying the local
|
||||
# variable dictionary and overwriting a null
|
||||
# string for the value of the variable name
|
||||
# we just expanded.
|
||||
#
|
||||
# This could potentially be optimized by only
|
||||
# copying lvars when s contains more expansions,
|
||||
# but lvars is usually supposed to be pretty
|
||||
# small, and deeply nested variable expansions
|
||||
# are probably more the exception than the norm,
|
||||
# so it should be tolerable for now.
|
||||
lv = lvars.copy()
|
||||
var = key.split('.')[0]
|
||||
lv[var] = ''
|
||||
return self.substitute(s, lv)
|
||||
elif is_Sequence(s):
|
||||
def func(l, conv=self.conv, substitute=self.substitute, lvars=lvars):
|
||||
return conv(substitute(l, lvars))
|
||||
return list(map(func, s))
|
||||
elif callable(s):
|
||||
# SCons has the unusual Null class where any __getattr__ call returns it's self,
|
||||
# which does not work the signature module, and the Null class returns an empty
|
||||
# string if called on, so we make an exception in this condition for Null class
|
||||
if (isinstance(s, SCons.Util.Null) or
|
||||
set(signature(s).parameters.keys()) == set(['target', 'source', 'env', 'for_signature'])):
|
||||
s = s(target=lvars['TARGETS'],
|
||||
source=lvars['SOURCES'],
|
||||
env=self.env,
|
||||
for_signature=(self.mode != SUBST_CMD))
|
||||
else:
|
||||
# This probably indicates that it's a callable
|
||||
# object that doesn't match our calling arguments
|
||||
# (like an Action).
|
||||
if self.mode == SUBST_RAW:
|
||||
return s
|
||||
s = self.conv(s)
|
||||
return self.substitute(s, lvars)
|
||||
elif s is None:
|
||||
return ''
|
||||
else:
|
||||
return s
|
||||
|
||||
def substitute(self, args, lvars):
|
||||
"""Substitute expansions in an argument or list of arguments.
|
||||
|
||||
This serves as a wrapper for splitting up a string into
|
||||
separate tokens.
|
||||
"""
|
||||
if is_String(args) and not isinstance(args, CmdStringHolder):
|
||||
args = str(args) # In case it's a UserString.
|
||||
try:
|
||||
def sub_match(match):
|
||||
return self.conv(self.expand(match.group(1), lvars))
|
||||
result = _dollar_exps.sub(sub_match, args)
|
||||
except TypeError:
|
||||
# If the internal conversion routine doesn't return
|
||||
# strings (it could be overridden to return Nodes, for
|
||||
# example), then the 1.5.2 re module will throw this
|
||||
# exception. Back off to a slower, general-purpose
|
||||
# algorithm that works for all data types.
|
||||
args = _separate_args.findall(args)
|
||||
result = []
|
||||
for a in args:
|
||||
result.append(self.conv(self.expand(a, lvars)))
|
||||
if len(result) == 1:
|
||||
result = result[0]
|
||||
else:
|
||||
result = ''.join(map(str, result))
|
||||
return result
|
||||
else:
|
||||
return self.expand(args, lvars)
|
||||
|
||||
|
||||
class ListSubber(collections.UserList):
|
||||
"""A class to construct the results of a scons_subst_list() call.
|
||||
|
||||
Like StringSubber, this class binds a specific construction
|
||||
environment, mode, target and source with two methods
|
||||
(substitute() and expand()) that handle the expansion.
|
||||
|
||||
In addition, however, this class is used to track the state of
|
||||
the result(s) we're gathering so we can do the appropriate thing
|
||||
whenever we have to append another word to the result--start a new
|
||||
line, start a new word, append to the current word, etc. We do
|
||||
this by setting the "append" attribute to the right method so
|
||||
that our wrapper methods only need ever call ListSubber.append(),
|
||||
and the rest of the object takes care of doing the right thing
|
||||
internally.
|
||||
"""
|
||||
def __init__(self, env, mode, conv, gvars):
|
||||
collections.UserList.__init__(self, [])
|
||||
self.env = env
|
||||
self.mode = mode
|
||||
self.conv = conv
|
||||
self.gvars = gvars
|
||||
|
||||
if self.mode == SUBST_RAW:
|
||||
self.add_strip = lambda x: self.append(x)
|
||||
else:
|
||||
self.add_strip = lambda x: None
|
||||
self.in_strip = None
|
||||
self.next_line()
|
||||
|
||||
def expanded(self, s):
|
||||
"""Determines if the string s requires further expansion.
|
||||
|
||||
Due to the implementation of ListSubber expand will call
|
||||
itself 2 additional times for an already expanded string. This
|
||||
method is used to determine if a string is already fully
|
||||
expanded and if so exit the loop early to prevent these
|
||||
recursive calls.
|
||||
"""
|
||||
if not is_String(s) or isinstance(s, CmdStringHolder):
|
||||
return False
|
||||
|
||||
s = str(s) # in case it's a UserString
|
||||
return _separate_args.findall(s) is None
|
||||
|
||||
def expand(self, s, lvars, within_list):
|
||||
"""Expand a single "token" as necessary, appending the
|
||||
expansion to the current result.
|
||||
|
||||
This handles expanding different types of things (strings,
|
||||
lists, callables) appropriately. It calls the wrapper
|
||||
substitute() method to re-expand things as necessary, so that
|
||||
the results of expansions of side-by-side strings still get
|
||||
re-evaluated separately, not smushed together.
|
||||
"""
|
||||
|
||||
if is_String(s):
|
||||
try:
|
||||
s0, s1 = s[:2]
|
||||
except (IndexError, ValueError):
|
||||
self.append(s)
|
||||
return
|
||||
if s0 != '$':
|
||||
self.append(s)
|
||||
return
|
||||
if s1 == '$':
|
||||
self.append('$')
|
||||
elif s1 == '(':
|
||||
self.open_strip('$(')
|
||||
elif s1 == ')':
|
||||
self.close_strip('$)')
|
||||
else:
|
||||
key = s[1:]
|
||||
if key[0] == '{' or key.find('.') >= 0:
|
||||
if key[0] == '{':
|
||||
key = key[1:-1]
|
||||
|
||||
# Store for error messages if we fail to expand the
|
||||
# value
|
||||
old_s = s
|
||||
s = None
|
||||
if key in lvars:
|
||||
s = lvars[key]
|
||||
elif key in self.gvars:
|
||||
s = self.gvars[key]
|
||||
else:
|
||||
try:
|
||||
s = eval(key, self.gvars, lvars)
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
except Exception as e:
|
||||
if e.__class__ in AllowableExceptions:
|
||||
return
|
||||
raise_exception(e, lvars['TARGETS'], old_s)
|
||||
|
||||
if s is None and NameError not in AllowableExceptions:
|
||||
raise_exception(NameError(), lvars['TARGETS'], old_s)
|
||||
elif s is None:
|
||||
return
|
||||
|
||||
# If the string is already full expanded there's no
|
||||
# need to continue recursion.
|
||||
if self.expanded(s):
|
||||
self.append(s)
|
||||
return
|
||||
|
||||
# Before re-expanding the result, handle
|
||||
# recursive expansion by copying the local
|
||||
# variable dictionary and overwriting a null
|
||||
# string for the value of the variable name
|
||||
# we just expanded.
|
||||
lv = lvars.copy()
|
||||
var = key.split('.')[0]
|
||||
lv[var] = ''
|
||||
self.substitute(s, lv, 0)
|
||||
self.this_word()
|
||||
elif is_Sequence(s):
|
||||
for a in s:
|
||||
self.substitute(a, lvars, 1)
|
||||
self.next_word()
|
||||
elif callable(s):
|
||||
# SCons has the unusual Null class where any __getattr__ call returns it's self,
|
||||
# which does not work the signature module, and the Null class returns an empty
|
||||
# string if called on, so we make an exception in this condition for Null class
|
||||
if (isinstance(s, SCons.Util.Null) or
|
||||
set(signature(s).parameters.keys()) == set(['target', 'source', 'env', 'for_signature'])):
|
||||
s = s(target=lvars['TARGETS'],
|
||||
source=lvars['SOURCES'],
|
||||
env=self.env,
|
||||
for_signature=(self.mode != SUBST_CMD))
|
||||
else:
|
||||
# This probably indicates that it's a callable
|
||||
# object that doesn't match our calling arguments
|
||||
# (like an Action).
|
||||
if self.mode == SUBST_RAW:
|
||||
self.append(s)
|
||||
return
|
||||
s = self.conv(s)
|
||||
self.substitute(s, lvars, within_list)
|
||||
elif s is None:
|
||||
self.this_word()
|
||||
else:
|
||||
self.append(s)
|
||||
|
||||
def substitute(self, args, lvars, within_list):
|
||||
"""Substitute expansions in an argument or list of arguments.
|
||||
|
||||
This serves as a wrapper for splitting up a string into
|
||||
separate tokens.
|
||||
"""
|
||||
|
||||
if is_String(args) and not isinstance(args, CmdStringHolder):
|
||||
args = str(args) # In case it's a UserString.
|
||||
args = _separate_args.findall(args)
|
||||
for a in args:
|
||||
if a[0] in ' \t\n\r\f\v':
|
||||
if '\n' in a:
|
||||
self.next_line()
|
||||
elif within_list:
|
||||
self.append(a)
|
||||
else:
|
||||
self.next_word()
|
||||
else:
|
||||
self.expand(a, lvars, within_list)
|
||||
else:
|
||||
self.expand(args, lvars, within_list)
|
||||
|
||||
def next_line(self):
|
||||
"""Arrange for the next word to start a new line. This
|
||||
is like starting a new word, except that we have to append
|
||||
another line to the result."""
|
||||
collections.UserList.append(self, [])
|
||||
self.next_word()
|
||||
|
||||
def this_word(self):
|
||||
"""Arrange for the next word to append to the end of the
|
||||
current last word in the result."""
|
||||
self.append = self.add_to_current_word
|
||||
|
||||
def next_word(self):
|
||||
"""Arrange for the next word to start a new word."""
|
||||
self.append = self.add_new_word
|
||||
|
||||
def add_to_current_word(self, x):
|
||||
"""Append the string x to the end of the current last word
|
||||
in the result. If that is not possible, then just add
|
||||
it as a new word. Make sure the entire concatenated string
|
||||
inherits the object attributes of x (in particular, the
|
||||
escape function) by wrapping it as CmdStringHolder."""
|
||||
|
||||
if not self.in_strip or self.mode != SUBST_SIG:
|
||||
try:
|
||||
current_word = self[-1][-1]
|
||||
except IndexError:
|
||||
self.add_new_word(x)
|
||||
else:
|
||||
# All right, this is a hack and it should probably
|
||||
# be refactored out of existence in the future.
|
||||
# The issue is that we want to smoosh words together
|
||||
# and make one file name that gets escaped if
|
||||
# we're expanding something like foo$EXTENSION,
|
||||
# but we don't want to smoosh them together if
|
||||
# it's something like >$TARGET, because then we'll
|
||||
# treat the '>' like it's part of the file name.
|
||||
# So for now, just hard-code looking for the special
|
||||
# command-line redirection characters...
|
||||
try:
|
||||
last_char = str(current_word)[-1]
|
||||
except IndexError:
|
||||
last_char = '\0'
|
||||
if last_char in '<>|':
|
||||
self.add_new_word(x)
|
||||
else:
|
||||
y = current_word + x
|
||||
|
||||
# We used to treat a word appended to a literal
|
||||
# as a literal itself, but this caused problems
|
||||
# with interpreting quotes around space-separated
|
||||
# targets on command lines. Removing this makes
|
||||
# none of the "substantive" end-to-end tests fail,
|
||||
# so we'll take this out but leave it commented
|
||||
# for now in case there's a problem not covered
|
||||
# by the test cases and we need to resurrect this.
|
||||
#literal1 = self.literal(self[-1][-1])
|
||||
#literal2 = self.literal(x)
|
||||
y = self.conv(y)
|
||||
if is_String(y):
|
||||
#y = CmdStringHolder(y, literal1 or literal2)
|
||||
y = CmdStringHolder(y, None)
|
||||
self[-1][-1] = y
|
||||
|
||||
def add_new_word(self, x):
|
||||
if not self.in_strip or self.mode != SUBST_SIG:
|
||||
literal = self.literal(x)
|
||||
x = self.conv(x)
|
||||
if is_String(x):
|
||||
x = CmdStringHolder(x, literal)
|
||||
self[-1].append(x)
|
||||
self.append = self.add_to_current_word
|
||||
|
||||
def literal(self, x):
|
||||
try:
|
||||
l = x.is_literal
|
||||
except AttributeError:
|
||||
return None
|
||||
else:
|
||||
return l()
|
||||
|
||||
def open_strip(self, x):
|
||||
"""Handle the "open strip" $( token."""
|
||||
self.add_strip(x)
|
||||
self.in_strip = 1
|
||||
|
||||
def close_strip(self, x):
|
||||
"""Handle the "close strip" $) token."""
|
||||
self.add_strip(x)
|
||||
self.in_strip = None
|
||||
|
||||
|
||||
# Constants for the "mode" parameter to scons_subst_list() and
|
||||
# scons_subst(). SUBST_RAW gives the raw command line. SUBST_CMD
|
||||
# gives a command line suitable for passing to a shell. SUBST_SIG
|
||||
# gives a command line appropriate for calculating the signature
|
||||
# of a command line...if this changes, we should rebuild.
|
||||
SUBST_CMD = 0
|
||||
SUBST_RAW = 1
|
||||
SUBST_SIG = 2
|
||||
|
||||
_rm = re.compile(r'\$[()]')
|
||||
|
||||
# Note the pattern below only matches $( or $) when there is no
|
||||
# preceeding $. (Thus the (?<!\$))
|
||||
_rm_split = re.compile(r'(?<!\$)(\$[()])')
|
||||
|
||||
# Indexed by the SUBST_* constants above.
|
||||
_regex_remove = [ _rm, None, _rm_split ]
|
||||
|
||||
def _rm_list(list):
|
||||
return [l for l in list if l not in ('$(', '$)')]
|
||||
|
||||
def _remove_list(list):
|
||||
result = []
|
||||
depth = 0
|
||||
for l in list:
|
||||
if l == '$(':
|
||||
depth += 1
|
||||
elif l == '$)':
|
||||
depth -= 1
|
||||
if depth < 0:
|
||||
break
|
||||
elif depth == 0:
|
||||
result.append(l)
|
||||
if depth != 0:
|
||||
return None
|
||||
return result
|
||||
|
||||
# Indexed by the SUBST_* constants above.
|
||||
_list_remove = [ _rm_list, None, _remove_list ]
|
||||
|
||||
# Regular expressions for splitting strings and handling substitutions,
|
||||
# for use by the scons_subst() and scons_subst_list() functions:
|
||||
#
|
||||
# The first expression compiled matches all of the $-introduced tokens
|
||||
# that we need to process in some way, and is used for substitutions.
|
||||
# The expressions it matches are:
|
||||
#
|
||||
# "$$"
|
||||
# "$("
|
||||
# "$)"
|
||||
# "$variable" [must begin with alphabetic or underscore]
|
||||
# "${any stuff}"
|
||||
#
|
||||
# The second expression compiled is used for splitting strings into tokens
|
||||
# to be processed, and it matches all of the tokens listed above, plus
|
||||
# the following that affect how arguments do or don't get joined together:
|
||||
#
|
||||
# " " [white space]
|
||||
# "non-white-space" [without any dollar signs]
|
||||
# "$" [single dollar sign]
|
||||
#
|
||||
_dollar_exps_str = r'\$[\$\(\)]|\$[_a-zA-Z][\.\w]*|\${[^}]*}'
|
||||
_dollar_exps = re.compile(r'(%s)' % _dollar_exps_str)
|
||||
_separate_args = re.compile(r'(%s|\s+|[^\s$]+|\$)' % _dollar_exps_str)
|
||||
|
||||
# This regular expression is used to replace strings of multiple white
|
||||
# space characters in the string result from the scons_subst() function.
|
||||
_space_sep = re.compile(r'[\t ]+(?![^{]*})')
|
||||
|
||||
def scons_subst(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={}, lvars={}, conv=None):
|
||||
"""Expand a string or list containing construction variable
|
||||
substitutions.
|
||||
|
||||
This is the work-horse function for substitutions in file names
|
||||
and the like. The companion scons_subst_list() function (below)
|
||||
handles separating command lines into lists of arguments, so see
|
||||
that function if that's what you're looking for.
|
||||
"""
|
||||
if (isinstance(strSubst, str) and '$' not in strSubst) or isinstance(strSubst, CmdStringHolder):
|
||||
return strSubst
|
||||
|
||||
if conv is None:
|
||||
conv = _strconv[mode]
|
||||
|
||||
# Doing this every time is a bit of a waste, since the Executor
|
||||
# has typically already populated the OverrideEnvironment with
|
||||
# $TARGET/$SOURCE variables. We're keeping this (for now), though,
|
||||
# because it supports existing behavior that allows us to call
|
||||
# an Action directly with an arbitrary target+source pair, which
|
||||
# we use in Tool/tex.py to handle calling $BIBTEX when necessary.
|
||||
# If we dropped that behavior (or found another way to cover it),
|
||||
# we could get rid of this call completely and just rely on the
|
||||
# Executor setting the variables.
|
||||
if 'TARGET' not in lvars:
|
||||
d = subst_dict(target, source)
|
||||
if d:
|
||||
lvars = lvars.copy()
|
||||
lvars.update(d)
|
||||
|
||||
# We're (most likely) going to eval() things. If Python doesn't
|
||||
# find a __builtins__ value in the global dictionary used for eval(),
|
||||
# it copies the current global values for you. Avoid this by
|
||||
# setting it explicitly and then deleting, so we don't pollute the
|
||||
# construction environment Dictionary(ies) that are typically used
|
||||
# for expansion.
|
||||
gvars['__builtins__'] = __builtins__
|
||||
|
||||
ss = StringSubber(env, mode, conv, gvars)
|
||||
result = ss.substitute(strSubst, lvars)
|
||||
|
||||
try:
|
||||
del gvars['__builtins__']
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
res = result
|
||||
if is_String(result):
|
||||
# Remove $(-$) pairs and any stuff in between,
|
||||
# if that's appropriate.
|
||||
remove = _regex_remove[mode]
|
||||
if remove:
|
||||
if mode == SUBST_SIG:
|
||||
result = _list_remove[mode](remove.split(result))
|
||||
if result is None:
|
||||
raise SCons.Errors.UserError("Unbalanced $(/$) in: " + res)
|
||||
result = ' '.join(result)
|
||||
else:
|
||||
result = remove.sub('', result)
|
||||
if mode != SUBST_RAW:
|
||||
# Compress strings of white space characters into
|
||||
# a single space.
|
||||
result = _space_sep.sub(' ', result).strip()
|
||||
|
||||
# Now replace escaped $'s currently "$$"
|
||||
# This is needed because we now retain $$ instead of
|
||||
# replacing them during substition to avoid
|
||||
# improperly trying to escape "$$(" as being "$("
|
||||
result = result.replace('$$','$')
|
||||
elif is_Sequence(result):
|
||||
remove = _list_remove[mode]
|
||||
if remove:
|
||||
result = remove(result)
|
||||
if result is None:
|
||||
raise SCons.Errors.UserError("Unbalanced $(/$) in: " + str(res))
|
||||
|
||||
return result
|
||||
|
||||
def scons_subst_list(strSubst, env, mode=SUBST_RAW, target=None, source=None, gvars={}, lvars={}, conv=None):
|
||||
"""Substitute construction variables in a string (or list or other
|
||||
object) and separate the arguments into a command list.
|
||||
|
||||
The companion scons_subst() function (above) handles basic
|
||||
substitutions within strings, so see that function instead
|
||||
if that's what you're looking for.
|
||||
"""
|
||||
if conv is None:
|
||||
conv = _strconv[mode]
|
||||
|
||||
# Doing this every time is a bit of a waste, since the Executor
|
||||
# has typically already populated the OverrideEnvironment with
|
||||
# $TARGET/$SOURCE variables. We're keeping this (for now), though,
|
||||
# because it supports existing behavior that allows us to call
|
||||
# an Action directly with an arbitrary target+source pair, which
|
||||
# we use in Tool/tex.py to handle calling $BIBTEX when necessary.
|
||||
# If we dropped that behavior (or found another way to cover it),
|
||||
# we could get rid of this call completely and just rely on the
|
||||
# Executor setting the variables.
|
||||
if 'TARGET' not in lvars:
|
||||
d = subst_dict(target, source)
|
||||
if d:
|
||||
lvars = lvars.copy()
|
||||
lvars.update(d)
|
||||
|
||||
# We're (most likely) going to eval() things. If Python doesn't
|
||||
# find a __builtins__ value in the global dictionary used for eval(),
|
||||
# it copies the current global values for you. Avoid this by
|
||||
# setting it explicitly and then deleting, so we don't pollute the
|
||||
# construction environment Dictionary(ies) that are typically used
|
||||
# for expansion.
|
||||
gvars['__builtins__'] = __builtins__
|
||||
|
||||
ls = ListSubber(env, mode, conv, gvars)
|
||||
ls.substitute(strSubst, lvars, 0)
|
||||
|
||||
try:
|
||||
del gvars['__builtins__']
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
return ls.data
|
||||
|
||||
def scons_subst_once(strSubst, env, key):
|
||||
"""Perform single (non-recursive) substitution of a single
|
||||
construction variable keyword.
|
||||
|
||||
This is used when setting a variable when copying or overriding values
|
||||
in an Environment. We want to capture (expand) the old value before
|
||||
we override it, so people can do things like:
|
||||
|
||||
env2 = env.Clone(CCFLAGS = '$CCFLAGS -g')
|
||||
|
||||
We do this with some straightforward, brute-force code here...
|
||||
"""
|
||||
if isinstance(strSubst, str) and strSubst.find('$') < 0:
|
||||
return strSubst
|
||||
|
||||
matchlist = ['$' + key, '${' + key + '}']
|
||||
val = env.get(key, '')
|
||||
def sub_match(match, val=val, matchlist=matchlist):
|
||||
a = match.group(1)
|
||||
if a in matchlist:
|
||||
a = val
|
||||
if is_Sequence(a):
|
||||
return ' '.join(map(str, a))
|
||||
else:
|
||||
return str(a)
|
||||
|
||||
if is_Sequence(strSubst):
|
||||
result = []
|
||||
for arg in strSubst:
|
||||
if is_String(arg):
|
||||
if arg in matchlist:
|
||||
arg = val
|
||||
if is_Sequence(arg):
|
||||
result.extend(arg)
|
||||
else:
|
||||
result.append(arg)
|
||||
else:
|
||||
result.append(_dollar_exps.sub(sub_match, arg))
|
||||
else:
|
||||
result.append(arg)
|
||||
return result
|
||||
elif is_String(strSubst):
|
||||
return _dollar_exps.sub(sub_match, strSubst)
|
||||
else:
|
||||
return strSubst
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
1068
scons/scons-local-4.0.1/SCons/Taskmaster.py
Normal file
1068
scons/scons-local-4.0.1/SCons/Taskmaster.py
Normal file
File diff suppressed because it is too large
Load diff
61
scons/scons-local-4.0.1/SCons/Tool/386asm.py
Normal file
61
scons/scons-local-4.0.1/SCons/Tool/386asm.py
Normal file
|
@ -0,0 +1,61 @@
|
|||
"""SCons.Tool.386asm
|
||||
|
||||
Tool specification for the 386ASM assembler for the Phar Lap ETS embedded
|
||||
operating system.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
from SCons.Tool.PharLapCommon import addPharLapPaths
|
||||
import SCons.Util
|
||||
|
||||
as_module = __import__('as', globals(), locals(), [], 1)
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for ar to an Environment."""
|
||||
as_module.generate(env)
|
||||
|
||||
env['AS'] = '386asm'
|
||||
env['ASFLAGS'] = SCons.Util.CLVar('')
|
||||
env['ASPPFLAGS'] = '$ASFLAGS'
|
||||
env['ASCOM'] = '$AS $ASFLAGS $SOURCES -o $TARGET'
|
||||
env['ASPPCOM'] = '$CC $ASPPFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS $SOURCES -o $TARGET'
|
||||
|
||||
addPharLapPaths(env)
|
||||
|
||||
def exists(env):
|
||||
return env.Detect('386asm')
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
67
scons/scons-local-4.0.1/SCons/Tool/DCommon.py
Normal file
67
scons/scons-local-4.0.1/SCons/Tool/DCommon.py
Normal file
|
@ -0,0 +1,67 @@
|
|||
"""SCons.Tool.DCommon
|
||||
|
||||
Common code for the various D tools.
|
||||
|
||||
Coded by Russel Winder (russel@winder.org.uk)
|
||||
2012-09-06
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import os.path
|
||||
|
||||
|
||||
def isD(env, source):
|
||||
if not source:
|
||||
return 0
|
||||
for s in source:
|
||||
if s.sources:
|
||||
ext = os.path.splitext(str(s.sources[0]))[1]
|
||||
if ext == '.d':
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
def addDPATHToEnv(env, executable):
|
||||
dPath = env.WhereIs(executable)
|
||||
if dPath:
|
||||
phobosDir = dPath[:dPath.rindex(executable)] + '/../src/phobos'
|
||||
if os.path.isdir(phobosDir):
|
||||
env.Append(DPATH=[phobosDir])
|
||||
|
||||
|
||||
def allAtOnceEmitter(target, source, env):
|
||||
if env['DC'] in ('ldc2', 'dmd'):
|
||||
env.SideEffect(str(target[0]) + '.o', target[0])
|
||||
env.Clean(target[0], str(target[0]) + '.o')
|
||||
return target, source
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
279
scons/scons-local-4.0.1/SCons/Tool/FortranCommon.py
Normal file
279
scons/scons-local-4.0.1/SCons/Tool/FortranCommon.py
Normal file
|
@ -0,0 +1,279 @@
|
|||
"""SCons.Tool.FortranCommon
|
||||
|
||||
Stuff for processing Fortran, common to all fortran dialects.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import re
|
||||
import os.path
|
||||
|
||||
import SCons.Action
|
||||
import SCons.Defaults
|
||||
import SCons.Scanner.Fortran
|
||||
import SCons.Tool
|
||||
import SCons.Util
|
||||
|
||||
def isfortran(env, source):
|
||||
"""Return 1 if any of code in source has fortran files in it, 0
|
||||
otherwise."""
|
||||
try:
|
||||
fsuffixes = env['FORTRANSUFFIXES']
|
||||
except KeyError:
|
||||
# If no FORTRANSUFFIXES, no fortran tool, so there is no need to look
|
||||
# for fortran sources.
|
||||
return 0
|
||||
|
||||
if not source:
|
||||
# Source might be None for unusual cases like SConf.
|
||||
return 0
|
||||
for s in source:
|
||||
if s.sources:
|
||||
ext = os.path.splitext(str(s.sources[0]))[1]
|
||||
if ext in fsuffixes:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def _fortranEmitter(target, source, env):
|
||||
node = source[0].rfile()
|
||||
if not node.exists() and not node.is_derived():
|
||||
print("Could not locate " + str(node.name))
|
||||
return ([], [])
|
||||
# This has to match the def_regex in the Fortran scanner
|
||||
mod_regex = r"""(?i)^\s*MODULE\s+(?!PROCEDURE|SUBROUTINE|FUNCTION|PURE|ELEMENTAL)(\w+)"""
|
||||
cre = re.compile(mod_regex,re.M)
|
||||
# Retrieve all USE'd module names
|
||||
modules = cre.findall(node.get_text_contents())
|
||||
# Remove unique items from the list
|
||||
modules = SCons.Util.unique(modules)
|
||||
# Convert module name to a .mod filename
|
||||
suffix = env.subst('$FORTRANMODSUFFIX', target=target, source=source)
|
||||
moddir = env.subst('$FORTRANMODDIR', target=target, source=source)
|
||||
modules = [x.lower() + suffix for x in modules]
|
||||
for m in modules:
|
||||
target.append(env.fs.File(m, moddir))
|
||||
return (target, source)
|
||||
|
||||
def FortranEmitter(target, source, env):
|
||||
target, source = _fortranEmitter(target, source, env)
|
||||
return SCons.Defaults.StaticObjectEmitter(target, source, env)
|
||||
|
||||
def ShFortranEmitter(target, source, env):
|
||||
target, source = _fortranEmitter(target, source, env)
|
||||
return SCons.Defaults.SharedObjectEmitter(target, source, env)
|
||||
|
||||
def ComputeFortranSuffixes(suffixes, ppsuffixes):
|
||||
"""suffixes are fortran source files, and ppsuffixes the ones to be
|
||||
pre-processed. Both should be sequences, not strings."""
|
||||
assert len(suffixes) > 0
|
||||
s = suffixes[0]
|
||||
sup = s.upper()
|
||||
upper_suffixes = [_.upper() for _ in suffixes]
|
||||
if SCons.Util.case_sensitive_suffixes(s, sup):
|
||||
ppsuffixes.extend(upper_suffixes)
|
||||
else:
|
||||
suffixes.extend(upper_suffixes)
|
||||
|
||||
def CreateDialectActions(dialect):
|
||||
"""Create dialect specific actions."""
|
||||
CompAction = SCons.Action.Action('$%sCOM ' % dialect, '$%sCOMSTR' % dialect)
|
||||
CompPPAction = SCons.Action.Action('$%sPPCOM ' % dialect, '$%sPPCOMSTR' % dialect)
|
||||
ShCompAction = SCons.Action.Action('$SH%sCOM ' % dialect, '$SH%sCOMSTR' % dialect)
|
||||
ShCompPPAction = SCons.Action.Action('$SH%sPPCOM ' % dialect, '$SH%sPPCOMSTR' % dialect)
|
||||
|
||||
return CompAction, CompPPAction, ShCompAction, ShCompPPAction
|
||||
|
||||
def DialectAddToEnv(env, dialect, suffixes, ppsuffixes, support_module = 0):
|
||||
"""Add dialect specific construction variables."""
|
||||
ComputeFortranSuffixes(suffixes, ppsuffixes)
|
||||
|
||||
fscan = SCons.Scanner.Fortran.FortranScan("%sPATH" % dialect)
|
||||
|
||||
for suffix in suffixes + ppsuffixes:
|
||||
SCons.Tool.SourceFileScanner.add_scanner(suffix, fscan)
|
||||
|
||||
env.AppendUnique(FORTRANSUFFIXES = suffixes + ppsuffixes)
|
||||
|
||||
compaction, compppaction, shcompaction, shcompppaction = \
|
||||
CreateDialectActions(dialect)
|
||||
|
||||
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
|
||||
|
||||
for suffix in suffixes:
|
||||
static_obj.add_action(suffix, compaction)
|
||||
shared_obj.add_action(suffix, shcompaction)
|
||||
static_obj.add_emitter(suffix, FortranEmitter)
|
||||
shared_obj.add_emitter(suffix, ShFortranEmitter)
|
||||
|
||||
for suffix in ppsuffixes:
|
||||
static_obj.add_action(suffix, compppaction)
|
||||
shared_obj.add_action(suffix, shcompppaction)
|
||||
static_obj.add_emitter(suffix, FortranEmitter)
|
||||
shared_obj.add_emitter(suffix, ShFortranEmitter)
|
||||
|
||||
if '%sFLAGS' % dialect not in env:
|
||||
env['%sFLAGS' % dialect] = SCons.Util.CLVar('')
|
||||
|
||||
if 'SH%sFLAGS' % dialect not in env:
|
||||
env['SH%sFLAGS' % dialect] = SCons.Util.CLVar('$%sFLAGS' % dialect)
|
||||
|
||||
# If a tool does not define fortran prefix/suffix for include path, use C ones
|
||||
if 'INC%sPREFIX' % dialect not in env:
|
||||
env['INC%sPREFIX' % dialect] = '$INCPREFIX'
|
||||
|
||||
if 'INC%sSUFFIX' % dialect not in env:
|
||||
env['INC%sSUFFIX' % dialect] = '$INCSUFFIX'
|
||||
|
||||
env['_%sINCFLAGS' % dialect] = '$( ${_concat(INC%sPREFIX, %sPATH, INC%sSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)' % (dialect, dialect, dialect)
|
||||
|
||||
if support_module == 1:
|
||||
env['%sCOM' % dialect] = '$%s -o $TARGET -c $%sFLAGS $_%sINCFLAGS $_FORTRANMODFLAG $SOURCES' % (dialect, dialect, dialect)
|
||||
env['%sPPCOM' % dialect] = '$%s -o $TARGET -c $%sFLAGS $CPPFLAGS $_CPPDEFFLAGS $_%sINCFLAGS $_FORTRANMODFLAG $SOURCES' % (dialect, dialect, dialect)
|
||||
env['SH%sCOM' % dialect] = '$SH%s -o $TARGET -c $SH%sFLAGS $_%sINCFLAGS $_FORTRANMODFLAG $SOURCES' % (dialect, dialect, dialect)
|
||||
env['SH%sPPCOM' % dialect] = '$SH%s -o $TARGET -c $SH%sFLAGS $CPPFLAGS $_CPPDEFFLAGS $_%sINCFLAGS $_FORTRANMODFLAG $SOURCES' % (dialect, dialect, dialect)
|
||||
else:
|
||||
env['%sCOM' % dialect] = '$%s -o $TARGET -c $%sFLAGS $_%sINCFLAGS $SOURCES' % (dialect, dialect, dialect)
|
||||
env['%sPPCOM' % dialect] = '$%s -o $TARGET -c $%sFLAGS $CPPFLAGS $_CPPDEFFLAGS $_%sINCFLAGS $SOURCES' % (dialect, dialect, dialect)
|
||||
env['SH%sCOM' % dialect] = '$SH%s -o $TARGET -c $SH%sFLAGS $_%sINCFLAGS $SOURCES' % (dialect, dialect, dialect)
|
||||
env['SH%sPPCOM' % dialect] = '$SH%s -o $TARGET -c $SH%sFLAGS $CPPFLAGS $_CPPDEFFLAGS $_%sINCFLAGS $SOURCES' % (dialect, dialect, dialect)
|
||||
|
||||
def add_fortran_to_env(env):
|
||||
"""Add Builders and construction variables for Fortran to an Environment."""
|
||||
try:
|
||||
FortranSuffixes = env['FORTRANFILESUFFIXES']
|
||||
except KeyError:
|
||||
FortranSuffixes = ['.f', '.for', '.ftn']
|
||||
|
||||
#print("Adding %s to fortran suffixes" % FortranSuffixes)
|
||||
try:
|
||||
FortranPPSuffixes = env['FORTRANPPFILESUFFIXES']
|
||||
except KeyError:
|
||||
FortranPPSuffixes = ['.fpp', '.FPP']
|
||||
|
||||
DialectAddToEnv(env, "FORTRAN", FortranSuffixes,
|
||||
FortranPPSuffixes, support_module = 1)
|
||||
|
||||
env['FORTRANMODPREFIX'] = '' # like $LIBPREFIX
|
||||
env['FORTRANMODSUFFIX'] = '.mod' # like $LIBSUFFIX
|
||||
|
||||
env['FORTRANMODDIR'] = '' # where the compiler should place .mod files
|
||||
env['FORTRANMODDIRPREFIX'] = '' # some prefix to $FORTRANMODDIR - similar to $INCPREFIX
|
||||
env['FORTRANMODDIRSUFFIX'] = '' # some suffix to $FORTRANMODDIR - similar to $INCSUFFIX
|
||||
env['_FORTRANMODFLAG'] = '$( ${_concat(FORTRANMODDIRPREFIX, FORTRANMODDIR, FORTRANMODDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)'
|
||||
|
||||
def add_f77_to_env(env):
|
||||
"""Add Builders and construction variables for f77 to an Environment."""
|
||||
try:
|
||||
F77Suffixes = env['F77FILESUFFIXES']
|
||||
except KeyError:
|
||||
F77Suffixes = ['.f77']
|
||||
|
||||
#print("Adding %s to f77 suffixes" % F77Suffixes)
|
||||
try:
|
||||
F77PPSuffixes = env['F77PPFILESUFFIXES']
|
||||
except KeyError:
|
||||
F77PPSuffixes = []
|
||||
|
||||
DialectAddToEnv(env, "F77", F77Suffixes, F77PPSuffixes)
|
||||
|
||||
def add_f90_to_env(env):
|
||||
"""Add Builders and construction variables for f90 to an Environment."""
|
||||
try:
|
||||
F90Suffixes = env['F90FILESUFFIXES']
|
||||
except KeyError:
|
||||
F90Suffixes = ['.f90']
|
||||
|
||||
#print("Adding %s to f90 suffixes" % F90Suffixes)
|
||||
try:
|
||||
F90PPSuffixes = env['F90PPFILESUFFIXES']
|
||||
except KeyError:
|
||||
F90PPSuffixes = []
|
||||
|
||||
DialectAddToEnv(env, "F90", F90Suffixes, F90PPSuffixes,
|
||||
support_module = 1)
|
||||
|
||||
def add_f95_to_env(env):
|
||||
"""Add Builders and construction variables for f95 to an Environment."""
|
||||
try:
|
||||
F95Suffixes = env['F95FILESUFFIXES']
|
||||
except KeyError:
|
||||
F95Suffixes = ['.f95']
|
||||
|
||||
#print("Adding %s to f95 suffixes" % F95Suffixes)
|
||||
try:
|
||||
F95PPSuffixes = env['F95PPFILESUFFIXES']
|
||||
except KeyError:
|
||||
F95PPSuffixes = []
|
||||
|
||||
DialectAddToEnv(env, "F95", F95Suffixes, F95PPSuffixes,
|
||||
support_module = 1)
|
||||
|
||||
def add_f03_to_env(env):
|
||||
"""Add Builders and construction variables for f03 to an Environment."""
|
||||
try:
|
||||
F03Suffixes = env['F03FILESUFFIXES']
|
||||
except KeyError:
|
||||
F03Suffixes = ['.f03']
|
||||
|
||||
#print("Adding %s to f95 suffixes" % F95Suffixes)
|
||||
try:
|
||||
F03PPSuffixes = env['F03PPFILESUFFIXES']
|
||||
except KeyError:
|
||||
F03PPSuffixes = []
|
||||
|
||||
DialectAddToEnv(env, "F03", F03Suffixes, F03PPSuffixes,
|
||||
support_module = 1)
|
||||
|
||||
def add_f08_to_env(env):
|
||||
"""Add Builders and construction variables for f08 to an Environment."""
|
||||
try:
|
||||
F08Suffixes = env['F08FILESUFFIXES']
|
||||
except KeyError:
|
||||
F08Suffixes = ['.f08']
|
||||
|
||||
try:
|
||||
F08PPSuffixes = env['F08PPFILESUFFIXES']
|
||||
except KeyError:
|
||||
F08PPSuffixes = []
|
||||
|
||||
DialectAddToEnv(env, "F08", F08Suffixes, F08PPSuffixes,
|
||||
support_module = 1)
|
||||
|
||||
def add_all_to_env(env):
|
||||
"""Add builders and construction variables for all supported fortran
|
||||
dialects."""
|
||||
add_fortran_to_env(env)
|
||||
add_f77_to_env(env)
|
||||
add_f90_to_env(env)
|
||||
add_f95_to_env(env)
|
||||
add_f03_to_env(env)
|
||||
add_f08_to_env(env)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
469
scons/scons-local-4.0.1/SCons/Tool/GettextCommon.py
Normal file
469
scons/scons-local-4.0.1/SCons/Tool/GettextCommon.py
Normal file
|
@ -0,0 +1,469 @@
|
|||
"""SCons.Tool.GettextCommon module
|
||||
|
||||
Used by several tools of `gettext` toolset.
|
||||
"""
|
||||
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import SCons.Warnings
|
||||
import re
|
||||
|
||||
|
||||
#############################################################################
|
||||
class XgettextToolWarning(SCons.Warnings.Warning): pass
|
||||
|
||||
|
||||
class XgettextNotFound(XgettextToolWarning): pass
|
||||
|
||||
|
||||
class MsginitToolWarning(SCons.Warnings.Warning): pass
|
||||
|
||||
|
||||
class MsginitNotFound(MsginitToolWarning): pass
|
||||
|
||||
|
||||
class MsgmergeToolWarning(SCons.Warnings.Warning): pass
|
||||
|
||||
|
||||
class MsgmergeNotFound(MsgmergeToolWarning): pass
|
||||
|
||||
|
||||
class MsgfmtToolWarning(SCons.Warnings.Warning): pass
|
||||
|
||||
|
||||
class MsgfmtNotFound(MsgfmtToolWarning): pass
|
||||
|
||||
|
||||
#############################################################################
|
||||
SCons.Warnings.enableWarningClass(XgettextToolWarning)
|
||||
SCons.Warnings.enableWarningClass(XgettextNotFound)
|
||||
SCons.Warnings.enableWarningClass(MsginitToolWarning)
|
||||
SCons.Warnings.enableWarningClass(MsginitNotFound)
|
||||
SCons.Warnings.enableWarningClass(MsgmergeToolWarning)
|
||||
SCons.Warnings.enableWarningClass(MsgmergeNotFound)
|
||||
SCons.Warnings.enableWarningClass(MsgfmtToolWarning)
|
||||
SCons.Warnings.enableWarningClass(MsgfmtNotFound)
|
||||
|
||||
|
||||
#############################################################################
|
||||
|
||||
#############################################################################
|
||||
class _POTargetFactory:
|
||||
""" A factory of `PO` target files.
|
||||
|
||||
Factory defaults differ from these of `SCons.Node.FS.FS`. We set `precious`
|
||||
(this is required by builders and actions gettext) and `noclean` flags by
|
||||
default for all produced nodes.
|
||||
"""
|
||||
|
||||
def __init__(self, env, nodefault=True, alias=None, precious=True
|
||||
, noclean=True):
|
||||
""" Object constructor.
|
||||
|
||||
**Arguments**
|
||||
|
||||
- *env* (`SCons.Environment.Environment`)
|
||||
- *nodefault* (`boolean`) - if `True`, produced nodes will be ignored
|
||||
from default target `'.'`
|
||||
- *alias* (`string`) - if provided, produced nodes will be automatically
|
||||
added to this alias, and alias will be set as `AlwaysBuild`
|
||||
- *precious* (`boolean`) - if `True`, the produced nodes will be set as
|
||||
`Precious`.
|
||||
- *noclen* (`boolean`) - if `True`, the produced nodes will be excluded
|
||||
from `Clean`.
|
||||
"""
|
||||
self.env = env
|
||||
self.alias = alias
|
||||
self.precious = precious
|
||||
self.noclean = noclean
|
||||
self.nodefault = nodefault
|
||||
|
||||
def _create_node(self, name, factory, directory=None, create=1):
|
||||
""" Create node, and set it up to factory settings. """
|
||||
import SCons.Util
|
||||
node = factory(name, directory, create)
|
||||
node.set_noclean(self.noclean)
|
||||
node.set_precious(self.precious)
|
||||
if self.nodefault:
|
||||
self.env.Ignore('.', node)
|
||||
if self.alias:
|
||||
self.env.AlwaysBuild(self.env.Alias(self.alias, node))
|
||||
return node
|
||||
|
||||
def Entry(self, name, directory=None, create=1):
|
||||
""" Create `SCons.Node.FS.Entry` """
|
||||
return self._create_node(name, self.env.fs.Entry, directory, create)
|
||||
|
||||
def File(self, name, directory=None, create=1):
|
||||
""" Create `SCons.Node.FS.File` """
|
||||
return self._create_node(name, self.env.fs.File, directory, create)
|
||||
|
||||
|
||||
#############################################################################
|
||||
|
||||
#############################################################################
|
||||
_re_comment = re.compile(r'(#[^\n\r]+)$', re.M)
|
||||
_re_lang = re.compile(r'([a-zA-Z0-9_]+)', re.M)
|
||||
|
||||
|
||||
#############################################################################
|
||||
def _read_linguas_from_files(env, linguas_files=None):
|
||||
""" Parse `LINGUAS` file and return list of extracted languages """
|
||||
import SCons.Util
|
||||
import SCons.Environment
|
||||
global _re_comment
|
||||
global _re_lang
|
||||
if not SCons.Util.is_List(linguas_files) \
|
||||
and not SCons.Util.is_String(linguas_files) \
|
||||
and not isinstance(linguas_files, SCons.Node.FS.Base) \
|
||||
and linguas_files:
|
||||
# If, linguas_files==True or such, then read 'LINGUAS' file.
|
||||
linguas_files = ['LINGUAS']
|
||||
if linguas_files is None:
|
||||
return []
|
||||
fnodes = env.arg2nodes(linguas_files)
|
||||
linguas = []
|
||||
for fnode in fnodes:
|
||||
contents = _re_comment.sub("", fnode.get_text_contents())
|
||||
ls = [l for l in _re_lang.findall(contents) if l]
|
||||
linguas.extend(ls)
|
||||
return linguas
|
||||
|
||||
|
||||
#############################################################################
|
||||
|
||||
#############################################################################
|
||||
from SCons.Builder import BuilderBase
|
||||
|
||||
|
||||
#############################################################################
|
||||
class _POFileBuilder(BuilderBase):
|
||||
""" `PO` file builder.
|
||||
|
||||
This is multi-target single-source builder. In typical situation the source
|
||||
is single `POT` file, e.g. `messages.pot`, and there are multiple `PO`
|
||||
targets to be updated from this `POT`. We must run
|
||||
`SCons.Builder.BuilderBase._execute()` separatelly for each target to track
|
||||
dependencies separatelly for each target file.
|
||||
|
||||
**NOTE**: if we call `SCons.Builder.BuilderBase._execute(.., target, ...)`
|
||||
with target being list of all targets, all targets would be rebuilt each time
|
||||
one of the targets from this list is missing. This would happen, for example,
|
||||
when new language `ll` enters `LINGUAS_FILE` (at this moment there is no
|
||||
`ll.po` file yet). To avoid this, we override
|
||||
`SCons.Builder.BuilerBase._execute()` and call it separatelly for each
|
||||
target. Here we also append to the target list the languages read from
|
||||
`LINGUAS_FILE`.
|
||||
"""
|
||||
|
||||
#
|
||||
# * The argument for overriding _execute(): We must use environment with
|
||||
# builder overrides applied (see BuilderBase.__init__(). Here it comes for
|
||||
# free.
|
||||
# * The argument against using 'emitter': The emitter is called too late
|
||||
# by BuilderBase._execute(). If user calls, for example:
|
||||
#
|
||||
# env.POUpdate(LINGUAS_FILE = 'LINGUAS')
|
||||
#
|
||||
# the builder throws error, because it is called with target=None,
|
||||
# source=None and is trying to "generate" sources or target list first.
|
||||
# If user calls
|
||||
#
|
||||
# env.POUpdate(['foo', 'baz'], LINGUAS_FILE = 'LINGUAS')
|
||||
#
|
||||
# the env.BuilderWrapper() calls our builder with target=None,
|
||||
# source=['foo', 'baz']. The BuilderBase._execute() then splits execution
|
||||
# and execute iterativelly (recursion) self._execute(None, source[i]).
|
||||
# After that it calls emitter (which is quite too late). The emitter is
|
||||
# also called in each iteration, what makes things yet worse.
|
||||
def __init__(self, env, **kw):
|
||||
if 'suffix' not in kw:
|
||||
kw['suffix'] = '$POSUFFIX'
|
||||
if 'src_suffix' not in kw:
|
||||
kw['src_suffix'] = '$POTSUFFIX'
|
||||
if 'src_builder' not in kw:
|
||||
kw['src_builder'] = '_POTUpdateBuilder'
|
||||
if 'single_source' not in kw:
|
||||
kw['single_source'] = True
|
||||
alias = None
|
||||
if 'target_alias' in kw:
|
||||
alias = kw['target_alias']
|
||||
del kw['target_alias']
|
||||
if 'target_factory' not in kw:
|
||||
kw['target_factory'] = _POTargetFactory(env, alias=alias).File
|
||||
BuilderBase.__init__(self, **kw)
|
||||
|
||||
def _execute(self, env, target, source, *args, **kw):
|
||||
""" Execute builder's actions.
|
||||
|
||||
Here we append to `target` the languages read from `$LINGUAS_FILE` and
|
||||
apply `SCons.Builder.BuilderBase._execute()` separatelly to each target.
|
||||
The arguments and return value are same as for
|
||||
`SCons.Builder.BuilderBase._execute()`.
|
||||
"""
|
||||
import SCons.Util
|
||||
import SCons.Node
|
||||
linguas_files = None
|
||||
if 'LINGUAS_FILE' in env and env['LINGUAS_FILE']:
|
||||
linguas_files = env['LINGUAS_FILE']
|
||||
# This prevents endless recursion loop (we'll be invoked once for
|
||||
# each target appended here, we must not extend the list again).
|
||||
env['LINGUAS_FILE'] = None
|
||||
linguas = _read_linguas_from_files(env, linguas_files)
|
||||
if SCons.Util.is_List(target):
|
||||
target.extend(linguas)
|
||||
elif target is not None:
|
||||
target = [target] + linguas
|
||||
else:
|
||||
target = linguas
|
||||
if not target:
|
||||
# Let the SCons.BuilderBase to handle this patologic situation
|
||||
return BuilderBase._execute(self, env, target, source, *args, **kw)
|
||||
# The rest is ours
|
||||
if not SCons.Util.is_List(target):
|
||||
target = [target]
|
||||
result = []
|
||||
for tgt in target:
|
||||
r = BuilderBase._execute(self, env, [tgt], source, *args, **kw)
|
||||
result.extend(r)
|
||||
if linguas_files is not None:
|
||||
env['LINGUAS_FILE'] = linguas_files
|
||||
return SCons.Node.NodeList(result)
|
||||
|
||||
|
||||
#############################################################################
|
||||
|
||||
import SCons.Environment
|
||||
|
||||
|
||||
#############################################################################
|
||||
def _translate(env, target=None, source=SCons.Environment._null, *args, **kw):
|
||||
""" Function for `Translate()` pseudo-builder """
|
||||
if target is None: target = []
|
||||
pot = env.POTUpdate(None, source, *args, **kw)
|
||||
po = env.POUpdate(target, pot, *args, **kw)
|
||||
return po
|
||||
|
||||
|
||||
#############################################################################
|
||||
|
||||
#############################################################################
|
||||
class RPaths:
|
||||
""" Callable object, which returns pathnames relative to SCons current
|
||||
working directory.
|
||||
|
||||
It seems like `SCons.Node.FS.Base.get_path()` returns absolute paths
|
||||
for nodes that are outside of current working directory (`env.fs.getcwd()`).
|
||||
Here, we often have `SConscript`, `POT` and `PO` files within `po/`
|
||||
directory and source files (e.g. `*.c`) outside of it. When generating `POT`
|
||||
template file, references to source files are written to `POT` template, so
|
||||
a translator may later quickly jump to appropriate source file and line from
|
||||
its `PO` editor (e.g. `poedit`). Relative paths in `PO` file are usually
|
||||
interpreted by `PO` editor as paths relative to the place, where `PO` file
|
||||
lives. The absolute paths would make resultant `POT` file nonportable, as
|
||||
the references would be correct only on the machine, where `POT` file was
|
||||
recently re-created. For such reason, we need a function, which always
|
||||
returns relative paths. This is the purpose of `RPaths` callable object.
|
||||
|
||||
The `__call__` method returns paths relative to current working directory, but
|
||||
we assume, that *xgettext(1)* is run from the directory, where target file is
|
||||
going to be created.
|
||||
|
||||
Note, that this may not work for files distributed over several hosts or
|
||||
across different drives on windows. We assume here, that single local
|
||||
filesystem holds both source files and target `POT` templates.
|
||||
|
||||
Intended use of `RPaths` - in `xgettext.py`::
|
||||
|
||||
def generate(env):
|
||||
from GettextCommon import RPaths
|
||||
...
|
||||
sources = '$( ${_concat( "", SOURCES, "", __env__, XgettextRPaths, TARGET, SOURCES)} $)'
|
||||
env.Append(
|
||||
...
|
||||
XGETTEXTCOM = 'XGETTEXT ... ' + sources,
|
||||
...
|
||||
XgettextRPaths = RPaths(env)
|
||||
)
|
||||
"""
|
||||
|
||||
# NOTE: This callable object returns pathnames of dirs/files relative to
|
||||
# current working directory. The pathname remains relative also for entries
|
||||
# that are outside of current working directory (node, that
|
||||
# SCons.Node.FS.File and siblings return absolute path in such case). For
|
||||
# simplicity we compute path relative to current working directory, this
|
||||
# seems be enough for our purposes (don't need TARGET variable and
|
||||
# SCons.Defaults.Variable_Caller stuff).
|
||||
|
||||
def __init__(self, env):
|
||||
""" Initialize `RPaths` callable object.
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- *env* - a `SCons.Environment.Environment` object, defines *current
|
||||
working dir*.
|
||||
"""
|
||||
self.env = env
|
||||
|
||||
# FIXME: I'm not sure, how it should be implemented (what the *args are in
|
||||
# general, what is **kw).
|
||||
def __call__(self, nodes, *args, **kw):
|
||||
""" Return nodes' paths (strings) relative to current working directory.
|
||||
|
||||
**Arguments**:
|
||||
|
||||
- *nodes* ([`SCons.Node.FS.Base`]) - list of nodes.
|
||||
- *args* - currently unused.
|
||||
- *kw* - currently unused.
|
||||
|
||||
**Returns**:
|
||||
|
||||
- Tuple of strings, which represent paths relative to current working
|
||||
directory (for given environment).
|
||||
"""
|
||||
import os
|
||||
import SCons.Node.FS
|
||||
rpaths = ()
|
||||
cwd = self.env.fs.getcwd().get_abspath()
|
||||
for node in nodes:
|
||||
rpath = None
|
||||
if isinstance(node, SCons.Node.FS.Base):
|
||||
rpath = os.path.relpath(node.get_abspath(), cwd)
|
||||
# FIXME: Other types possible here?
|
||||
if rpath is not None:
|
||||
rpaths += (rpath,)
|
||||
return rpaths
|
||||
|
||||
|
||||
#############################################################################
|
||||
|
||||
#############################################################################
|
||||
def _init_po_files(target, source, env):
|
||||
""" Action function for `POInit` builder. """
|
||||
nop = lambda target, source, env: 0
|
||||
if 'POAUTOINIT' in env:
|
||||
autoinit = env['POAUTOINIT']
|
||||
else:
|
||||
autoinit = False
|
||||
# Well, if everything outside works well, this loop should do single
|
||||
# iteration. Otherwise we are rebuilding all the targets even, if just
|
||||
# one has changed (but is this our fault?).
|
||||
for tgt in target:
|
||||
if not tgt.exists():
|
||||
if autoinit:
|
||||
action = SCons.Action.Action('$MSGINITCOM', '$MSGINITCOMSTR')
|
||||
else:
|
||||
msg = 'File ' + repr(str(tgt)) + ' does not exist. ' \
|
||||
+ 'If you are a translator, you can create it through: \n' \
|
||||
+ '$MSGINITCOM'
|
||||
action = SCons.Action.Action(nop, msg)
|
||||
status = action([tgt], source, env)
|
||||
if status: return status
|
||||
return 0
|
||||
|
||||
|
||||
#############################################################################
|
||||
|
||||
#############################################################################
|
||||
def _detect_xgettext(env):
|
||||
""" Detects *xgettext(1)* binary """
|
||||
if 'XGETTEXT' in env:
|
||||
return env['XGETTEXT']
|
||||
xgettext = env.Detect('xgettext')
|
||||
if xgettext:
|
||||
return xgettext
|
||||
raise SCons.Errors.StopError(XgettextNotFound, "Could not detect xgettext")
|
||||
return None
|
||||
|
||||
|
||||
#############################################################################
|
||||
def _xgettext_exists(env):
|
||||
return _detect_xgettext(env)
|
||||
|
||||
|
||||
#############################################################################
|
||||
|
||||
#############################################################################
|
||||
def _detect_msginit(env):
|
||||
""" Detects *msginit(1)* program. """
|
||||
if 'MSGINIT' in env:
|
||||
return env['MSGINIT']
|
||||
msginit = env.Detect('msginit')
|
||||
if msginit:
|
||||
return msginit
|
||||
raise SCons.Errors.StopError(MsginitNotFound, "Could not detect msginit")
|
||||
return None
|
||||
|
||||
|
||||
#############################################################################
|
||||
def _msginit_exists(env):
|
||||
return _detect_msginit(env)
|
||||
|
||||
|
||||
#############################################################################
|
||||
|
||||
#############################################################################
|
||||
def _detect_msgmerge(env):
|
||||
""" Detects *msgmerge(1)* program. """
|
||||
if 'MSGMERGE' in env:
|
||||
return env['MSGMERGE']
|
||||
msgmerge = env.Detect('msgmerge')
|
||||
if msgmerge:
|
||||
return msgmerge
|
||||
raise SCons.Errors.StopError(MsgmergeNotFound, "Could not detect msgmerge")
|
||||
return None
|
||||
|
||||
|
||||
#############################################################################
|
||||
def _msgmerge_exists(env):
|
||||
return _detect_msgmerge(env)
|
||||
|
||||
|
||||
#############################################################################
|
||||
|
||||
#############################################################################
|
||||
def _detect_msgfmt(env):
|
||||
""" Detects *msgmfmt(1)* program. """
|
||||
if 'MSGFMT' in env:
|
||||
return env['MSGFMT']
|
||||
msgfmt = env.Detect('msgfmt')
|
||||
if msgfmt:
|
||||
return msgfmt
|
||||
raise SCons.Errors.StopError(MsgfmtNotFound, "Could not detect msgfmt")
|
||||
return None
|
||||
|
||||
|
||||
#############################################################################
|
||||
def _msgfmt_exists(env):
|
||||
return _detect_msgfmt(env)
|
||||
|
||||
|
||||
#############################################################################
|
||||
|
||||
#############################################################################
|
||||
def tool_list(platform, env):
|
||||
""" List tools that shall be generated by top-level `gettext` tool """
|
||||
return ['xgettext', 'msginit', 'msgmerge', 'msgfmt']
|
||||
|
||||
#############################################################################
|
512
scons/scons-local-4.0.1/SCons/Tool/JavaCommon.py
Normal file
512
scons/scons-local-4.0.1/SCons/Tool/JavaCommon.py
Normal file
|
@ -0,0 +1,512 @@
|
|||
"""SCons.Tool.JavaCommon
|
||||
|
||||
Stuff for processing Java.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import re
|
||||
import glob
|
||||
|
||||
java_parsing = 1
|
||||
|
||||
default_java_version = '1.4'
|
||||
|
||||
# a switch for which jdk versions to use the Scope state for smarter
|
||||
# anonymous inner class parsing.
|
||||
scopeStateVersions = ('1.8',)
|
||||
|
||||
# Glob patterns for use in finding where the JDK is.
|
||||
# These are pairs, *dir_glob used in the general case,
|
||||
# *version_dir_glob if matching only a specific version.
|
||||
# For now only used for Windows.
|
||||
java_win32_dir_glob = 'C:/Program Files*/Java/jdk*/bin'
|
||||
# On windows, since Java 9, there is a dash between 'jdk' and the version
|
||||
# string that wasn't there before. this glob should catch either way.
|
||||
java_win32_version_dir_glob = 'C:/Program Files*/Java/jdk*%s*/bin'
|
||||
|
||||
# Glob patterns for use in finding where the JDK headers are.
|
||||
# These are pairs, *dir_glob used in the general case,
|
||||
# *version_dir_glob if matching only a specific version.
|
||||
java_macos_include_dir_glob = '/System/Library/Frameworks/JavaVM.framework/Headers/'
|
||||
java_macos_version_include_dir_glob = '/System/Library/Frameworks/JavaVM.framework/Versions/%s*/Headers/'
|
||||
|
||||
java_linux_include_dirs_glob = [
|
||||
'/usr/lib/jvm/default-java/include',
|
||||
'/usr/lib/jvm/java-*/include'
|
||||
]
|
||||
# Need to match path like below (from Centos 7)
|
||||
# /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.191.b12-0.el7_5.x86_64/include/
|
||||
java_linux_version_include_dirs_glob = [
|
||||
'/usr/lib/jvm/java-*-sun-%s*/include',
|
||||
'/usr/lib/jvm/java-%s*-openjdk*/include',
|
||||
'/usr/java/jdk%s*/include'
|
||||
]
|
||||
|
||||
if java_parsing:
|
||||
# Parse Java files for class names.
|
||||
#
|
||||
# This is a really cool parser from Charles Crain
|
||||
# that finds appropriate class names in Java source.
|
||||
|
||||
# A regular expression that will find, in a java file:
|
||||
# newlines;
|
||||
# double-backslashes;
|
||||
# a single-line comment "//";
|
||||
# single or double quotes preceeded by a backslash;
|
||||
# single quotes, double quotes, open or close braces, semi-colons,
|
||||
# periods, open or close parentheses;
|
||||
# floating-point numbers;
|
||||
# any alphanumeric token (keyword, class name, specifier);
|
||||
# any alphanumeric token surrounded by angle brackets (generics);
|
||||
# the multi-line comment begin and end tokens /* and */;
|
||||
# array declarations "[]".
|
||||
_reToken = re.compile(r'(\n|\\\\|//|\\[\'"]|[\'"{\};.()]|' +
|
||||
r'\d*\.\d*|[A-Za-z_][\w$.]*|<[A-Za-z_]\w+>|' +
|
||||
r'/\*|\*/|\[\])')
|
||||
|
||||
|
||||
class OuterState:
|
||||
"""The initial state for parsing a Java file for classes,
|
||||
interfaces, and anonymous inner classes."""
|
||||
|
||||
def __init__(self, version=default_java_version):
|
||||
|
||||
if version not in ('1.1', '1.2', '1.3', '1.4', '1.5', '1.6', '1.7',
|
||||
'1.8', '5', '6', '9.0', '10.0', '11.0', '12.0'):
|
||||
msg = "Java version %s not supported" % version
|
||||
raise NotImplementedError(msg)
|
||||
|
||||
self.version = version
|
||||
self.listClasses = []
|
||||
self.listOutputs = []
|
||||
self.stackBrackets = []
|
||||
self.brackets = 0
|
||||
self.nextAnon = 1
|
||||
self.localClasses = []
|
||||
self.stackAnonClassBrackets = []
|
||||
self.anonStacksStack = [[0]]
|
||||
self.package = None
|
||||
|
||||
def trace(self):
|
||||
pass
|
||||
|
||||
def __getClassState(self):
|
||||
try:
|
||||
return self.classState
|
||||
except AttributeError:
|
||||
ret = ClassState(self)
|
||||
self.classState = ret
|
||||
return ret
|
||||
|
||||
def __getPackageState(self):
|
||||
try:
|
||||
return self.packageState
|
||||
except AttributeError:
|
||||
ret = PackageState(self)
|
||||
self.packageState = ret
|
||||
return ret
|
||||
|
||||
def __getAnonClassState(self):
|
||||
try:
|
||||
return self.anonState
|
||||
except AttributeError:
|
||||
self.outer_state = self
|
||||
ret = SkipState(1, AnonClassState(self))
|
||||
self.anonState = ret
|
||||
return ret
|
||||
|
||||
def __getSkipState(self):
|
||||
try:
|
||||
return self.skipState
|
||||
except AttributeError:
|
||||
ret = SkipState(1, self)
|
||||
self.skipState = ret
|
||||
return ret
|
||||
|
||||
def _getAnonStack(self):
|
||||
return self.anonStacksStack[-1]
|
||||
|
||||
def openBracket(self):
|
||||
self.brackets = self.brackets + 1
|
||||
|
||||
def closeBracket(self):
|
||||
self.brackets = self.brackets - 1
|
||||
if len(self.stackBrackets) and \
|
||||
self.brackets == self.stackBrackets[-1]:
|
||||
self.listOutputs.append('$'.join(self.listClasses))
|
||||
self.localClasses.pop()
|
||||
self.listClasses.pop()
|
||||
self.anonStacksStack.pop()
|
||||
self.stackBrackets.pop()
|
||||
if len(self.stackAnonClassBrackets) and \
|
||||
self.brackets == self.stackAnonClassBrackets[-1] and \
|
||||
self.version not in scopeStateVersions:
|
||||
self._getAnonStack().pop()
|
||||
self.stackAnonClassBrackets.pop()
|
||||
|
||||
def parseToken(self, token):
|
||||
if token[:2] == '//':
|
||||
return IgnoreState('\n', self)
|
||||
elif token == '/*':
|
||||
return IgnoreState('*/', self)
|
||||
elif token == '{':
|
||||
self.openBracket()
|
||||
elif token == '}':
|
||||
self.closeBracket()
|
||||
elif token in ['"', "'"]:
|
||||
return IgnoreState(token, self)
|
||||
elif token == "new":
|
||||
# anonymous inner class
|
||||
if len(self.listClasses) > 0:
|
||||
return self.__getAnonClassState()
|
||||
return self.__getSkipState() # Skip the class name
|
||||
elif token in ['class', 'interface', 'enum']:
|
||||
if len(self.listClasses) == 0:
|
||||
self.nextAnon = 1
|
||||
self.stackBrackets.append(self.brackets)
|
||||
return self.__getClassState()
|
||||
elif token == 'package':
|
||||
return self.__getPackageState()
|
||||
elif token == '.':
|
||||
# Skip the attribute, it might be named "class", in which
|
||||
# case we don't want to treat the following token as
|
||||
# an inner class name...
|
||||
return self.__getSkipState()
|
||||
return self
|
||||
|
||||
def addAnonClass(self):
|
||||
"""Add an anonymous inner class"""
|
||||
if self.version in ('1.1', '1.2', '1.3', '1.4'):
|
||||
clazz = self.listClasses[0]
|
||||
self.listOutputs.append('%s$%d' % (clazz, self.nextAnon))
|
||||
elif self.version in ('1.5', '1.6', '1.7', '1.8', '5', '6', '9.0', '10.0', '11.0', '12.0'):
|
||||
self.stackAnonClassBrackets.append(self.brackets)
|
||||
className = []
|
||||
className.extend(self.listClasses)
|
||||
self._getAnonStack()[-1] = self._getAnonStack()[-1] + 1
|
||||
for anon in self._getAnonStack():
|
||||
className.append(str(anon))
|
||||
self.listOutputs.append('$'.join(className))
|
||||
|
||||
self.nextAnon = self.nextAnon + 1
|
||||
self._getAnonStack().append(0)
|
||||
|
||||
def setPackage(self, package):
|
||||
self.package = package
|
||||
|
||||
|
||||
class ScopeState:
|
||||
"""
|
||||
A state that parses code within a scope normally,
|
||||
within the confines of a scope.
|
||||
"""
|
||||
|
||||
def __init__(self, old_state):
|
||||
self.outer_state = old_state.outer_state
|
||||
self.old_state = old_state
|
||||
self.brackets = 0
|
||||
|
||||
def __getClassState(self):
|
||||
try:
|
||||
return self.classState
|
||||
except AttributeError:
|
||||
ret = ClassState(self)
|
||||
self.classState = ret
|
||||
return ret
|
||||
|
||||
def __getAnonClassState(self):
|
||||
try:
|
||||
return self.anonState
|
||||
except AttributeError:
|
||||
ret = SkipState(1, AnonClassState(self))
|
||||
self.anonState = ret
|
||||
return ret
|
||||
|
||||
def __getSkipState(self):
|
||||
try:
|
||||
return self.skipState
|
||||
except AttributeError:
|
||||
ret = SkipState(1, self)
|
||||
self.skipState = ret
|
||||
return ret
|
||||
|
||||
def openBracket(self):
|
||||
self.brackets = self.brackets + 1
|
||||
|
||||
def closeBracket(self):
|
||||
self.brackets = self.brackets - 1
|
||||
|
||||
def parseToken(self, token):
|
||||
# if self.brackets == 0:
|
||||
# return self.old_state.parseToken(token)
|
||||
if token[:2] == '//':
|
||||
return IgnoreState('\n', self)
|
||||
elif token == '/*':
|
||||
return IgnoreState('*/', self)
|
||||
elif token == '{':
|
||||
self.openBracket()
|
||||
elif token == '}':
|
||||
self.closeBracket()
|
||||
if self.brackets == 0:
|
||||
self.outer_state._getAnonStack().pop()
|
||||
return self.old_state
|
||||
elif token in ['"', "'"]:
|
||||
return IgnoreState(token, self)
|
||||
elif token == "new":
|
||||
# anonymous inner class
|
||||
return self.__getAnonClassState()
|
||||
elif token == '.':
|
||||
# Skip the attribute, it might be named "class", in which
|
||||
# case we don't want to treat the following token as
|
||||
# an inner class name...
|
||||
return self.__getSkipState()
|
||||
return self
|
||||
|
||||
|
||||
class AnonClassState:
|
||||
"""A state that looks for anonymous inner classes."""
|
||||
|
||||
def __init__(self, old_state):
|
||||
# outer_state is always an instance of OuterState
|
||||
self.outer_state = old_state.outer_state
|
||||
self.old_state = old_state
|
||||
self.brace_level = 0
|
||||
|
||||
def parseToken(self, token):
|
||||
# This is an anonymous class if and only if the next
|
||||
# non-whitespace token is a bracket. Everything between
|
||||
# braces should be parsed as normal java code.
|
||||
if token[:2] == '//':
|
||||
return IgnoreState('\n', self)
|
||||
elif token == '/*':
|
||||
return IgnoreState('*/', self)
|
||||
elif token == '\n':
|
||||
return self
|
||||
elif token[0] == '<' and token[-1] == '>':
|
||||
return self
|
||||
elif token == '(':
|
||||
self.brace_level = self.brace_level + 1
|
||||
return self
|
||||
if self.brace_level > 0:
|
||||
if token == 'new':
|
||||
# look further for anonymous inner class
|
||||
return SkipState(1, AnonClassState(self))
|
||||
elif token in ['"', "'"]:
|
||||
return IgnoreState(token, self)
|
||||
elif token == ')':
|
||||
self.brace_level = self.brace_level - 1
|
||||
return self
|
||||
if token == '{':
|
||||
self.outer_state.addAnonClass()
|
||||
if self.outer_state.version in scopeStateVersions:
|
||||
return ScopeState(old_state=self.old_state).parseToken(token)
|
||||
return self.old_state.parseToken(token)
|
||||
|
||||
|
||||
class SkipState:
|
||||
"""A state that will skip a specified number of tokens before
|
||||
reverting to the previous state."""
|
||||
|
||||
def __init__(self, tokens_to_skip, old_state):
|
||||
self.tokens_to_skip = tokens_to_skip
|
||||
self.old_state = old_state
|
||||
|
||||
def parseToken(self, token):
|
||||
self.tokens_to_skip = self.tokens_to_skip - 1
|
||||
if self.tokens_to_skip < 1:
|
||||
return self.old_state
|
||||
return self
|
||||
|
||||
|
||||
class ClassState:
|
||||
"""A state we go into when we hit a class or interface keyword."""
|
||||
|
||||
def __init__(self, outer_state):
|
||||
# outer_state is always an instance of OuterState
|
||||
self.outer_state = outer_state
|
||||
|
||||
def parseToken(self, token):
|
||||
# the next non-whitespace token should be the name of the class
|
||||
if token == '\n':
|
||||
return self
|
||||
# If that's an inner class which is declared in a method, it
|
||||
# requires an index prepended to the class-name, e.g.
|
||||
# 'Foo$1Inner'
|
||||
# https://github.com/SCons/scons/issues/2087
|
||||
if self.outer_state.localClasses and \
|
||||
self.outer_state.stackBrackets[-1] > \
|
||||
self.outer_state.stackBrackets[-2] + 1:
|
||||
locals = self.outer_state.localClasses[-1]
|
||||
try:
|
||||
idx = locals[token]
|
||||
locals[token] = locals[token] + 1
|
||||
except KeyError:
|
||||
locals[token] = 1
|
||||
token = str(locals[token]) + token
|
||||
self.outer_state.localClasses.append({})
|
||||
self.outer_state.listClasses.append(token)
|
||||
self.outer_state.anonStacksStack.append([0])
|
||||
return self.outer_state
|
||||
|
||||
|
||||
class IgnoreState:
|
||||
"""A state that will ignore all tokens until it gets to a
|
||||
specified token."""
|
||||
|
||||
def __init__(self, ignore_until, old_state):
|
||||
self.ignore_until = ignore_until
|
||||
self.old_state = old_state
|
||||
|
||||
def parseToken(self, token):
|
||||
if self.ignore_until == token:
|
||||
return self.old_state
|
||||
return self
|
||||
|
||||
|
||||
class PackageState:
|
||||
"""The state we enter when we encounter the package keyword.
|
||||
We assume the next token will be the package name."""
|
||||
|
||||
def __init__(self, outer_state):
|
||||
# outer_state is always an instance of OuterState
|
||||
self.outer_state = outer_state
|
||||
|
||||
def parseToken(self, token):
|
||||
self.outer_state.setPackage(token)
|
||||
return self.outer_state
|
||||
|
||||
|
||||
def parse_java_file(fn, version=default_java_version):
|
||||
with open(fn, 'r', encoding='utf-8') as f:
|
||||
data = f.read()
|
||||
return parse_java(data, version)
|
||||
|
||||
|
||||
def parse_java(contents, version=default_java_version, trace=None):
|
||||
"""Parse a .java file and return a double of package directory,
|
||||
plus a list of .class files that compiling that .java file will
|
||||
produce"""
|
||||
package = None
|
||||
initial = OuterState(version)
|
||||
currstate = initial
|
||||
for token in _reToken.findall(contents):
|
||||
# The regex produces a bunch of groups, but only one will
|
||||
# have anything in it.
|
||||
currstate = currstate.parseToken(token)
|
||||
if trace: trace(token, currstate)
|
||||
if initial.package:
|
||||
package = initial.package.replace('.', os.sep)
|
||||
return (package, initial.listOutputs)
|
||||
|
||||
else:
|
||||
# Don't actually parse Java files for class names.
|
||||
#
|
||||
# We might make this a configurable option in the future if
|
||||
# Java-file parsing takes too long (although it shouldn't relative
|
||||
# to how long the Java compiler itself seems to take...).
|
||||
|
||||
def parse_java_file(fn):
|
||||
""" "Parse" a .java file.
|
||||
|
||||
This actually just splits the file name, so the assumption here
|
||||
is that the file name matches the public class name, and that
|
||||
the path to the file is the same as the package name.
|
||||
"""
|
||||
return os.path.split(fn)
|
||||
|
||||
|
||||
def get_java_install_dirs(platform, version=None):
|
||||
"""
|
||||
Find the java jdk installation directories.
|
||||
|
||||
This list is intended to supply as "default paths" for use when looking
|
||||
up actual java binaries.
|
||||
|
||||
:param platform: selector for search algorithm.
|
||||
:param version: If specified, only look for java sdk's of this version
|
||||
:return: list of default paths for java.
|
||||
"""
|
||||
|
||||
paths = []
|
||||
if platform == 'win32':
|
||||
if version:
|
||||
paths = glob.glob(java_win32_version_dir_glob % version)
|
||||
else:
|
||||
paths = glob.glob(java_win32_dir_glob)
|
||||
else:
|
||||
# other platforms, do nothing for now
|
||||
pass
|
||||
|
||||
return sorted(paths)
|
||||
|
||||
|
||||
def get_java_include_paths(env, javac, version):
|
||||
"""
|
||||
Find java include paths for JNI building.
|
||||
|
||||
:param env: construction environment, used to extract platform.
|
||||
:param javac: path to detected javac.
|
||||
:return: list of paths.
|
||||
"""
|
||||
|
||||
paths = []
|
||||
if not javac:
|
||||
# there are no paths if we've not detected javac.
|
||||
pass
|
||||
elif env['PLATFORM'] == 'win32':
|
||||
# on Windows, we have the right path to javac, so look locally
|
||||
javac_bin_dir = os.path.dirname(javac)
|
||||
java_inc_dir = os.path.normpath(os.path.join(javac_bin_dir, '..', 'include'))
|
||||
paths = [java_inc_dir, os.path.join(java_inc_dir, 'win32')]
|
||||
elif env['PLATFORM'] == 'darwin':
|
||||
if not version:
|
||||
paths = [java_macos_include_dir_glob]
|
||||
else:
|
||||
paths = sorted(glob.glob(java_macos_version_include_dir_glob % version))
|
||||
else:
|
||||
base_paths = []
|
||||
if not version:
|
||||
for p in java_linux_include_dirs_glob:
|
||||
base_paths.extend(glob.glob(p))
|
||||
else:
|
||||
for p in java_linux_version_include_dirs_glob:
|
||||
base_paths.extend(glob.glob(p % version))
|
||||
|
||||
for p in base_paths:
|
||||
paths.extend([p, os.path.join(p, 'linux')])
|
||||
|
||||
# print("PATHS:%s"%paths)
|
||||
return paths
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
107
scons/scons-local-4.0.1/SCons/Tool/MSCommon/README
Normal file
107
scons/scons-local-4.0.1/SCons/Tool/MSCommon/README
Normal file
|
@ -0,0 +1,107 @@
|
|||
This is the flow of the compiler detection logic:
|
||||
|
||||
External to MSCommon:
|
||||
|
||||
The Tool init modules, in their exists() routines, call -> msvc_exists(env)
|
||||
|
||||
At the moment, those modules are:
|
||||
SCons/Tool/midl.py
|
||||
SCons/Tool/mslib.py
|
||||
SCons/Tool/mslink.py
|
||||
SCons/Tool/msvc.py
|
||||
SCons/Tool/msvs.py
|
||||
|
||||
env may contain a version request in MSVC_VERSION, but this is not used
|
||||
in the detection that follows from msvc_exists(), only in the later
|
||||
batch that starts with a call to msvc_setup_env().
|
||||
|
||||
Internal to MSCommon/vc.py:
|
||||
|
||||
+ MSCommon/vc.py:msvc_exists:
|
||||
| vcs = cached_get_installed_vcs(env)
|
||||
| returns True if vcs > 0
|
||||
|
|
||||
+-> MSCommon/vc.py:cached_get_installed_vcs:
|
||||
| checks global if we've run previously, if so return it
|
||||
| populate the global from -> get_installed_vcs(env)
|
||||
|
|
||||
+-> MSCommon/vc.py:get_installed_vcs:
|
||||
| loop through "known" versions of msvc, granularity is maj.min
|
||||
| check for product dir -> find_vc_pdir(env, ver)
|
||||
|
|
||||
+-> MSCommon/vc.py:find_vc_pdir:
|
||||
| From the msvc-version to pdir mapping dict, get reg key base and value
|
||||
| If value is none -> find_vc_pdir_vswhere(ver, env)
|
||||
|
|
||||
+-> MSCommon/vc.py:find_vc_pdir_vswhere:
|
||||
| From the vc-version to VS-version mapping table get string
|
||||
| Figure out where vswhere is -> msvc_find_vswhere()
|
||||
| Use subprocess to call vswhere, return first line of match
|
||||
/
|
||||
| else get product directory from registry (<= 14.0)
|
||||
/
|
||||
| if we found one -> _check_cl_exists_in_vc_dir(env, pdir, ver)
|
||||
|
|
||||
+-> MSCommon/vc.py:_check_cl_exists_in_vc_dir:
|
||||
| Figure out host/target pair
|
||||
| if version > 14.0 get specific version by looking in
|
||||
| pdir + Auxiliary/Build/Microsoft/VCToolsVersion/default.txt
|
||||
| look for pdir + Tools/MSVC/{specver}/bin/host/target/cl.exe
|
||||
| if 14.0 or less, "do older stuff"
|
||||
|
||||
All of this just got us a yes-no answer on whether /some/ msvc version
|
||||
exists, but does populate __INSTALLED_VCS_RUN with all of the top-level
|
||||
versions as noted for get_installed_vcs
|
||||
|
||||
Externally:
|
||||
|
||||
Once a module's exists() has been called (or, in the case of
|
||||
clang/clangxx, after the compiler has been detected by other means -
|
||||
those still expect the rest of the msvc chain but not cl.exe)
|
||||
the module's generate() function calls -> msvc_setup_env_once(env)
|
||||
|
||||
Internally:
|
||||
|
||||
+ MSCommon/vc.py:msvc_setup_env_once:
|
||||
| checks for environment flag MSVC_SETUP_RUN
|
||||
| if not, -> msvc_setup_env(env) and set flag
|
||||
|
|
||||
+-+ MSCommon/vc.py:msvc_setup_env:
|
||||
| set ver from -> get_default_version(env)
|
||||
|
|
||||
+-+ MSCommon/vc.py:get_default_version:
|
||||
| if no version specified in env.MSVC_VERSION:
|
||||
| return first entry from -> cached_get_installed_vcs(env)
|
||||
| else return requested version
|
||||
/
|
||||
| get script from MSVC_USE_SCRIPT if set to a filename
|
||||
| -> script_env(script)
|
||||
|
|
||||
+-+ MSCommon/vc.py:script_env:
|
||||
| return (possibly cached) script variables matching script arg
|
||||
/
|
||||
| else -> msvc_find_valid_batch_script(env, version)
|
||||
|
|
||||
+-+ MSCommon/vc.py:msvc_find_valid_batch_script:
|
||||
| Build a list of plausible target values, and loop through
|
||||
| look for host + target -> find_batch_file(env, ver, host, target)
|
||||
|
|
||||
+-+ MSCommon/vc.py:find_batch_file:
|
||||
| call -> find_vc_pdir (see above)
|
||||
| use the return to construct a version-biased batfile path, check
|
||||
/
|
||||
| if not found, try sdk scripts (unknown if this is still useful)
|
||||
|
||||
|
||||
Problems:
|
||||
- For VS >= 2017, VS and VS are not 1:1, there can be many VC for one VS
|
||||
- For vswhere-ready versions, detection does not proceed beyond the
|
||||
product level ("2019") into individual "features" (individual msvc)
|
||||
- As documented for MSVC_VERSION, compilers can only be requested if versions
|
||||
are from the set in _VCVER, so 14.1 but not 14.16 or 14.16.27023
|
||||
- Information found in the first pass (msvs_exists) isn't really
|
||||
available anywhere except the cached version list, since we just
|
||||
return true/false.
|
||||
- Since msvc_exists chain of calls does not look at version, we
|
||||
can proceed to compiler setup if *any* msvc was found, even if the
|
||||
one requested wasn't found.
|
58
scons/scons-local-4.0.1/SCons/Tool/MSCommon/__init__.py
Normal file
58
scons/scons-local-4.0.1/SCons/Tool/MSCommon/__init__.py
Normal file
|
@ -0,0 +1,58 @@
|
|||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
__doc__ = """
|
||||
Common functions for Microsoft Visual Studio and Visual C/C++.
|
||||
"""
|
||||
|
||||
import copy
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
import SCons.Errors
|
||||
import SCons.Platform.win32
|
||||
import SCons.Util
|
||||
|
||||
from SCons.Tool.MSCommon.sdk import mssdk_exists, \
|
||||
mssdk_setup_env
|
||||
|
||||
from SCons.Tool.MSCommon.vc import msvc_exists, \
|
||||
msvc_setup_env, \
|
||||
msvc_setup_env_once, \
|
||||
msvc_version_to_maj_min, \
|
||||
msvc_find_vswhere
|
||||
|
||||
from SCons.Tool.MSCommon.vs import get_default_version, \
|
||||
get_vs_by_version, \
|
||||
merge_default_version, \
|
||||
msvs_exists, \
|
||||
query_versions
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
67
scons/scons-local-4.0.1/SCons/Tool/MSCommon/arch.py
Normal file
67
scons/scons-local-4.0.1/SCons/Tool/MSCommon/arch.py
Normal file
|
@ -0,0 +1,67 @@
|
|||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
__doc__ = """Module to define supported Windows chip architectures.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
class ArchDefinition:
|
||||
"""
|
||||
A class for defining architecture-specific settings and logic.
|
||||
"""
|
||||
def __init__(self, arch, synonyms=[]):
|
||||
self.arch = arch
|
||||
self.synonyms = synonyms
|
||||
|
||||
SupportedArchitectureList = [
|
||||
ArchDefinition(
|
||||
'x86',
|
||||
['i386', 'i486', 'i586', 'i686'],
|
||||
),
|
||||
|
||||
ArchDefinition(
|
||||
'x86_64',
|
||||
['AMD64', 'amd64', 'em64t', 'EM64T', 'x86_64'],
|
||||
),
|
||||
|
||||
ArchDefinition(
|
||||
'ia64',
|
||||
['IA64'],
|
||||
),
|
||||
|
||||
ArchDefinition(
|
||||
'arm',
|
||||
['ARM'],
|
||||
),
|
||||
|
||||
]
|
||||
|
||||
SupportedArchitectureMap = {}
|
||||
for a in SupportedArchitectureList:
|
||||
SupportedArchitectureMap[a.arch] = a
|
||||
for s in a.synonyms:
|
||||
SupportedArchitectureMap[s] = a
|
||||
|
326
scons/scons-local-4.0.1/SCons/Tool/MSCommon/common.py
Normal file
326
scons/scons-local-4.0.1/SCons/Tool/MSCommon/common.py
Normal file
|
@ -0,0 +1,326 @@
|
|||
"""
|
||||
Common helper functions for working with the Microsoft tool chain.
|
||||
"""
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import copy
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import SCons.Util
|
||||
|
||||
# SCONS_MSCOMMON_DEBUG is internal-use so undocumented:
|
||||
# set to '-' to print to console, else set to filename to log to
|
||||
LOGFILE = os.environ.get('SCONS_MSCOMMON_DEBUG')
|
||||
if LOGFILE == '-':
|
||||
def debug(message):
|
||||
print(message)
|
||||
elif LOGFILE:
|
||||
import logging
|
||||
logging.basicConfig(
|
||||
# This looks like:
|
||||
# 00109ms:MSCommon/vc.py:find_vc_pdir#447:
|
||||
format=(
|
||||
'%(relativeCreated)05dms'
|
||||
':MSCommon/%(filename)s'
|
||||
':%(funcName)s'
|
||||
'#%(lineno)s'
|
||||
':%(message)s: '
|
||||
),
|
||||
filename=LOGFILE,
|
||||
level=logging.DEBUG)
|
||||
debug = logging.getLogger(name=__name__).debug
|
||||
else:
|
||||
def debug(x): return None
|
||||
|
||||
|
||||
# SCONS_CACHE_MSVC_CONFIG is public, and is documented.
|
||||
CONFIG_CACHE = os.environ.get('SCONS_CACHE_MSVC_CONFIG')
|
||||
if CONFIG_CACHE in ('1', 'true', 'True'):
|
||||
CONFIG_CACHE = os.path.join(os.path.expanduser('~'), '.scons_msvc_cache')
|
||||
|
||||
|
||||
def read_script_env_cache():
|
||||
""" fetch cached msvc env vars if requested, else return empty dict """
|
||||
envcache = {}
|
||||
if CONFIG_CACHE:
|
||||
try:
|
||||
with open(CONFIG_CACHE, 'r') as f:
|
||||
envcache = json.load(f)
|
||||
except FileNotFoundError:
|
||||
# don't fail if no cache file, just proceed without it
|
||||
pass
|
||||
return envcache
|
||||
|
||||
|
||||
def write_script_env_cache(cache):
|
||||
""" write out cache of msvc env vars if requested """
|
||||
if CONFIG_CACHE:
|
||||
try:
|
||||
with open(CONFIG_CACHE, 'w') as f:
|
||||
json.dump(cache, f, indent=2)
|
||||
except TypeError:
|
||||
# data can't serialize to json, don't leave partial file
|
||||
os.remove(CONFIG_CACHE)
|
||||
except IOError:
|
||||
# can't write the file, just skip
|
||||
pass
|
||||
|
||||
|
||||
_is_win64 = None
|
||||
|
||||
|
||||
def is_win64():
|
||||
"""Return true if running on windows 64 bits.
|
||||
|
||||
Works whether python itself runs in 64 bits or 32 bits."""
|
||||
# Unfortunately, python does not provide a useful way to determine
|
||||
# if the underlying Windows OS is 32-bit or 64-bit. Worse, whether
|
||||
# the Python itself is 32-bit or 64-bit affects what it returns,
|
||||
# so nothing in sys.* or os.* help.
|
||||
|
||||
# Apparently the best solution is to use env vars that Windows
|
||||
# sets. If PROCESSOR_ARCHITECTURE is not x86, then the python
|
||||
# process is running in 64 bit mode (on a 64-bit OS, 64-bit
|
||||
# hardware, obviously).
|
||||
# If this python is 32-bit but the OS is 64, Windows will set
|
||||
# ProgramW6432 and PROCESSOR_ARCHITEW6432 to non-null.
|
||||
# (Checking for HKLM\Software\Wow6432Node in the registry doesn't
|
||||
# work, because some 32-bit installers create it.)
|
||||
global _is_win64
|
||||
if _is_win64 is None:
|
||||
# I structured these tests to make it easy to add new ones or
|
||||
# add exceptions in the future, because this is a bit fragile.
|
||||
_is_win64 = False
|
||||
if os.environ.get('PROCESSOR_ARCHITECTURE', 'x86') != 'x86':
|
||||
_is_win64 = True
|
||||
if os.environ.get('PROCESSOR_ARCHITEW6432'):
|
||||
_is_win64 = True
|
||||
if os.environ.get('ProgramW6432'):
|
||||
_is_win64 = True
|
||||
return _is_win64
|
||||
|
||||
|
||||
def read_reg(value, hkroot=SCons.Util.HKEY_LOCAL_MACHINE):
|
||||
return SCons.Util.RegGetValue(hkroot, value)[0]
|
||||
|
||||
|
||||
def has_reg(value):
|
||||
"""Return True if the given key exists in HKEY_LOCAL_MACHINE, False
|
||||
otherwise."""
|
||||
try:
|
||||
SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE, value)
|
||||
ret = True
|
||||
except SCons.Util.WinError:
|
||||
ret = False
|
||||
return ret
|
||||
|
||||
# Functions for fetching environment variable settings from batch files.
|
||||
|
||||
|
||||
def normalize_env(env, keys, force=False):
|
||||
"""Given a dictionary representing a shell environment, add the variables
|
||||
from os.environ needed for the processing of .bat files; the keys are
|
||||
controlled by the keys argument.
|
||||
|
||||
It also makes sure the environment values are correctly encoded.
|
||||
|
||||
If force=True, then all of the key values that exist are copied
|
||||
into the returned dictionary. If force=false, values are only
|
||||
copied if the key does not already exist in the copied dictionary.
|
||||
|
||||
Note: the environment is copied."""
|
||||
normenv = {}
|
||||
if env:
|
||||
for k, v in env.items():
|
||||
normenv[k] = copy.deepcopy(v)
|
||||
|
||||
for k in keys:
|
||||
if k in os.environ and (force or k not in normenv):
|
||||
normenv[k] = os.environ[k]
|
||||
|
||||
# add some things to PATH to prevent problems:
|
||||
# Shouldn't be necessary to add system32, since the default environment
|
||||
# should include it, but keep this here to be safe (needed for reg.exe)
|
||||
sys32_dir = os.path.join(
|
||||
os.environ.get("SystemRoot", os.environ.get("windir", r"C:\Windows")), "System32"
|
||||
)
|
||||
if sys32_dir not in normenv["PATH"]:
|
||||
normenv["PATH"] = normenv["PATH"] + os.pathsep + sys32_dir
|
||||
|
||||
# Without Wbem in PATH, vcvarsall.bat has a "'wmic' is not recognized"
|
||||
# error starting with Visual Studio 2017, although the script still
|
||||
# seems to work anyway.
|
||||
sys32_wbem_dir = os.path.join(sys32_dir, 'Wbem')
|
||||
if sys32_wbem_dir not in normenv['PATH']:
|
||||
normenv['PATH'] = normenv['PATH'] + os.pathsep + sys32_wbem_dir
|
||||
|
||||
# Without Powershell in PATH, an internal call to a telemetry
|
||||
# function (starting with a VS2019 update) can fail
|
||||
# Note can also set VSCMD_SKIP_SENDTELEMETRY to avoid this.
|
||||
sys32_ps_dir = os.path.join(sys32_dir, r'WindowsPowerShell\v1.0')
|
||||
if sys32_ps_dir not in normenv['PATH']:
|
||||
normenv['PATH'] = normenv['PATH'] + os.pathsep + sys32_ps_dir
|
||||
|
||||
debug("PATH: %s" % normenv['PATH'])
|
||||
return normenv
|
||||
|
||||
|
||||
def get_output(vcbat, args=None, env=None):
|
||||
"""Parse the output of given bat file, with given args."""
|
||||
|
||||
if env is None:
|
||||
# Create a blank environment, for use in launching the tools
|
||||
env = SCons.Environment.Environment(tools=[])
|
||||
|
||||
# TODO: Hard-coded list of the variables that (may) need to be
|
||||
# imported from os.environ[] for the chain of development batch
|
||||
# files to execute correctly. One call to vcvars*.bat may
|
||||
# end up running a dozen or more scripts, changes not only with
|
||||
# each release but with what is installed at the time. We think
|
||||
# in modern installations most are set along the way and don't
|
||||
# need to be picked from the env, but include these for safety's sake.
|
||||
# Any VSCMD variables definitely are picked from the env and
|
||||
# control execution in interesting ways.
|
||||
# Note these really should be unified - either controlled by vs.py,
|
||||
# or synced with the the common_tools_var # settings in vs.py.
|
||||
vs_vc_vars = [
|
||||
'COMSPEC', # path to "shell"
|
||||
'VS160COMNTOOLS', # path to common tools for given version
|
||||
'VS150COMNTOOLS',
|
||||
'VS140COMNTOOLS',
|
||||
'VS120COMNTOOLS',
|
||||
'VS110COMNTOOLS',
|
||||
'VS100COMNTOOLS',
|
||||
'VS90COMNTOOLS',
|
||||
'VS80COMNTOOLS',
|
||||
'VS71COMNTOOLS',
|
||||
'VS70COMNTOOLS',
|
||||
'VS60COMNTOOLS',
|
||||
'VSCMD_DEBUG', # enable logging and other debug aids
|
||||
'VSCMD_SKIP_SENDTELEMETRY',
|
||||
]
|
||||
env['ENV'] = normalize_env(env['ENV'], vs_vc_vars, force=False)
|
||||
|
||||
if args:
|
||||
debug("Calling '%s %s'" % (vcbat, args))
|
||||
popen = SCons.Action._subproc(env,
|
||||
'"%s" %s & set' % (vcbat, args),
|
||||
stdin='devnull',
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
else:
|
||||
debug("Calling '%s'" % vcbat)
|
||||
popen = SCons.Action._subproc(env,
|
||||
'"%s" & set' % vcbat,
|
||||
stdin='devnull',
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
|
||||
# Use the .stdout and .stderr attributes directly because the
|
||||
# .communicate() method uses the threading module on Windows
|
||||
# and won't work under Pythons not built with threading.
|
||||
with popen.stdout:
|
||||
stdout = popen.stdout.read()
|
||||
with popen.stderr:
|
||||
stderr = popen.stderr.read()
|
||||
|
||||
# Extra debug logic, uncomment if necessary
|
||||
# debug('stdout:%s' % stdout)
|
||||
# debug('stderr:%s' % stderr)
|
||||
|
||||
# Ongoing problems getting non-corrupted text led to this
|
||||
# changing to "oem" from "mbcs" - the scripts run presumably
|
||||
# attached to a console, so some particular rules apply.
|
||||
# Unfortunately, "oem" not defined in Python 3.5, so get another way
|
||||
if sys.version_info.major == 3 and sys.version_info.minor < 6:
|
||||
from ctypes import windll
|
||||
|
||||
OEM = "cp{}".format(windll.kernel32.GetConsoleOutputCP())
|
||||
else:
|
||||
OEM = "oem"
|
||||
if stderr:
|
||||
# TODO: find something better to do with stderr;
|
||||
# this at least prevents errors from getting swallowed.
|
||||
sys.stderr.write(stderr.decode(OEM))
|
||||
if popen.wait() != 0:
|
||||
raise IOError(stderr.decode(OEM))
|
||||
|
||||
return stdout.decode(OEM)
|
||||
|
||||
|
||||
KEEPLIST = (
|
||||
"INCLUDE",
|
||||
"LIB",
|
||||
"LIBPATH",
|
||||
"PATH",
|
||||
"VSCMD_ARG_app_plat",
|
||||
"VCINSTALLDIR", # needed by clang -VS 2017 and newer
|
||||
"VCToolsInstallDir", # needed by clang - VS 2015 and older
|
||||
)
|
||||
|
||||
|
||||
def parse_output(output, keep=KEEPLIST):
|
||||
"""
|
||||
Parse output from running visual c++/studios vcvarsall.bat and running set
|
||||
To capture the values listed in keep
|
||||
"""
|
||||
|
||||
# dkeep is a dict associating key: path_list, where key is one item from
|
||||
# keep, and path_list the associated list of paths
|
||||
dkeep = dict([(i, []) for i in keep])
|
||||
|
||||
# rdk will keep the regex to match the .bat file output line starts
|
||||
rdk = {}
|
||||
for i in keep:
|
||||
rdk[i] = re.compile('%s=(.*)' % i, re.I)
|
||||
|
||||
def add_env(rmatch, key, dkeep=dkeep):
|
||||
path_list = rmatch.group(1).split(os.pathsep)
|
||||
for path in path_list:
|
||||
# Do not add empty paths (when a var ends with ;)
|
||||
if path:
|
||||
# XXX: For some reason, VC98 .bat file adds "" around the PATH
|
||||
# values, and it screws up the environment later, so we strip
|
||||
# it.
|
||||
path = path.strip('"')
|
||||
dkeep[key].append(str(path))
|
||||
|
||||
for line in output.splitlines():
|
||||
for k, value in rdk.items():
|
||||
match = value.match(line)
|
||||
if match:
|
||||
add_env(match, k)
|
||||
|
||||
return dkeep
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
83
scons/scons-local-4.0.1/SCons/Tool/MSCommon/netframework.py
Normal file
83
scons/scons-local-4.0.1/SCons/Tool/MSCommon/netframework.py
Normal file
|
@ -0,0 +1,83 @@
|
|||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
__doc__ = """
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import SCons.Util
|
||||
|
||||
from .common import read_reg, debug
|
||||
|
||||
# Original value recorded by dcournapeau
|
||||
_FRAMEWORKDIR_HKEY_ROOT = r'Software\Microsoft\.NETFramework\InstallRoot'
|
||||
# On SGK's system
|
||||
_FRAMEWORKDIR_HKEY_ROOT = r'Software\Microsoft\Microsoft SDKs\.NETFramework\v2.0\InstallationFolder'
|
||||
|
||||
def find_framework_root():
|
||||
# XXX: find it from environment (FrameworkDir)
|
||||
try:
|
||||
froot = read_reg(_FRAMEWORKDIR_HKEY_ROOT)
|
||||
debug("Found framework install root in registry: {}".format(froot))
|
||||
except SCons.Util.WinError as e:
|
||||
debug("Could not read reg key {}".format(_FRAMEWORKDIR_HKEY_ROOT))
|
||||
return None
|
||||
|
||||
if not os.path.exists(froot):
|
||||
debug("{} not found on fs".format(froot))
|
||||
return None
|
||||
|
||||
return froot
|
||||
|
||||
def query_versions():
|
||||
froot = find_framework_root()
|
||||
if froot:
|
||||
contents = os.listdir(froot)
|
||||
|
||||
l = re.compile('v[0-9]+.*')
|
||||
versions = [e for e in contents if l.match(e)]
|
||||
|
||||
def versrt(a,b):
|
||||
# since version numbers aren't really floats...
|
||||
aa = a[1:]
|
||||
bb = b[1:]
|
||||
aal = aa.split('.')
|
||||
bbl = bb.split('.')
|
||||
# sequence comparison in python is lexicographical
|
||||
# which is exactly what we want.
|
||||
# Note we sort backwards so the highest version is first.
|
||||
return (aal > bbl) - (aal < bbl)
|
||||
|
||||
versions.sort(versrt)
|
||||
else:
|
||||
versions = []
|
||||
|
||||
return versions
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
411
scons/scons-local-4.0.1/SCons/Tool/MSCommon/sdk.py
Normal file
411
scons/scons-local-4.0.1/SCons/Tool/MSCommon/sdk.py
Normal file
|
@ -0,0 +1,411 @@
|
|||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
__doc__ = """Module to detect the Platform/Windows SDK
|
||||
|
||||
PSDK 2003 R1 is the earliest version detected.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
import SCons.Errors
|
||||
import SCons.Util
|
||||
|
||||
from .common import debug, read_reg
|
||||
|
||||
# SDK Checks. This is of course a mess as everything else on MS platforms. Here
|
||||
# is what we do to detect the SDK:
|
||||
#
|
||||
# For Windows SDK >= 6.0: just look into the registry entries:
|
||||
# HKLM\Software\Microsoft\Microsoft SDKs\Windows
|
||||
# All the keys in there are the available versions.
|
||||
#
|
||||
# For Platform SDK before 6.0 (2003 server R1 and R2, etc...), there does not
|
||||
# seem to be any sane registry key, so the precise location is hardcoded.
|
||||
#
|
||||
# For versions below 2003R1, it seems the PSDK is included with Visual Studio?
|
||||
#
|
||||
# Also, per the following:
|
||||
# http://benjamin.smedbergs.us/blog/tag/atl/
|
||||
# VC++ Professional comes with the SDK, VC++ Express does not.
|
||||
|
||||
# Location of the SDK (checked for 6.1 only)
|
||||
_CURINSTALLED_SDK_HKEY_ROOT = \
|
||||
r"Software\Microsoft\Microsoft SDKs\Windows\CurrentInstallFolder"
|
||||
|
||||
|
||||
class SDKDefinition:
|
||||
"""
|
||||
An abstract base class for trying to find installed SDK directories.
|
||||
"""
|
||||
def __init__(self, version, **kw):
|
||||
self.version = version
|
||||
self.__dict__.update(kw)
|
||||
|
||||
def find_sdk_dir(self):
|
||||
"""Try to find the MS SDK from the registry.
|
||||
|
||||
Return None if failed or the directory does not exist.
|
||||
"""
|
||||
if not SCons.Util.can_read_reg:
|
||||
debug('find_sdk_dir(): can not read registry')
|
||||
return None
|
||||
|
||||
hkey = self.HKEY_FMT % self.hkey_data
|
||||
debug('find_sdk_dir(): checking registry:{}'.format(hkey))
|
||||
|
||||
try:
|
||||
sdk_dir = read_reg(hkey)
|
||||
except SCons.Util.WinError as e:
|
||||
debug('find_sdk_dir(): no SDK registry key {}'.format(repr(hkey)))
|
||||
return None
|
||||
|
||||
debug('find_sdk_dir(): Trying SDK Dir: {}'.format(sdk_dir))
|
||||
|
||||
if not os.path.exists(sdk_dir):
|
||||
debug('find_sdk_dir(): {} not on file system'.format(sdk_dir))
|
||||
return None
|
||||
|
||||
ftc = os.path.join(sdk_dir, self.sanity_check_file)
|
||||
if not os.path.exists(ftc):
|
||||
debug("find_sdk_dir(): sanity check {} not found".format(ftc))
|
||||
return None
|
||||
|
||||
return sdk_dir
|
||||
|
||||
def get_sdk_dir(self):
|
||||
"""Return the MSSSDK given the version string."""
|
||||
try:
|
||||
return self._sdk_dir
|
||||
except AttributeError:
|
||||
sdk_dir = self.find_sdk_dir()
|
||||
self._sdk_dir = sdk_dir
|
||||
return sdk_dir
|
||||
|
||||
def get_sdk_vc_script(self,host_arch, target_arch):
|
||||
""" Return the script to initialize the VC compiler installed by SDK
|
||||
"""
|
||||
|
||||
if host_arch == 'amd64' and target_arch == 'x86':
|
||||
# No cross tools needed compiling 32 bits on 64 bit machine
|
||||
host_arch=target_arch
|
||||
|
||||
arch_string=target_arch
|
||||
if host_arch != target_arch:
|
||||
arch_string='%s_%s'%(host_arch,target_arch)
|
||||
|
||||
debug("get_sdk_vc_script():arch_string:%s host_arch:%s target_arch:%s"%(arch_string,
|
||||
host_arch,
|
||||
target_arch))
|
||||
file=self.vc_setup_scripts.get(arch_string,None)
|
||||
debug("get_sdk_vc_script():file:%s"%file)
|
||||
return file
|
||||
|
||||
class WindowsSDK(SDKDefinition):
|
||||
"""
|
||||
A subclass for trying to find installed Windows SDK directories.
|
||||
"""
|
||||
HKEY_FMT = r'Software\Microsoft\Microsoft SDKs\Windows\v%s\InstallationFolder'
|
||||
def __init__(self, *args, **kw):
|
||||
SDKDefinition.__init__(self, *args, **kw)
|
||||
self.hkey_data = self.version
|
||||
|
||||
class PlatformSDK(SDKDefinition):
|
||||
"""
|
||||
A subclass for trying to find installed Platform SDK directories.
|
||||
"""
|
||||
HKEY_FMT = r'Software\Microsoft\MicrosoftSDK\InstalledSDKS\%s\Install Dir'
|
||||
def __init__(self, *args, **kw):
|
||||
SDKDefinition.__init__(self, *args, **kw)
|
||||
self.hkey_data = self.uuid
|
||||
|
||||
#
|
||||
# The list of VC initialization scripts installed by the SDK
|
||||
# These should be tried if the vcvarsall.bat TARGET_ARCH fails
|
||||
preSDK61VCSetupScripts = { 'x86' : r'bin\vcvars32.bat',
|
||||
'amd64' : r'bin\vcvarsamd64.bat',
|
||||
'x86_amd64': r'bin\vcvarsx86_amd64.bat',
|
||||
'x86_ia64' : r'bin\vcvarsx86_ia64.bat',
|
||||
'ia64' : r'bin\vcvarsia64.bat'}
|
||||
|
||||
SDK61VCSetupScripts = {'x86' : r'bin\vcvars32.bat',
|
||||
'amd64' : r'bin\amd64\vcvarsamd64.bat',
|
||||
'x86_amd64': r'bin\x86_amd64\vcvarsx86_amd64.bat',
|
||||
'x86_ia64' : r'bin\x86_ia64\vcvarsx86_ia64.bat',
|
||||
'ia64' : r'bin\ia64\vcvarsia64.bat'}
|
||||
|
||||
SDK70VCSetupScripts = { 'x86' : r'bin\vcvars32.bat',
|
||||
'amd64' : r'bin\vcvars64.bat',
|
||||
'x86_amd64': r'bin\vcvarsx86_amd64.bat',
|
||||
'x86_ia64' : r'bin\vcvarsx86_ia64.bat',
|
||||
'ia64' : r'bin\vcvarsia64.bat'}
|
||||
|
||||
SDK100VCSetupScripts = {'x86' : r'bin\vcvars32.bat',
|
||||
'amd64' : r'bin\vcvars64.bat',
|
||||
'x86_amd64': r'bin\x86_amd64\vcvarsx86_amd64.bat',
|
||||
'x86_arm' : r'bin\x86_arm\vcvarsx86_arm.bat'}
|
||||
|
||||
|
||||
# The list of support SDKs which we know how to detect.
|
||||
#
|
||||
# The first SDK found in the list is the one used by default if there
|
||||
# are multiple SDKs installed. Barring good reasons to the contrary,
|
||||
# this means we should list SDKs from most recent to oldest.
|
||||
#
|
||||
# If you update this list, update the documentation in Tool/mssdk.xml.
|
||||
SupportedSDKList = [
|
||||
WindowsSDK('10.0A',
|
||||
sanity_check_file=r'bin\SetEnv.Cmd',
|
||||
include_subdir='include',
|
||||
lib_subdir={
|
||||
'x86' : ['lib'],
|
||||
'x86_64' : [r'lib\x64'],
|
||||
'ia64' : [r'lib\ia64'],
|
||||
},
|
||||
vc_setup_scripts = SDK70VCSetupScripts,
|
||||
),
|
||||
WindowsSDK('10.0',
|
||||
sanity_check_file=r'bin\SetEnv.Cmd',
|
||||
include_subdir='include',
|
||||
lib_subdir={
|
||||
'x86' : ['lib'],
|
||||
'x86_64' : [r'lib\x64'],
|
||||
'ia64' : [r'lib\ia64'],
|
||||
},
|
||||
vc_setup_scripts = SDK70VCSetupScripts,
|
||||
),
|
||||
WindowsSDK('7.1',
|
||||
sanity_check_file=r'bin\SetEnv.Cmd',
|
||||
include_subdir='include',
|
||||
lib_subdir={
|
||||
'x86' : ['lib'],
|
||||
'x86_64' : [r'lib\x64'],
|
||||
'ia64' : [r'lib\ia64'],
|
||||
},
|
||||
vc_setup_scripts = SDK70VCSetupScripts,
|
||||
),
|
||||
WindowsSDK('7.0A',
|
||||
sanity_check_file=r'bin\SetEnv.Cmd',
|
||||
include_subdir='include',
|
||||
lib_subdir={
|
||||
'x86' : ['lib'],
|
||||
'x86_64' : [r'lib\x64'],
|
||||
'ia64' : [r'lib\ia64'],
|
||||
},
|
||||
vc_setup_scripts = SDK70VCSetupScripts,
|
||||
),
|
||||
WindowsSDK('7.0',
|
||||
sanity_check_file=r'bin\SetEnv.Cmd',
|
||||
include_subdir='include',
|
||||
lib_subdir={
|
||||
'x86' : ['lib'],
|
||||
'x86_64' : [r'lib\x64'],
|
||||
'ia64' : [r'lib\ia64'],
|
||||
},
|
||||
vc_setup_scripts = SDK70VCSetupScripts,
|
||||
),
|
||||
WindowsSDK('6.1',
|
||||
sanity_check_file=r'bin\SetEnv.Cmd',
|
||||
include_subdir='include',
|
||||
lib_subdir={
|
||||
'x86' : ['lib'],
|
||||
'x86_64' : [r'lib\x64'],
|
||||
'ia64' : [r'lib\ia64'],
|
||||
},
|
||||
vc_setup_scripts = SDK61VCSetupScripts,
|
||||
),
|
||||
|
||||
WindowsSDK('6.0A',
|
||||
sanity_check_file=r'include\windows.h',
|
||||
include_subdir='include',
|
||||
lib_subdir={
|
||||
'x86' : ['lib'],
|
||||
'x86_64' : [r'lib\x64'],
|
||||
'ia64' : [r'lib\ia64'],
|
||||
},
|
||||
vc_setup_scripts = preSDK61VCSetupScripts,
|
||||
),
|
||||
|
||||
WindowsSDK('6.0',
|
||||
sanity_check_file=r'bin\gacutil.exe',
|
||||
include_subdir='include',
|
||||
lib_subdir='lib',
|
||||
vc_setup_scripts = preSDK61VCSetupScripts,
|
||||
),
|
||||
|
||||
PlatformSDK('2003R2',
|
||||
sanity_check_file=r'SetEnv.Cmd',
|
||||
uuid="D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1",
|
||||
vc_setup_scripts = preSDK61VCSetupScripts,
|
||||
),
|
||||
|
||||
PlatformSDK('2003R1',
|
||||
sanity_check_file=r'SetEnv.Cmd',
|
||||
uuid="8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3",
|
||||
vc_setup_scripts = preSDK61VCSetupScripts,
|
||||
),
|
||||
]
|
||||
|
||||
SupportedSDKMap = {}
|
||||
for sdk in SupportedSDKList:
|
||||
SupportedSDKMap[sdk.version] = sdk
|
||||
|
||||
|
||||
# Finding installed SDKs isn't cheap, because it goes not only to the
|
||||
# registry but also to the disk to sanity-check that there is, in fact,
|
||||
# an SDK installed there and that the registry entry isn't just stale.
|
||||
# Find this information once, when requested, and cache it.
|
||||
|
||||
InstalledSDKList = None
|
||||
InstalledSDKMap = None
|
||||
|
||||
def get_installed_sdks():
|
||||
global InstalledSDKList
|
||||
global InstalledSDKMap
|
||||
debug('get_installed_sdks()')
|
||||
if InstalledSDKList is None:
|
||||
InstalledSDKList = []
|
||||
InstalledSDKMap = {}
|
||||
for sdk in SupportedSDKList:
|
||||
debug('trying to find SDK %s' % sdk.version)
|
||||
if sdk.get_sdk_dir():
|
||||
debug('found SDK %s' % sdk.version)
|
||||
InstalledSDKList.append(sdk)
|
||||
InstalledSDKMap[sdk.version] = sdk
|
||||
return InstalledSDKList
|
||||
|
||||
|
||||
# We may be asked to update multiple construction environments with
|
||||
# SDK information. When doing this, we check on-disk for whether
|
||||
# the SDK has 'mfc' and 'atl' subdirectories. Since going to disk
|
||||
# is expensive, cache results by directory.
|
||||
|
||||
SDKEnvironmentUpdates = {}
|
||||
|
||||
def set_sdk_by_directory(env, sdk_dir):
|
||||
global SDKEnvironmentUpdates
|
||||
debug('set_sdk_by_directory: Using dir:%s'%sdk_dir)
|
||||
try:
|
||||
env_tuple_list = SDKEnvironmentUpdates[sdk_dir]
|
||||
except KeyError:
|
||||
env_tuple_list = []
|
||||
SDKEnvironmentUpdates[sdk_dir] = env_tuple_list
|
||||
|
||||
include_path = os.path.join(sdk_dir, 'include')
|
||||
mfc_path = os.path.join(include_path, 'mfc')
|
||||
atl_path = os.path.join(include_path, 'atl')
|
||||
|
||||
if os.path.exists(mfc_path):
|
||||
env_tuple_list.append(('INCLUDE', mfc_path))
|
||||
if os.path.exists(atl_path):
|
||||
env_tuple_list.append(('INCLUDE', atl_path))
|
||||
env_tuple_list.append(('INCLUDE', include_path))
|
||||
|
||||
env_tuple_list.append(('LIB', os.path.join(sdk_dir, 'lib')))
|
||||
env_tuple_list.append(('LIBPATH', os.path.join(sdk_dir, 'lib')))
|
||||
env_tuple_list.append(('PATH', os.path.join(sdk_dir, 'bin')))
|
||||
|
||||
for variable, directory in env_tuple_list:
|
||||
env.PrependENVPath(variable, directory)
|
||||
|
||||
def get_sdk_by_version(mssdk):
|
||||
if mssdk not in SupportedSDKMap:
|
||||
raise SCons.Errors.UserError("SDK version {} is not supported".format(repr(mssdk)))
|
||||
get_installed_sdks()
|
||||
return InstalledSDKMap.get(mssdk)
|
||||
|
||||
def get_default_sdk():
|
||||
"""Set up the default Platform/Windows SDK."""
|
||||
get_installed_sdks()
|
||||
if not InstalledSDKList:
|
||||
return None
|
||||
return InstalledSDKList[0]
|
||||
|
||||
def mssdk_setup_env(env):
|
||||
debug('mssdk_setup_env()')
|
||||
if 'MSSDK_DIR' in env:
|
||||
sdk_dir = env['MSSDK_DIR']
|
||||
if sdk_dir is None:
|
||||
return
|
||||
sdk_dir = env.subst(sdk_dir)
|
||||
debug('mssdk_setup_env: Using MSSDK_DIR:{}'.format(sdk_dir))
|
||||
elif 'MSSDK_VERSION' in env:
|
||||
sdk_version = env['MSSDK_VERSION']
|
||||
if sdk_version is None:
|
||||
msg = "SDK version is specified as None"
|
||||
raise SCons.Errors.UserError(msg)
|
||||
sdk_version = env.subst(sdk_version)
|
||||
mssdk = get_sdk_by_version(sdk_version)
|
||||
if mssdk is None:
|
||||
msg = "SDK version %s is not installed" % sdk_version
|
||||
raise SCons.Errors.UserError(msg)
|
||||
sdk_dir = mssdk.get_sdk_dir()
|
||||
debug('mssdk_setup_env: Using MSSDK_VERSION:%s'%sdk_dir)
|
||||
elif 'MSVS_VERSION' in env:
|
||||
msvs_version = env['MSVS_VERSION']
|
||||
debug('mssdk_setup_env:Getting MSVS_VERSION from env:%s'%msvs_version)
|
||||
if msvs_version is None:
|
||||
debug('mssdk_setup_env thinks msvs_version is None')
|
||||
return
|
||||
msvs_version = env.subst(msvs_version)
|
||||
from . import vs
|
||||
msvs = vs.get_vs_by_version(msvs_version)
|
||||
debug('mssdk_setup_env:msvs is :%s'%msvs)
|
||||
if not msvs:
|
||||
debug('mssdk_setup_env: no VS version detected, bailingout:%s'%msvs)
|
||||
return
|
||||
sdk_version = msvs.sdk_version
|
||||
debug('msvs.sdk_version is %s'%sdk_version)
|
||||
if not sdk_version:
|
||||
return
|
||||
mssdk = get_sdk_by_version(sdk_version)
|
||||
if not mssdk:
|
||||
mssdk = get_default_sdk()
|
||||
if not mssdk:
|
||||
return
|
||||
sdk_dir = mssdk.get_sdk_dir()
|
||||
debug('mssdk_setup_env: Using MSVS_VERSION:%s'%sdk_dir)
|
||||
else:
|
||||
mssdk = get_default_sdk()
|
||||
if not mssdk:
|
||||
return
|
||||
sdk_dir = mssdk.get_sdk_dir()
|
||||
debug('mssdk_setup_env: not using any env values. sdk_dir:%s'%sdk_dir)
|
||||
|
||||
set_sdk_by_directory(env, sdk_dir)
|
||||
|
||||
#print "No MSVS_VERSION: this is likely to be a bug"
|
||||
|
||||
def mssdk_exists(version=None):
|
||||
sdks = get_installed_sdks()
|
||||
if version is None:
|
||||
return len(sdks) > 0
|
||||
return version in sdks
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
954
scons/scons-local-4.0.1/SCons/Tool/MSCommon/vc.py
Normal file
954
scons/scons-local-4.0.1/SCons/Tool/MSCommon/vc.py
Normal file
|
@ -0,0 +1,954 @@
|
|||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# TODO:
|
||||
# * gather all the information from a single vswhere call instead
|
||||
# of calling repeatedly (use json format?)
|
||||
# * support passing/setting location for vswhere in env.
|
||||
# * supported arch for versions: for old versions of batch file without
|
||||
# argument, giving bogus argument cannot be detected, so we have to hardcode
|
||||
# this here
|
||||
# * print warning when msvc version specified but not found
|
||||
# * find out why warning do not print
|
||||
# * test on 64 bits XP + VS 2005 (and VS 6 if possible)
|
||||
# * SDK
|
||||
# * Assembly
|
||||
__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
__doc__ = """Module for Visual C/C++ detection and configuration.
|
||||
"""
|
||||
import SCons.compat
|
||||
import SCons.Util
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
from string import digits as string_digits
|
||||
from subprocess import PIPE
|
||||
|
||||
import SCons.Warnings
|
||||
from SCons.Tool import find_program_path
|
||||
|
||||
from . import common
|
||||
from .common import CONFIG_CACHE, debug
|
||||
from .sdk import get_installed_sdks
|
||||
|
||||
|
||||
class VisualCException(Exception):
|
||||
pass
|
||||
|
||||
class UnsupportedVersion(VisualCException):
|
||||
pass
|
||||
|
||||
class MSVCUnsupportedHostArch(VisualCException):
|
||||
pass
|
||||
|
||||
class MSVCUnsupportedTargetArch(VisualCException):
|
||||
pass
|
||||
|
||||
class MissingConfiguration(VisualCException):
|
||||
pass
|
||||
|
||||
class NoVersionFound(VisualCException):
|
||||
pass
|
||||
|
||||
class BatchFileExecutionError(VisualCException):
|
||||
pass
|
||||
|
||||
# Dict to 'canonalize' the arch
|
||||
_ARCH_TO_CANONICAL = {
|
||||
"amd64" : "amd64",
|
||||
"emt64" : "amd64",
|
||||
"i386" : "x86",
|
||||
"i486" : "x86",
|
||||
"i586" : "x86",
|
||||
"i686" : "x86",
|
||||
"ia64" : "ia64", # deprecated
|
||||
"itanium" : "ia64", # deprecated
|
||||
"x86" : "x86",
|
||||
"x86_64" : "amd64",
|
||||
"arm" : "arm",
|
||||
"arm64" : "arm64",
|
||||
"aarch64" : "arm64",
|
||||
}
|
||||
|
||||
# Starting with 14.1 (aka VS2017), the tools are organized by host directory.
|
||||
# subdirs for each target. They are now in .../VC/Auxuiliary/Build.
|
||||
# Note 2017 Express uses Hostx86 even if it's on 64-bit Windows,
|
||||
# not reflected in this table.
|
||||
_HOST_TARGET_TO_CL_DIR_GREATER_THAN_14 = {
|
||||
("amd64","amd64") : ("Hostx64","x64"),
|
||||
("amd64","x86") : ("Hostx64","x86"),
|
||||
("amd64","arm") : ("Hostx64","arm"),
|
||||
("amd64","arm64") : ("Hostx64","arm64"),
|
||||
("x86","amd64") : ("Hostx86","x64"),
|
||||
("x86","x86") : ("Hostx86","x86"),
|
||||
("x86","arm") : ("Hostx86","arm"),
|
||||
("x86","arm64") : ("Hostx86","arm64"),
|
||||
}
|
||||
|
||||
# before 14.1 (VS2017): the original x86 tools are in the tools dir,
|
||||
# any others are in a subdir named by the host/target pair,
|
||||
# or just a single word if host==target
|
||||
_HOST_TARGET_TO_CL_DIR = {
|
||||
("amd64","amd64") : "amd64",
|
||||
("amd64","x86") : "amd64_x86",
|
||||
("amd64","arm") : "amd64_arm",
|
||||
("amd64","arm64") : "amd64_arm64",
|
||||
("x86","amd64") : "x86_amd64",
|
||||
("x86","x86") : "",
|
||||
("x86","arm") : "x86_arm",
|
||||
("x86","arm64") : "x86_arm64",
|
||||
("arm","arm") : "arm",
|
||||
}
|
||||
|
||||
# 14.1 (VS2017) and later:
|
||||
# Given a (host, target) tuple, return the batch file to look for.
|
||||
# We can't rely on returning an arg to use for vcvarsall.bat,
|
||||
# because that script will run even if given a pair that isn't installed.
|
||||
# Targets that already look like a pair are pseudo targets that
|
||||
# effectively mean to skip whatever the host was specified as.
|
||||
_HOST_TARGET_TO_BAT_ARCH_GT14 = {
|
||||
("amd64", "amd64"): "vcvars64.bat",
|
||||
("amd64", "x86"): "vcvarsamd64_x86.bat",
|
||||
("amd64", "x86_amd64"): "vcvarsx86_amd64.bat",
|
||||
("amd64", "x86_x86"): "vcvars32.bat",
|
||||
("amd64", "arm"): "vcvarsamd64_arm.bat",
|
||||
("amd64", "x86_arm"): "vcvarsx86_arm.bat",
|
||||
("amd64", "arm64"): "vcvarsamd64_arm64.bat",
|
||||
("amd64", "x86_arm64"): "vcvarsx86_arm64.bat",
|
||||
("x86", "x86"): "vcvars32.bat",
|
||||
("x86", "amd64"): "vcvarsx86_amd64.bat",
|
||||
("x86", "x86_amd64"): "vcvarsx86_amd64.bat",
|
||||
("x86", "arm"): "vcvarsx86_arm.bat",
|
||||
("x86", "x86_arm"): "vcvarsx86_arm.bat",
|
||||
("x86", "arm64"): "vcvarsx86_arm64.bat",
|
||||
("x86", "x86_arm64"): "vcvarsx86_arm64.bat",
|
||||
}
|
||||
|
||||
# before 14.1 (VS2017):
|
||||
# Given a (host, target) tuple, return the argument for the bat file;
|
||||
# Both host and target should be canoncalized.
|
||||
# If the target already looks like a pair, return it - these are
|
||||
# pseudo targets (mainly used by Express versions)
|
||||
_HOST_TARGET_ARCH_TO_BAT_ARCH = {
|
||||
("x86", "x86"): "x86",
|
||||
("x86", "amd64"): "x86_amd64",
|
||||
("x86", "x86_amd64"): "x86_amd64",
|
||||
("amd64", "x86_amd64"): "x86_amd64", # This is present in (at least) VS2012 express
|
||||
("amd64", "amd64"): "amd64",
|
||||
("amd64", "x86"): "x86",
|
||||
("amd64", "x86_x86"): "x86",
|
||||
("x86", "ia64"): "x86_ia64", # gone since 14.0
|
||||
("x86", "arm"): "x86_arm", # since 14.0
|
||||
("x86", "arm64"): "x86_arm64", # since 14.1
|
||||
("amd64", "arm"): "amd64_arm", # since 14.0
|
||||
("amd64", "arm64"): "amd64_arm64", # since 14.1
|
||||
("x86", "x86_arm"): "x86_arm", # since 14.0
|
||||
("x86", "x86_arm64"): "x86_arm64", # since 14.1
|
||||
("amd64", "x86_arm"): "x86_arm", # since 14.0
|
||||
("amd64", "x86_arm64"): "x86_arm64", # since 14.1
|
||||
}
|
||||
|
||||
_CL_EXE_NAME = 'cl.exe'
|
||||
|
||||
def get_msvc_version_numeric(msvc_version):
|
||||
"""Get the raw version numbers from a MSVC_VERSION string, so it
|
||||
could be cast to float or other numeric values. For example, '14.0Exp'
|
||||
would get converted to '14.0'.
|
||||
|
||||
Args:
|
||||
msvc_version: str
|
||||
string representing the version number, could contain non
|
||||
digit characters
|
||||
|
||||
Returns:
|
||||
str: the value converted to a numeric only string
|
||||
|
||||
"""
|
||||
return ''.join([x for x in msvc_version if x in string_digits + '.'])
|
||||
|
||||
def get_host_target(env):
|
||||
host_platform = env.get('HOST_ARCH')
|
||||
debug("HOST_ARCH:" + str(host_platform))
|
||||
if not host_platform:
|
||||
host_platform = platform.machine()
|
||||
|
||||
# Solaris returns i86pc for both 32 and 64 bit architectures
|
||||
if host_platform == "i86pc":
|
||||
if platform.architecture()[0] == "64bit":
|
||||
host_platform = "amd64"
|
||||
else:
|
||||
host_platform = "x86"
|
||||
|
||||
# Retain user requested TARGET_ARCH
|
||||
req_target_platform = env.get('TARGET_ARCH')
|
||||
debug("HOST_ARCH:" + str(req_target_platform))
|
||||
if req_target_platform:
|
||||
# If user requested a specific platform then only try that one.
|
||||
target_platform = req_target_platform
|
||||
else:
|
||||
target_platform = host_platform
|
||||
|
||||
try:
|
||||
host = _ARCH_TO_CANONICAL[host_platform.lower()]
|
||||
except KeyError:
|
||||
msg = "Unrecognized host architecture %s"
|
||||
raise MSVCUnsupportedHostArch(msg % repr(host_platform))
|
||||
|
||||
try:
|
||||
target = _ARCH_TO_CANONICAL[target_platform.lower()]
|
||||
except KeyError:
|
||||
all_archs = str(list(_ARCH_TO_CANONICAL.keys()))
|
||||
raise MSVCUnsupportedTargetArch("Unrecognized target architecture %s\n\tValid architectures: %s" % (target_platform, all_archs))
|
||||
|
||||
return (host, target,req_target_platform)
|
||||
|
||||
# If you update this, update SupportedVSList in Tool/MSCommon/vs.py, and the
|
||||
# MSVC_VERSION documentation in Tool/msvc.xml.
|
||||
_VCVER = ["14.2", "14.1", "14.1Exp", "14.0", "14.0Exp", "12.0", "12.0Exp", "11.0", "11.0Exp", "10.0", "10.0Exp", "9.0", "9.0Exp","8.0", "8.0Exp","7.1", "7.0", "6.0"]
|
||||
|
||||
# if using vswhere, configure command line arguments to probe for installed VC editions
|
||||
_VCVER_TO_VSWHERE_VER = {
|
||||
'14.2': [
|
||||
["-version", "[16.0, 17.0)", ], # default: Enterprise, Professional, Community (order unpredictable?)
|
||||
["-version", "[16.0, 17.0)", "-products", "Microsoft.VisualStudio.Product.BuildTools"], # BuildTools
|
||||
],
|
||||
'14.1': [
|
||||
["-version", "[15.0, 16.0)", ], # default: Enterprise, Professional, Community (order unpredictable?)
|
||||
["-version", "[15.0, 16.0)", "-products", "Microsoft.VisualStudio.Product.BuildTools"], # BuildTools
|
||||
],
|
||||
'14.1Exp': [
|
||||
["-version", "[15.0, 16.0)", "-products", "Microsoft.VisualStudio.Product.WDExpress"], # Express
|
||||
],
|
||||
}
|
||||
|
||||
_VCVER_TO_PRODUCT_DIR = {
|
||||
'14.2': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'')], # not set by this version
|
||||
'14.1': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'')], # not set by this version
|
||||
'14.1Exp': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'')], # not set by this version
|
||||
'14.0' : [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\14.0\Setup\VC\ProductDir')],
|
||||
'14.0Exp' : [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\14.0\Setup\VC\ProductDir')],
|
||||
'12.0' : [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\12.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'12.0Exp' : [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\12.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'11.0': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\11.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'11.0Exp' : [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\11.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'10.0': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\10.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'10.0Exp' : [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\10.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'9.0': [
|
||||
(SCons.Util.HKEY_CURRENT_USER, r'Microsoft\DevDiv\VCForPython\9.0\installdir',),
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\9.0\Setup\VC\ProductDir',),
|
||||
],
|
||||
'9.0Exp' : [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\9.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'8.0': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\8.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'8.0Exp': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VCExpress\8.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'7.1': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\7.1\Setup\VC\ProductDir'),
|
||||
],
|
||||
'7.0': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\7.0\Setup\VC\ProductDir'),
|
||||
],
|
||||
'6.0': [
|
||||
(SCons.Util.HKEY_LOCAL_MACHINE, r'Microsoft\VisualStudio\6.0\Setup\Microsoft Visual C++\ProductDir'),
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def msvc_version_to_maj_min(msvc_version):
|
||||
msvc_version_numeric = get_msvc_version_numeric(msvc_version)
|
||||
|
||||
t = msvc_version_numeric.split(".")
|
||||
if not len(t) == 2:
|
||||
raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric))
|
||||
try:
|
||||
maj = int(t[0])
|
||||
min = int(t[1])
|
||||
return maj, min
|
||||
except ValueError as e:
|
||||
raise ValueError("Unrecognized version %s (%s)" % (msvc_version,msvc_version_numeric))
|
||||
|
||||
|
||||
def is_host_target_supported(host_target, msvc_version):
|
||||
"""Check if (host, target) pair is supported for a VC version.
|
||||
|
||||
Only checks whether a given version *may* support the given
|
||||
(host, target) pair, not that the toolchain is actually on the machine.
|
||||
|
||||
Args:
|
||||
host_target: canonalized host-target pair, e.g.
|
||||
("x86", "amd64") for cross compilation from 32- to 64-bit Windows.
|
||||
msvc_version: Visual C++ version (major.minor), e.g. "10.0"
|
||||
|
||||
Returns:
|
||||
True or False
|
||||
|
||||
"""
|
||||
# We assume that any Visual Studio version supports x86 as a target
|
||||
if host_target[1] != "x86":
|
||||
maj, min = msvc_version_to_maj_min(msvc_version)
|
||||
if maj < 8:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
VSWHERE_PATHS = [os.path.join(p,'vswhere.exe') for p in [
|
||||
os.path.expandvars(r"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer"),
|
||||
os.path.expandvars(r"%ProgramFiles%\Microsoft Visual Studio\Installer"),
|
||||
os.path.expandvars(r"%ChocolateyInstall%\bin"),
|
||||
]]
|
||||
|
||||
def msvc_find_vswhere():
|
||||
""" Find the location of vswhere """
|
||||
# For bug 3333: support default location of vswhere for both
|
||||
# 64 and 32 bit windows installs.
|
||||
# For bug 3542: also accommodate not being on C: drive.
|
||||
# NB: this gets called from testsuite on non-Windows platforms.
|
||||
# Whether that makes sense or not, don't break it for those.
|
||||
vswhere_path = None
|
||||
for pf in VSWHERE_PATHS:
|
||||
if os.path.exists(pf):
|
||||
vswhere_path = pf
|
||||
break
|
||||
|
||||
return vswhere_path
|
||||
|
||||
def find_vc_pdir_vswhere(msvc_version, env=None):
|
||||
""" Find the MSVC product directory using the vswhere program.
|
||||
|
||||
Args:
|
||||
msvc_version: MSVC version to search for
|
||||
env: optional to look up VSWHERE variable
|
||||
|
||||
Returns:
|
||||
MSVC install dir or None
|
||||
|
||||
Raises:
|
||||
UnsupportedVersion: if the version is not known by this file
|
||||
|
||||
"""
|
||||
try:
|
||||
vswhere_version = _VCVER_TO_VSWHERE_VER[msvc_version]
|
||||
except KeyError:
|
||||
debug("Unknown version of MSVC: %s" % msvc_version)
|
||||
raise UnsupportedVersion("Unknown version %s" % msvc_version)
|
||||
|
||||
if env is None or not env.get('VSWHERE'):
|
||||
vswhere_path = msvc_find_vswhere()
|
||||
else:
|
||||
vswhere_path = env.subst('$VSWHERE')
|
||||
|
||||
if vswhere_path is None:
|
||||
return None
|
||||
|
||||
debug('VSWHERE: %s' % vswhere_path)
|
||||
for vswhere_version_args in vswhere_version:
|
||||
|
||||
vswhere_cmd = [vswhere_path] + vswhere_version_args + ["-property", "installationPath"]
|
||||
|
||||
debug("running: %s" % vswhere_cmd)
|
||||
|
||||
#cp = subprocess.run(vswhere_cmd, capture_output=True) # 3.7+ only
|
||||
cp = subprocess.run(vswhere_cmd, stdout=PIPE, stderr=PIPE)
|
||||
|
||||
if cp.stdout:
|
||||
# vswhere could return multiple lines, e.g. if Build Tools
|
||||
# and {Community,Professional,Enterprise} are both installed.
|
||||
# We could define a way to pick the one we prefer, but since
|
||||
# this data is currently only used to make a check for existence,
|
||||
# returning the first hit should be good enough.
|
||||
lines = cp.stdout.decode("mbcs").splitlines()
|
||||
return os.path.join(lines[0], 'VC')
|
||||
else:
|
||||
# We found vswhere, but no install info available for this version
|
||||
pass
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def find_vc_pdir(env, msvc_version):
|
||||
"""Find the MSVC product directory for the given version.
|
||||
|
||||
Tries to look up the path using a registry key from the table
|
||||
_VCVER_TO_PRODUCT_DIR; if there is no key, calls find_vc_pdir_wshere
|
||||
for help instead.
|
||||
|
||||
Args:
|
||||
msvc_version: str
|
||||
msvc version (major.minor, e.g. 10.0)
|
||||
|
||||
Returns:
|
||||
str: Path found in registry, or None
|
||||
|
||||
Raises:
|
||||
UnsupportedVersion: if the version is not known by this file.
|
||||
MissingConfiguration: found version but the directory is missing.
|
||||
|
||||
Both exceptions inherit from VisualCException.
|
||||
|
||||
"""
|
||||
root = 'Software\\'
|
||||
try:
|
||||
hkeys = _VCVER_TO_PRODUCT_DIR[msvc_version]
|
||||
except KeyError:
|
||||
debug("Unknown version of MSVC: %s" % msvc_version)
|
||||
raise UnsupportedVersion("Unknown version %s" % msvc_version)
|
||||
|
||||
for hkroot, key in hkeys:
|
||||
try:
|
||||
comps = None
|
||||
if not key:
|
||||
comps = find_vc_pdir_vswhere(msvc_version, env)
|
||||
if not comps:
|
||||
debug('no VC found for version {}'.format(repr(msvc_version)))
|
||||
raise SCons.Util.WinError
|
||||
debug('VC found: {}'.format(repr(msvc_version)))
|
||||
return comps
|
||||
else:
|
||||
if common.is_win64():
|
||||
try:
|
||||
# ordinarily at win64, try Wow6432Node first.
|
||||
comps = common.read_reg(root + 'Wow6432Node\\' + key, hkroot)
|
||||
except SCons.Util.WinError as e:
|
||||
# at Microsoft Visual Studio for Python 2.7, value is not in Wow6432Node
|
||||
pass
|
||||
if not comps:
|
||||
# not Win64, or Microsoft Visual Studio for Python 2.7
|
||||
comps = common.read_reg(root + key, hkroot)
|
||||
except SCons.Util.WinError as e:
|
||||
debug('no VC registry key {}'.format(repr(key)))
|
||||
else:
|
||||
debug('found VC in registry: {}'.format(comps))
|
||||
if os.path.exists(comps):
|
||||
return comps
|
||||
else:
|
||||
debug('reg says dir is {}, but it does not exist. (ignoring)'.format(comps))
|
||||
raise MissingConfiguration("registry dir {} not found on the filesystem".format(comps))
|
||||
return None
|
||||
|
||||
def find_batch_file(env,msvc_version,host_arch,target_arch):
|
||||
"""
|
||||
Find the location of the batch script which should set up the compiler
|
||||
for any TARGET_ARCH whose compilers were installed by Visual Studio/VCExpress
|
||||
|
||||
In newer (2017+) compilers, make use of the fact there are vcvars
|
||||
scripts named with a host_target pair that calls vcvarsall.bat properly,
|
||||
so use that and return an indication we don't need the argument
|
||||
we would have computed to run vcvarsall.bat.
|
||||
"""
|
||||
pdir = find_vc_pdir(env, msvc_version)
|
||||
if pdir is None:
|
||||
raise NoVersionFound("No version of Visual Studio found")
|
||||
debug('looking in {}'.format(pdir))
|
||||
|
||||
# filter out e.g. "Exp" from the version name
|
||||
msvc_ver_numeric = get_msvc_version_numeric(msvc_version)
|
||||
use_arg = True
|
||||
vernum = float(msvc_ver_numeric)
|
||||
if 7 <= vernum < 8:
|
||||
pdir = os.path.join(pdir, os.pardir, "Common7", "Tools")
|
||||
batfilename = os.path.join(pdir, "vsvars32.bat")
|
||||
elif vernum < 7:
|
||||
pdir = os.path.join(pdir, "Bin")
|
||||
batfilename = os.path.join(pdir, "vcvars32.bat")
|
||||
elif 8 <= vernum <= 14:
|
||||
batfilename = os.path.join(pdir, "vcvarsall.bat")
|
||||
else: # vernum >= 14.1 VS2017 and above
|
||||
batfiledir = os.path.join(pdir, "Auxiliary", "Build")
|
||||
targ = _HOST_TARGET_TO_BAT_ARCH_GT14[(host_arch, target_arch)]
|
||||
batfilename = os.path.join(batfiledir, targ)
|
||||
use_arg = False
|
||||
|
||||
if not os.path.exists(batfilename):
|
||||
debug("Not found: %s" % batfilename)
|
||||
batfilename = None
|
||||
|
||||
installed_sdks = get_installed_sdks()
|
||||
for _sdk in installed_sdks:
|
||||
sdk_bat_file = _sdk.get_sdk_vc_script(host_arch,target_arch)
|
||||
if not sdk_bat_file:
|
||||
debug("batch file not found:%s" % _sdk)
|
||||
else:
|
||||
sdk_bat_file_path = os.path.join(pdir,sdk_bat_file)
|
||||
if os.path.exists(sdk_bat_file_path):
|
||||
debug('sdk_bat_file_path:%s' % sdk_bat_file_path)
|
||||
return (batfilename, use_arg, sdk_bat_file_path)
|
||||
return (batfilename, use_arg, None)
|
||||
|
||||
|
||||
__INSTALLED_VCS_RUN = None
|
||||
_VC_TOOLS_VERSION_FILE_PATH = ['Auxiliary', 'Build', 'Microsoft.VCToolsVersion.default.txt']
|
||||
_VC_TOOLS_VERSION_FILE = os.sep.join(_VC_TOOLS_VERSION_FILE_PATH)
|
||||
|
||||
def _check_cl_exists_in_vc_dir(env, vc_dir, msvc_version):
|
||||
"""Return status of finding a cl.exe to use.
|
||||
|
||||
Locates cl in the vc_dir depending on TARGET_ARCH, HOST_ARCH and the
|
||||
msvc version. TARGET_ARCH and HOST_ARCH can be extracted from the
|
||||
passed env, unless it is None, in which case the native platform is
|
||||
assumed for both host and target.
|
||||
|
||||
Args:
|
||||
env: Environment
|
||||
a construction environment, usually if this is passed its
|
||||
because there is a desired TARGET_ARCH to be used when searching
|
||||
for a cl.exe
|
||||
vc_dir: str
|
||||
the path to the VC dir in the MSVC installation
|
||||
msvc_version: str
|
||||
msvc version (major.minor, e.g. 10.0)
|
||||
|
||||
Returns:
|
||||
bool:
|
||||
|
||||
"""
|
||||
|
||||
# determine if there is a specific target platform we want to build for and
|
||||
# use that to find a list of valid VCs, default is host platform == target platform
|
||||
# and same for if no env is specified to extract target platform from
|
||||
if env:
|
||||
(host_platform, target_platform, req_target_platform) = get_host_target(env)
|
||||
else:
|
||||
host_platform = platform.machine().lower()
|
||||
target_platform = host_platform
|
||||
|
||||
host_platform = _ARCH_TO_CANONICAL[host_platform]
|
||||
target_platform = _ARCH_TO_CANONICAL[target_platform]
|
||||
|
||||
debug('host platform %s, target platform %s for version %s' % (host_platform, target_platform, msvc_version))
|
||||
|
||||
ver_num = float(get_msvc_version_numeric(msvc_version))
|
||||
|
||||
# make sure the cl.exe exists meaning the tool is installed
|
||||
if ver_num > 14:
|
||||
# 2017 and newer allowed multiple versions of the VC toolset to be
|
||||
# installed at the same time. This changes the layout.
|
||||
# Just get the default tool version for now
|
||||
#TODO: support setting a specific minor VC version
|
||||
default_toolset_file = os.path.join(vc_dir, _VC_TOOLS_VERSION_FILE)
|
||||
try:
|
||||
with open(default_toolset_file) as f:
|
||||
vc_specific_version = f.readlines()[0].strip()
|
||||
except IOError:
|
||||
debug('failed to read ' + default_toolset_file)
|
||||
return False
|
||||
except IndexError:
|
||||
debug('failed to find MSVC version in ' + default_toolset_file)
|
||||
return False
|
||||
|
||||
host_trgt_dir = _HOST_TARGET_TO_CL_DIR_GREATER_THAN_14.get((host_platform, target_platform), None)
|
||||
if host_trgt_dir is None:
|
||||
debug('unsupported host/target platform combo: (%s,%s)'%(host_platform, target_platform))
|
||||
return False
|
||||
|
||||
cl_path = os.path.join(vc_dir, 'Tools','MSVC', vc_specific_version, 'bin', host_trgt_dir[0], host_trgt_dir[1], _CL_EXE_NAME)
|
||||
debug('checking for ' + _CL_EXE_NAME + ' at ' + cl_path)
|
||||
if os.path.exists(cl_path):
|
||||
debug('found ' + _CL_EXE_NAME + '!')
|
||||
return True
|
||||
|
||||
elif host_platform == "amd64" and host_trgt_dir[0] == "Hostx64":
|
||||
# Special case: fallback to Hostx86 if Hostx64 was tried
|
||||
# and failed. This is because VS 2017 Express running on amd64
|
||||
# will look to our probe like the host dir should be Hostx64,
|
||||
# but Express uses Hostx86 anyway.
|
||||
# We should key this off the "x86_amd64" and related pseudo
|
||||
# targets, but we don't see those in this function.
|
||||
host_trgt_dir = ("Hostx86", host_trgt_dir[1])
|
||||
cl_path = os.path.join(vc_dir, 'Tools','MSVC', vc_specific_version, 'bin', host_trgt_dir[0], host_trgt_dir[1], _CL_EXE_NAME)
|
||||
debug('checking for ' + _CL_EXE_NAME + ' at ' + cl_path)
|
||||
if os.path.exists(cl_path):
|
||||
debug('found ' + _CL_EXE_NAME + '!')
|
||||
return True
|
||||
|
||||
elif 14 >= ver_num >= 8:
|
||||
# Set default value to be -1 as "", which is the value for x86/x86,
|
||||
# yields true when tested if not host_trgt_dir
|
||||
host_trgt_dir = _HOST_TARGET_TO_CL_DIR.get((host_platform, target_platform), None)
|
||||
if host_trgt_dir is None:
|
||||
debug('unsupported host/target platform combo')
|
||||
return False
|
||||
|
||||
cl_path = os.path.join(vc_dir, 'bin', host_trgt_dir, _CL_EXE_NAME)
|
||||
debug('checking for ' + _CL_EXE_NAME + ' at ' + cl_path)
|
||||
|
||||
cl_path_exists = os.path.exists(cl_path)
|
||||
if not cl_path_exists and host_platform == 'amd64':
|
||||
# older versions of visual studio only had x86 binaries,
|
||||
# so if the host platform is amd64, we need to check cross
|
||||
# compile options (x86 binary compiles some other target on a 64 bit os)
|
||||
|
||||
# Set default value to be -1 as "" which is the value for x86/x86 yields true when tested
|
||||
# if not host_trgt_dir
|
||||
host_trgt_dir = _HOST_TARGET_TO_CL_DIR.get(('x86', target_platform), None)
|
||||
if host_trgt_dir is None:
|
||||
return False
|
||||
|
||||
cl_path = os.path.join(vc_dir, 'bin', host_trgt_dir, _CL_EXE_NAME)
|
||||
debug('checking for ' + _CL_EXE_NAME + ' at ' + cl_path)
|
||||
cl_path_exists = os.path.exists(cl_path)
|
||||
|
||||
if cl_path_exists:
|
||||
debug('found ' + _CL_EXE_NAME + '!')
|
||||
return True
|
||||
|
||||
elif 8 > ver_num >= 6:
|
||||
# quick check for vc_dir/bin and vc_dir/ before walk
|
||||
# need to check root as the walk only considers subdirectories
|
||||
for cl_dir in ('bin', ''):
|
||||
cl_path = os.path.join(vc_dir, cl_dir, _CL_EXE_NAME)
|
||||
if os.path.exists(cl_path):
|
||||
debug(_CL_EXE_NAME + ' found %s' % cl_path)
|
||||
return True
|
||||
# not in bin or root: must be in a subdirectory
|
||||
for cl_root, cl_dirs, _ in os.walk(vc_dir):
|
||||
for cl_dir in cl_dirs:
|
||||
cl_path = os.path.join(cl_root, cl_dir, _CL_EXE_NAME)
|
||||
if os.path.exists(cl_path):
|
||||
debug(_CL_EXE_NAME + ' found %s' % cl_path)
|
||||
return True
|
||||
return False
|
||||
else:
|
||||
# version not support return false
|
||||
debug('unsupported MSVC version: ' + str(ver_num))
|
||||
|
||||
return False
|
||||
|
||||
def cached_get_installed_vcs(env=None):
|
||||
global __INSTALLED_VCS_RUN
|
||||
|
||||
if __INSTALLED_VCS_RUN is None:
|
||||
ret = get_installed_vcs(env)
|
||||
__INSTALLED_VCS_RUN = ret
|
||||
|
||||
return __INSTALLED_VCS_RUN
|
||||
|
||||
def get_installed_vcs(env=None):
|
||||
installed_versions = []
|
||||
|
||||
for ver in _VCVER:
|
||||
debug('trying to find VC %s' % ver)
|
||||
try:
|
||||
VC_DIR = find_vc_pdir(env, ver)
|
||||
if VC_DIR:
|
||||
debug('found VC %s' % ver)
|
||||
if _check_cl_exists_in_vc_dir(env, VC_DIR, ver):
|
||||
installed_versions.append(ver)
|
||||
else:
|
||||
debug('no compiler found %s' % ver)
|
||||
else:
|
||||
debug('return None for ver %s' % ver)
|
||||
except (MSVCUnsupportedTargetArch, MSVCUnsupportedHostArch):
|
||||
# Allow this exception to propagate further as it should cause
|
||||
# SCons to exit with an error code
|
||||
raise
|
||||
except VisualCException as e:
|
||||
debug('did not find VC %s: caught exception %s' % (ver, str(e)))
|
||||
return installed_versions
|
||||
|
||||
def reset_installed_vcs():
|
||||
"""Make it try again to find VC. This is just for the tests."""
|
||||
global __INSTALLED_VCS_RUN
|
||||
__INSTALLED_VCS_RUN = None
|
||||
|
||||
# Running these batch files isn't cheap: most of the time spent in
|
||||
# msvs.generate() is due to vcvars*.bat. In a build that uses "tools='msvs'"
|
||||
# in multiple environments, for example:
|
||||
# env1 = Environment(tools='msvs')
|
||||
# env2 = Environment(tools='msvs')
|
||||
# we can greatly improve the speed of the second and subsequent Environment
|
||||
# (or Clone) calls by memoizing the environment variables set by vcvars*.bat.
|
||||
#
|
||||
# Updated: by 2018, vcvarsall.bat had gotten so expensive (vs2017 era)
|
||||
# it was breaking CI builds because the test suite starts scons so many
|
||||
# times and the existing memo logic only helped with repeated calls
|
||||
# within the same scons run. Windows builds on the CI system were split
|
||||
# into chunks to get around single-build time limits.
|
||||
# With VS2019 it got even slower and an optional persistent cache file
|
||||
# was introduced. The cache now also stores only the parsed vars,
|
||||
# not the entire output of running the batch file - saves a bit
|
||||
# of time not parsing every time.
|
||||
|
||||
script_env_cache = None
|
||||
|
||||
def script_env(script, args=None):
|
||||
global script_env_cache
|
||||
|
||||
if script_env_cache is None:
|
||||
script_env_cache = common.read_script_env_cache()
|
||||
cache_key = "{}--{}".format(script, args)
|
||||
cache_data = script_env_cache.get(cache_key, None)
|
||||
if cache_data is None:
|
||||
stdout = common.get_output(script, args)
|
||||
|
||||
# Stupid batch files do not set return code: we take a look at the
|
||||
# beginning of the output for an error message instead
|
||||
olines = stdout.splitlines()
|
||||
if olines[0].startswith("The specified configuration type is missing"):
|
||||
raise BatchFileExecutionError("\n".join(olines[:2]))
|
||||
|
||||
cache_data = common.parse_output(stdout)
|
||||
script_env_cache[cache_key] = cache_data
|
||||
# once we updated cache, give a chance to write out if user wanted
|
||||
common.write_script_env_cache(script_env_cache)
|
||||
|
||||
return cache_data
|
||||
|
||||
def get_default_version(env):
|
||||
msvc_version = env.get('MSVC_VERSION')
|
||||
msvs_version = env.get('MSVS_VERSION')
|
||||
debug('msvc_version:%s msvs_version:%s' % (msvc_version, msvs_version))
|
||||
|
||||
if msvs_version and not msvc_version:
|
||||
SCons.Warnings.warn(
|
||||
SCons.Warnings.DeprecatedWarning,
|
||||
"MSVS_VERSION is deprecated: please use MSVC_VERSION instead ")
|
||||
return msvs_version
|
||||
elif msvc_version and msvs_version:
|
||||
if not msvc_version == msvs_version:
|
||||
SCons.Warnings.warn(
|
||||
SCons.Warnings.VisualVersionMismatch,
|
||||
"Requested msvc version (%s) and msvs version (%s) do " \
|
||||
"not match: please use MSVC_VERSION only to request a " \
|
||||
"visual studio version, MSVS_VERSION is deprecated" \
|
||||
% (msvc_version, msvs_version))
|
||||
return msvs_version
|
||||
|
||||
if not msvc_version:
|
||||
installed_vcs = cached_get_installed_vcs(env)
|
||||
debug('installed_vcs:%s' % installed_vcs)
|
||||
if not installed_vcs:
|
||||
#msg = 'No installed VCs'
|
||||
#debug('msv %s' % repr(msg))
|
||||
#SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, msg)
|
||||
debug('No installed VCs')
|
||||
return None
|
||||
msvc_version = installed_vcs[0]
|
||||
debug('using default installed MSVC version %s' % repr(msvc_version))
|
||||
else:
|
||||
debug('using specified MSVC version %s' % repr(msvc_version))
|
||||
|
||||
return msvc_version
|
||||
|
||||
def msvc_setup_env_once(env):
|
||||
try:
|
||||
has_run = env["MSVC_SETUP_RUN"]
|
||||
except KeyError:
|
||||
has_run = False
|
||||
|
||||
if not has_run:
|
||||
msvc_setup_env(env)
|
||||
env["MSVC_SETUP_RUN"] = True
|
||||
|
||||
def msvc_find_valid_batch_script(env, version):
|
||||
"""Find and execute appropriate batch script to set up build env.
|
||||
|
||||
The MSVC build environment depends heavily on having the shell
|
||||
environment set. SCons does not inherit that, and does not count
|
||||
on that being set up correctly anyway, so it tries to find the right
|
||||
MSVC batch script, or the right arguments to the generic batch script
|
||||
vcvarsall.bat, and run that, so we have a valid environment to build in.
|
||||
There are dragons here: the batch scripts don't fail (see comments
|
||||
elsewhere), they just leave you with a bad setup, so try hard to
|
||||
get it right.
|
||||
"""
|
||||
|
||||
# Find the host, target, and if present the requested target:
|
||||
platforms = get_host_target(env)
|
||||
debug("host_platform %s, target_platform %s req_target_platform %s" % platforms)
|
||||
host_platform, target_platform, req_target_platform = platforms
|
||||
|
||||
# Most combinations of host + target are straightforward.
|
||||
# While all MSVC / Visual Studio tools are pysically 32-bit, they
|
||||
# make it look like there are 64-bit tools if the host is 64-bit,
|
||||
# so you can invoke the environment batch script to set up to build,
|
||||
# say, amd64 host -> x86 target. Express versions are an exception:
|
||||
# they always look 32-bit, so the batch scripts with 64-bit
|
||||
# host parts are absent. We try to fix that up in a couple of ways.
|
||||
# One is here: we make a table of "targets" to try, with the extra
|
||||
# targets being tags that tell us to try a different "host" instead
|
||||
# of the deduced host.
|
||||
try_target_archs = [target_platform]
|
||||
if req_target_platform in ('amd64', 'x86_64'):
|
||||
try_target_archs.append('x86_amd64')
|
||||
elif req_target_platform in ('x86',):
|
||||
try_target_archs.append('x86_x86')
|
||||
elif req_target_platform in ('arm',):
|
||||
try_target_archs.append('x86_arm')
|
||||
elif req_target_platform in ('arm64',):
|
||||
try_target_archs.append('x86_arm64')
|
||||
elif not req_target_platform:
|
||||
if target_platform in ('amd64', 'x86_64'):
|
||||
try_target_archs.append('x86_amd64')
|
||||
# If the user hasn't specifically requested a TARGET_ARCH,
|
||||
# and the TARGET_ARCH is amd64 then also try 32 bits
|
||||
# if there are no viable 64 bit tools installed
|
||||
try_target_archs.append('x86')
|
||||
|
||||
debug("host_platform: %s, try_target_archs: %s"%(host_platform, try_target_archs))
|
||||
|
||||
d = None
|
||||
for tp in try_target_archs:
|
||||
# Set to current arch.
|
||||
env['TARGET_ARCH'] = tp
|
||||
|
||||
debug("trying target_platform:%s" % tp)
|
||||
host_target = (host_platform, tp)
|
||||
if not is_host_target_supported(host_target, version):
|
||||
warn_msg = "host, target = %s not supported for MSVC version %s" % \
|
||||
(host_target, version)
|
||||
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
|
||||
arg = _HOST_TARGET_ARCH_TO_BAT_ARCH[host_target]
|
||||
|
||||
# Try to locate a batch file for this host/target platform combo
|
||||
try:
|
||||
(vc_script, use_arg, sdk_script) = find_batch_file(env, version, host_platform, tp)
|
||||
debug('vc_script:%s sdk_script:%s'%(vc_script,sdk_script))
|
||||
except VisualCException as e:
|
||||
msg = str(e)
|
||||
debug('Caught exception while looking for batch file (%s)' % msg)
|
||||
warn_msg = "VC version %s not installed. " + \
|
||||
"C/C++ compilers are most likely not set correctly.\n" + \
|
||||
" Installed versions are: %s"
|
||||
warn_msg = warn_msg % (version, cached_get_installed_vcs(env))
|
||||
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
|
||||
continue
|
||||
|
||||
# Try to use the located batch file for this host/target platform combo
|
||||
debug('use_script 2 %s, args:%s' % (repr(vc_script), arg))
|
||||
found = None
|
||||
if vc_script:
|
||||
if not use_arg:
|
||||
arg = '' # bat file will supply platform type
|
||||
# Get just version numbers
|
||||
maj, min = msvc_version_to_maj_min(version)
|
||||
# VS2015+
|
||||
if maj >= 14:
|
||||
if env.get('MSVC_UWP_APP') == '1':
|
||||
# Initialize environment variables with store/UWP paths
|
||||
arg = (arg + ' store').lstrip()
|
||||
|
||||
try:
|
||||
d = script_env(vc_script, args=arg)
|
||||
found = vc_script
|
||||
except BatchFileExecutionError as e:
|
||||
debug('use_script 3: failed running VC script %s: %s: Error:%s'%(repr(vc_script),arg,e))
|
||||
vc_script=None
|
||||
continue
|
||||
if not vc_script and sdk_script:
|
||||
debug('use_script 4: trying sdk script: %s' % sdk_script)
|
||||
try:
|
||||
d = script_env(sdk_script)
|
||||
found = sdk_script
|
||||
except BatchFileExecutionError as e:
|
||||
debug('use_script 5: failed running SDK script %s: Error:%s'%(repr(sdk_script), e))
|
||||
continue
|
||||
elif not vc_script and not sdk_script:
|
||||
debug('use_script 6: Neither VC script nor SDK script found')
|
||||
continue
|
||||
|
||||
debug("Found a working script/target: %s/%s"%(repr(found),arg))
|
||||
break # We've found a working target_platform, so stop looking
|
||||
|
||||
# If we cannot find a viable installed compiler, reset the TARGET_ARCH
|
||||
# To it's initial value
|
||||
if not d:
|
||||
env['TARGET_ARCH']=req_target_platform
|
||||
|
||||
return d
|
||||
|
||||
|
||||
def msvc_setup_env(env):
|
||||
debug('called')
|
||||
version = get_default_version(env)
|
||||
if version is None:
|
||||
warn_msg = "No version of Visual Studio compiler found - C/C++ " \
|
||||
"compilers most likely not set correctly"
|
||||
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
|
||||
return None
|
||||
|
||||
# XXX: we set-up both MSVS version for backward
|
||||
# compatibility with the msvs tool
|
||||
env['MSVC_VERSION'] = version
|
||||
env['MSVS_VERSION'] = version
|
||||
env['MSVS'] = {}
|
||||
|
||||
|
||||
use_script = env.get('MSVC_USE_SCRIPT', True)
|
||||
if SCons.Util.is_String(use_script):
|
||||
debug('use_script 1 %s' % repr(use_script))
|
||||
d = script_env(use_script)
|
||||
elif use_script:
|
||||
d = msvc_find_valid_batch_script(env,version)
|
||||
debug('use_script 2 %s' % d)
|
||||
if not d:
|
||||
return d
|
||||
else:
|
||||
debug('MSVC_USE_SCRIPT set to False')
|
||||
warn_msg = "MSVC_USE_SCRIPT set to False, assuming environment " \
|
||||
"set correctly."
|
||||
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
|
||||
return None
|
||||
|
||||
for k, v in d.items():
|
||||
env.PrependENVPath(k, v, delete_existing=True)
|
||||
debug("env['ENV']['%s'] = %s" % (k, env['ENV'][k]))
|
||||
|
||||
# final check to issue a warning if the compiler is not present
|
||||
if not find_program_path(env, 'cl'):
|
||||
debug("did not find " + _CL_EXE_NAME)
|
||||
if CONFIG_CACHE:
|
||||
propose = "SCONS_CACHE_MSVC_CONFIG caching enabled, remove cache file {} if out of date.".format(CONFIG_CACHE)
|
||||
else:
|
||||
propose = "It may need to be installed separately with Visual Studio."
|
||||
warn_msg = "Could not find MSVC compiler 'cl'. {}".format(propose)
|
||||
SCons.Warnings.warn(SCons.Warnings.VisualCMissingWarning, warn_msg)
|
||||
|
||||
def msvc_exists(env=None, version=None):
|
||||
vcs = cached_get_installed_vcs(env)
|
||||
if version is None:
|
||||
return len(vcs) > 0
|
||||
return version in vcs
|
597
scons/scons-local-4.0.1/SCons/Tool/MSCommon/vs.py
Normal file
597
scons/scons-local-4.0.1/SCons/Tool/MSCommon/vs.py
Normal file
|
@ -0,0 +1,597 @@
|
|||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
__doc__ = """Module to detect Visual Studio and/or Visual C/C++
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
import SCons.Errors
|
||||
import SCons.Util
|
||||
|
||||
from .common import debug, \
|
||||
get_output, \
|
||||
is_win64, \
|
||||
normalize_env, \
|
||||
parse_output, \
|
||||
read_reg
|
||||
|
||||
import SCons.Tool.MSCommon.vc
|
||||
|
||||
class VisualStudio:
|
||||
"""
|
||||
An abstract base class for trying to find installed versions of
|
||||
Visual Studio.
|
||||
"""
|
||||
def __init__(self, version, **kw):
|
||||
self.version = version
|
||||
kw['vc_version'] = kw.get('vc_version', version)
|
||||
kw['sdk_version'] = kw.get('sdk_version', version)
|
||||
self.__dict__.update(kw)
|
||||
self._cache = {}
|
||||
|
||||
def find_batch_file(self):
|
||||
vs_dir = self.get_vs_dir()
|
||||
if not vs_dir:
|
||||
debug('no vs_dir')
|
||||
return None
|
||||
batch_file = os.path.join(vs_dir, self.batch_file_path)
|
||||
batch_file = os.path.normpath(batch_file)
|
||||
if not os.path.isfile(batch_file):
|
||||
debug('%s not on file system' % batch_file)
|
||||
return None
|
||||
return batch_file
|
||||
|
||||
def find_vs_dir_by_vc(self, env):
|
||||
SCons.Tool.MSCommon.vc.get_installed_vcs(env)
|
||||
dir = SCons.Tool.MSCommon.vc.find_vc_pdir(env, self.vc_version)
|
||||
if not dir:
|
||||
debug('no installed VC %s' % self.vc_version)
|
||||
return None
|
||||
return os.path.abspath(os.path.join(dir, os.pardir))
|
||||
|
||||
def find_vs_dir_by_reg(self, env):
|
||||
root = 'Software\\'
|
||||
|
||||
if is_win64():
|
||||
root = root + 'Wow6432Node\\'
|
||||
for key in self.hkeys:
|
||||
if key=='use_dir':
|
||||
return self.find_vs_dir_by_vc(env)
|
||||
key = root + key
|
||||
try:
|
||||
comps = read_reg(key)
|
||||
except SCons.Util.WinError as e:
|
||||
debug('no VS registry key {}'.format(repr(key)))
|
||||
else:
|
||||
debug('found VS in registry: {}'.format(comps))
|
||||
return comps
|
||||
return None
|
||||
|
||||
def find_vs_dir(self, env):
|
||||
""" Can use registry or location of VC to find vs dir
|
||||
First try to find by registry, and if that fails find via VC dir
|
||||
"""
|
||||
|
||||
vs_dir=self.find_vs_dir_by_reg(env)
|
||||
if not vs_dir:
|
||||
vs_dir = self.find_vs_dir_by_vc(env)
|
||||
debug('found VS in ' + str(vs_dir ))
|
||||
return vs_dir
|
||||
|
||||
def find_executable(self, env):
|
||||
vs_dir = self.get_vs_dir(env)
|
||||
if not vs_dir:
|
||||
debug('no vs_dir ({})'.format(vs_dir))
|
||||
return None
|
||||
executable = os.path.join(vs_dir, self.executable_path)
|
||||
executable = os.path.normpath(executable)
|
||||
if not os.path.isfile(executable):
|
||||
debug('{} not on file system'.format(executable))
|
||||
return None
|
||||
return executable
|
||||
|
||||
def get_batch_file(self):
|
||||
try:
|
||||
return self._cache['batch_file']
|
||||
except KeyError:
|
||||
batch_file = self.find_batch_file()
|
||||
self._cache['batch_file'] = batch_file
|
||||
return batch_file
|
||||
|
||||
def get_executable(self, env=None):
|
||||
try:
|
||||
debug('using cache:%s'%self._cache['executable'])
|
||||
return self._cache['executable']
|
||||
except KeyError:
|
||||
executable = self.find_executable(env)
|
||||
self._cache['executable'] = executable
|
||||
debug('not in cache:%s'%executable)
|
||||
return executable
|
||||
|
||||
def get_vs_dir(self, env):
|
||||
try:
|
||||
return self._cache['vs_dir']
|
||||
except KeyError:
|
||||
vs_dir = self.find_vs_dir(env)
|
||||
self._cache['vs_dir'] = vs_dir
|
||||
return vs_dir
|
||||
|
||||
def get_supported_arch(self):
|
||||
try:
|
||||
return self._cache['supported_arch']
|
||||
except KeyError:
|
||||
# RDEVE: for the time being use hardcoded lists
|
||||
# supported_arch = self.find_supported_arch()
|
||||
self._cache['supported_arch'] = self.supported_arch
|
||||
return self.supported_arch
|
||||
|
||||
def reset(self):
|
||||
self._cache = {}
|
||||
|
||||
# The list of supported Visual Studio versions we know how to detect.
|
||||
#
|
||||
# How to look for .bat file ?
|
||||
# - VS 2008 Express (x86):
|
||||
# * from registry key productdir, gives the full path to vsvarsall.bat. In
|
||||
# HKEY_LOCAL_MACHINE):
|
||||
# Software\Microsoft\VCEpress\9.0\Setup\VC\productdir
|
||||
# * from environmnent variable VS90COMNTOOLS: the path is then ..\..\VC
|
||||
# relatively to the path given by the variable.
|
||||
#
|
||||
# - VS 2008 Express (WoW6432: 32 bits on windows x64):
|
||||
# Software\Wow6432Node\Microsoft\VCEpress\9.0\Setup\VC\productdir
|
||||
#
|
||||
# - VS 2005 Express (x86):
|
||||
# * from registry key productdir, gives the full path to vsvarsall.bat. In
|
||||
# HKEY_LOCAL_MACHINE):
|
||||
# Software\Microsoft\VCEpress\8.0\Setup\VC\productdir
|
||||
# * from environmnent variable VS80COMNTOOLS: the path is then ..\..\VC
|
||||
# relatively to the path given by the variable.
|
||||
#
|
||||
# - VS 2005 Express (WoW6432: 32 bits on windows x64): does not seem to have a
|
||||
# productdir ?
|
||||
#
|
||||
# - VS 2003 .Net (pro edition ? x86):
|
||||
# * from registry key productdir. The path is then ..\Common7\Tools\
|
||||
# relatively to the key. The key is in HKEY_LOCAL_MACHINE):
|
||||
# Software\Microsoft\VisualStudio\7.1\Setup\VC\productdir
|
||||
# * from environmnent variable VS71COMNTOOLS: the path is the full path to
|
||||
# vsvars32.bat
|
||||
#
|
||||
# - VS 98 (VS 6):
|
||||
# * from registry key productdir. The path is then Bin
|
||||
# relatively to the key. The key is in HKEY_LOCAL_MACHINE):
|
||||
# Software\Microsoft\VisualStudio\6.0\Setup\VC98\productdir
|
||||
#
|
||||
# The first version found in the list is the one used by default if
|
||||
# there are multiple versions installed. Barring good reasons to
|
||||
# the contrary, this means we should list versions from most recent
|
||||
# to oldest. Pro versions get listed before Express versions on the
|
||||
# assumption that, by default, you'd rather use the version you paid
|
||||
# good money for in preference to whatever Microsoft makes available
|
||||
# for free.
|
||||
#
|
||||
# If you update this list, update _VCVER and _VCVER_TO_PRODUCT_DIR in
|
||||
# Tool/MSCommon/vc.py, and the MSVC_VERSION documentation in Tool/msvc.xml.
|
||||
|
||||
SupportedVSList = [
|
||||
# Visual Studio 2019
|
||||
VisualStudio('14.2',
|
||||
vc_version='14.2',
|
||||
sdk_version='10.0A',
|
||||
hkeys=[],
|
||||
common_tools_var='VS160COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\devenv.com',
|
||||
# should be a fallback, prefer use vswhere installationPath
|
||||
batch_file_path=r'Common7\Tools\VsDevCmd.bat',
|
||||
supported_arch=['x86', 'amd64', "arm"],
|
||||
),
|
||||
|
||||
# Visual Studio 2017
|
||||
VisualStudio('14.1',
|
||||
vc_version='14.1',
|
||||
sdk_version='10.0A',
|
||||
hkeys=[],
|
||||
common_tools_var='VS150COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\devenv.com',
|
||||
# should be a fallback, prefer use vswhere installationPath
|
||||
batch_file_path=r'Common7\Tools\VsDevCmd.bat',
|
||||
supported_arch=['x86', 'amd64', "arm"],
|
||||
),
|
||||
|
||||
# Visual C++ 2017 Express Edition (for Desktop)
|
||||
VisualStudio('14.1Exp',
|
||||
vc_version='14.1',
|
||||
sdk_version='10.0A',
|
||||
hkeys=[],
|
||||
common_tools_var='VS150COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\WDExpress.exe',
|
||||
# should be a fallback, prefer use vswhere installationPath
|
||||
batch_file_path=r'Common7\Tools\VsDevCmd.bat',
|
||||
supported_arch=['x86', 'amd64', "arm"],
|
||||
),
|
||||
|
||||
# Visual Studio 2015
|
||||
VisualStudio('14.0',
|
||||
vc_version='14.0',
|
||||
sdk_version='10.0',
|
||||
hkeys=[r'Microsoft\VisualStudio\14.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS140COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\devenv.com',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
supported_arch=['x86', 'amd64', "arm"],
|
||||
),
|
||||
|
||||
# Visual C++ 2015 Express Edition (for Desktop)
|
||||
VisualStudio('14.0Exp',
|
||||
vc_version='14.0',
|
||||
sdk_version='10.0A',
|
||||
hkeys=[r'Microsoft\VisualStudio\14.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS140COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\WDExpress.exe',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
supported_arch=['x86', 'amd64', "arm"],
|
||||
),
|
||||
|
||||
# Visual Studio 2013
|
||||
VisualStudio('12.0',
|
||||
vc_version='12.0',
|
||||
sdk_version='8.1A',
|
||||
hkeys=[r'Microsoft\VisualStudio\12.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS120COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\devenv.com',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
supported_arch=['x86', 'amd64'],
|
||||
),
|
||||
|
||||
# Visual C++ 2013 Express Edition (for Desktop)
|
||||
VisualStudio('12.0Exp',
|
||||
vc_version='12.0',
|
||||
sdk_version='8.1A',
|
||||
hkeys=[r'Microsoft\VisualStudio\12.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS120COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\WDExpress.exe',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
supported_arch=['x86', 'amd64'],
|
||||
),
|
||||
|
||||
# Visual Studio 2012
|
||||
VisualStudio('11.0',
|
||||
sdk_version='8.0A',
|
||||
hkeys=[r'Microsoft\VisualStudio\11.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS110COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\devenv.com',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
supported_arch=['x86', 'amd64'],
|
||||
),
|
||||
|
||||
# Visual C++ 2012 Express Edition (for Desktop)
|
||||
VisualStudio('11.0Exp',
|
||||
vc_version='11.0',
|
||||
sdk_version='8.0A',
|
||||
hkeys=[r'Microsoft\VisualStudio\11.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS110COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\WDExpress.exe',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
supported_arch=['x86', 'amd64'],
|
||||
),
|
||||
|
||||
# Visual Studio 2010
|
||||
VisualStudio('10.0',
|
||||
sdk_version='7.0A',
|
||||
hkeys=[r'Microsoft\VisualStudio\10.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS100COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\devenv.com',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
supported_arch=['x86', 'amd64'],
|
||||
),
|
||||
|
||||
# Visual C++ 2010 Express Edition
|
||||
VisualStudio('10.0Exp',
|
||||
vc_version='10.0',
|
||||
sdk_version='7.0A',
|
||||
hkeys=[r'Microsoft\VCExpress\10.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS100COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\VCExpress.exe',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
supported_arch=['x86'],
|
||||
),
|
||||
|
||||
# Visual Studio 2008
|
||||
VisualStudio('9.0',
|
||||
sdk_version='6.0A',
|
||||
hkeys=[r'Microsoft\VisualStudio\9.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS90COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\devenv.com',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
supported_arch=['x86', 'amd64'],
|
||||
),
|
||||
|
||||
# Visual C++ 2008 Express Edition
|
||||
VisualStudio('9.0Exp',
|
||||
vc_version='9.0',
|
||||
sdk_version='6.0A',
|
||||
hkeys=[r'Microsoft\VCExpress\9.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS90COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\VCExpress.exe',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
supported_arch=['x86'],
|
||||
),
|
||||
|
||||
# Visual Studio 2005
|
||||
VisualStudio('8.0',
|
||||
sdk_version='6.0A',
|
||||
hkeys=[r'Microsoft\VisualStudio\8.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS80COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\devenv.com',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
default_dirname='Microsoft Visual Studio 8',
|
||||
supported_arch=['x86', 'amd64'],
|
||||
),
|
||||
|
||||
# Visual C++ 2005 Express Edition
|
||||
VisualStudio('8.0Exp',
|
||||
vc_version='8.0Exp',
|
||||
sdk_version='6.0A',
|
||||
hkeys=[r'Microsoft\VCExpress\8.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS80COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\VCExpress.exe',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
default_dirname='Microsoft Visual Studio 8',
|
||||
supported_arch=['x86'],
|
||||
),
|
||||
|
||||
# Visual Studio .NET 2003
|
||||
VisualStudio('7.1',
|
||||
sdk_version='6.0',
|
||||
hkeys=[r'Microsoft\VisualStudio\7.1\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS71COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\devenv.com',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
default_dirname='Microsoft Visual Studio .NET 2003',
|
||||
supported_arch=['x86'],
|
||||
),
|
||||
|
||||
# Visual Studio .NET
|
||||
VisualStudio('7.0',
|
||||
sdk_version='2003R2',
|
||||
hkeys=[r'Microsoft\VisualStudio\7.0\Setup\VS\ProductDir'],
|
||||
common_tools_var='VS70COMNTOOLS',
|
||||
executable_path=r'Common7\IDE\devenv.com',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
default_dirname='Microsoft Visual Studio .NET',
|
||||
supported_arch=['x86'],
|
||||
),
|
||||
|
||||
# Visual Studio 6.0
|
||||
VisualStudio('6.0',
|
||||
sdk_version='2003R1',
|
||||
hkeys=[r'Microsoft\VisualStudio\6.0\Setup\Microsoft Visual Studio\ProductDir',
|
||||
'use_dir'],
|
||||
common_tools_var='VS60COMNTOOLS',
|
||||
executable_path=r'Common\MSDev98\Bin\MSDEV.COM',
|
||||
batch_file_path=r'Common7\Tools\vsvars32.bat',
|
||||
default_dirname='Microsoft Visual Studio',
|
||||
supported_arch=['x86'],
|
||||
),
|
||||
]
|
||||
|
||||
SupportedVSMap = {}
|
||||
for vs in SupportedVSList:
|
||||
SupportedVSMap[vs.version] = vs
|
||||
|
||||
|
||||
# Finding installed versions of Visual Studio isn't cheap, because it
|
||||
# goes not only to the registry but also to the disk to sanity-check
|
||||
# that there is, in fact, a Visual Studio directory there and that the
|
||||
# registry entry isn't just stale. Find this information once, when
|
||||
# requested, and cache it.
|
||||
|
||||
InstalledVSList = None
|
||||
InstalledVSMap = None
|
||||
|
||||
def get_installed_visual_studios(env=None):
|
||||
global InstalledVSList
|
||||
global InstalledVSMap
|
||||
if InstalledVSList is None:
|
||||
InstalledVSList = []
|
||||
InstalledVSMap = {}
|
||||
for vs in SupportedVSList:
|
||||
debug('trying to find VS %s' % vs.version)
|
||||
if vs.get_executable(env):
|
||||
debug('found VS %s' % vs.version)
|
||||
InstalledVSList.append(vs)
|
||||
InstalledVSMap[vs.version] = vs
|
||||
return InstalledVSList
|
||||
|
||||
def reset_installed_visual_studios():
|
||||
global InstalledVSList
|
||||
global InstalledVSMap
|
||||
InstalledVSList = None
|
||||
InstalledVSMap = None
|
||||
for vs in SupportedVSList:
|
||||
vs.reset()
|
||||
|
||||
# Need to clear installed VC's as well as they are used in finding
|
||||
# installed VS's
|
||||
SCons.Tool.MSCommon.vc.reset_installed_vcs()
|
||||
|
||||
|
||||
# We may be asked to update multiple construction environments with
|
||||
# SDK information. When doing this, we check on-disk for whether
|
||||
# the SDK has 'mfc' and 'atl' subdirectories. Since going to disk
|
||||
# is expensive, cache results by directory.
|
||||
|
||||
#SDKEnvironmentUpdates = {}
|
||||
#
|
||||
#def set_sdk_by_directory(env, sdk_dir):
|
||||
# global SDKEnvironmentUpdates
|
||||
# try:
|
||||
# env_tuple_list = SDKEnvironmentUpdates[sdk_dir]
|
||||
# except KeyError:
|
||||
# env_tuple_list = []
|
||||
# SDKEnvironmentUpdates[sdk_dir] = env_tuple_list
|
||||
#
|
||||
# include_path = os.path.join(sdk_dir, 'include')
|
||||
# mfc_path = os.path.join(include_path, 'mfc')
|
||||
# atl_path = os.path.join(include_path, 'atl')
|
||||
#
|
||||
# if os.path.exists(mfc_path):
|
||||
# env_tuple_list.append(('INCLUDE', mfc_path))
|
||||
# if os.path.exists(atl_path):
|
||||
# env_tuple_list.append(('INCLUDE', atl_path))
|
||||
# env_tuple_list.append(('INCLUDE', include_path))
|
||||
#
|
||||
# env_tuple_list.append(('LIB', os.path.join(sdk_dir, 'lib')))
|
||||
# env_tuple_list.append(('LIBPATH', os.path.join(sdk_dir, 'lib')))
|
||||
# env_tuple_list.append(('PATH', os.path.join(sdk_dir, 'bin')))
|
||||
#
|
||||
# for variable, directory in env_tuple_list:
|
||||
# env.PrependENVPath(variable, directory)
|
||||
|
||||
def msvs_exists(env=None):
|
||||
return (len(get_installed_visual_studios(env)) > 0)
|
||||
|
||||
def get_vs_by_version(msvs):
|
||||
global InstalledVSMap
|
||||
global SupportedVSMap
|
||||
|
||||
debug('called')
|
||||
if msvs not in SupportedVSMap:
|
||||
msg = "Visual Studio version %s is not supported" % repr(msvs)
|
||||
raise SCons.Errors.UserError(msg)
|
||||
get_installed_visual_studios()
|
||||
vs = InstalledVSMap.get(msvs)
|
||||
debug('InstalledVSMap:%s' % InstalledVSMap)
|
||||
debug('found vs:%s' % vs)
|
||||
# Some check like this would let us provide a useful error message
|
||||
# if they try to set a Visual Studio version that's not installed.
|
||||
# However, we also want to be able to run tests (like the unit
|
||||
# tests) on systems that don't, or won't ever, have it installed.
|
||||
# It might be worth resurrecting this, with some configurable
|
||||
# setting that the tests can use to bypass the check.
|
||||
#if not vs:
|
||||
# msg = "Visual Studio version %s is not installed" % repr(msvs)
|
||||
# raise SCons.Errors.UserError, msg
|
||||
return vs
|
||||
|
||||
def get_default_version(env):
|
||||
"""Returns the default version string to use for MSVS.
|
||||
|
||||
If no version was requested by the user through the MSVS environment
|
||||
variable, query all the available visual studios through
|
||||
get_installed_visual_studios, and take the highest one.
|
||||
|
||||
Return
|
||||
------
|
||||
version: str
|
||||
the default version.
|
||||
"""
|
||||
if 'MSVS' not in env or not SCons.Util.is_Dict(env['MSVS']):
|
||||
# get all versions, and remember them for speed later
|
||||
versions = [vs.version for vs in get_installed_visual_studios()]
|
||||
env['MSVS'] = {'VERSIONS' : versions}
|
||||
else:
|
||||
versions = env['MSVS'].get('VERSIONS', [])
|
||||
|
||||
if 'MSVS_VERSION' not in env:
|
||||
if versions:
|
||||
env['MSVS_VERSION'] = versions[0] #use highest version by default
|
||||
else:
|
||||
debug('WARNING: no installed versions found, '
|
||||
'using first in SupportedVSList (%s)' % SupportedVSList[0].version)
|
||||
env['MSVS_VERSION'] = SupportedVSList[0].version
|
||||
|
||||
env['MSVS']['VERSION'] = env['MSVS_VERSION']
|
||||
|
||||
return env['MSVS_VERSION']
|
||||
|
||||
def get_default_arch(env):
|
||||
"""Return the default arch to use for MSVS
|
||||
|
||||
if no version was requested by the user through the MSVS_ARCH environment
|
||||
variable, select x86
|
||||
|
||||
Return
|
||||
------
|
||||
arch: str
|
||||
"""
|
||||
arch = env.get('MSVS_ARCH', 'x86')
|
||||
|
||||
msvs = InstalledVSMap.get(env['MSVS_VERSION'])
|
||||
|
||||
if not msvs:
|
||||
arch = 'x86'
|
||||
elif arch not in msvs.get_supported_arch():
|
||||
fmt = "Visual Studio version %s does not support architecture %s"
|
||||
raise SCons.Errors.UserError(fmt % (env['MSVS_VERSION'], arch))
|
||||
|
||||
return arch
|
||||
|
||||
def merge_default_version(env):
|
||||
version = get_default_version(env)
|
||||
arch = get_default_arch(env)
|
||||
|
||||
def msvs_setup_env(env):
|
||||
batfilename = msvs.get_batch_file()
|
||||
msvs = get_vs_by_version(version)
|
||||
if msvs is None:
|
||||
return
|
||||
|
||||
# XXX: I think this is broken. This will silently set a bogus tool instead
|
||||
# of failing, but there is no other way with the current scons tool
|
||||
# framework
|
||||
if batfilename is not None:
|
||||
|
||||
vars = ('LIB', 'LIBPATH', 'PATH', 'INCLUDE')
|
||||
|
||||
msvs_list = get_installed_visual_studios()
|
||||
vscommonvarnames = [vs.common_tools_var for vs in msvs_list]
|
||||
save_ENV = env['ENV']
|
||||
nenv = normalize_env(env['ENV'],
|
||||
['COMSPEC'] + vscommonvarnames,
|
||||
force=True)
|
||||
try:
|
||||
output = get_output(batfilename, arch, env=nenv)
|
||||
finally:
|
||||
env['ENV'] = save_ENV
|
||||
vars = parse_output(output, vars)
|
||||
|
||||
for k, v in vars.items():
|
||||
env.PrependENVPath(k, v, delete_existing=1)
|
||||
|
||||
def query_versions():
|
||||
"""Query the system to get available versions of VS. A version is
|
||||
considered when a batfile is found."""
|
||||
msvs_list = get_installed_visual_studios()
|
||||
versions = [msvs.version for msvs in msvs_list]
|
||||
return versions
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
116
scons/scons-local-4.0.1/SCons/Tool/PharLapCommon.py
Normal file
116
scons/scons-local-4.0.1/SCons/Tool/PharLapCommon.py
Normal file
|
@ -0,0 +1,116 @@
|
|||
"""SCons.Tool.PharLapCommon
|
||||
|
||||
This module contains common code used by all Tools for the
|
||||
Phar Lap ETS tool chain. Right now, this is linkloc and
|
||||
386asm.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import os
|
||||
import os.path
|
||||
import SCons.Errors
|
||||
import SCons.Util
|
||||
import re
|
||||
|
||||
def getPharLapPath():
|
||||
"""Reads the registry to find the installed path of the Phar Lap ETS
|
||||
development kit.
|
||||
|
||||
Raises UserError if no installed version of Phar Lap can
|
||||
be found."""
|
||||
|
||||
if not SCons.Util.can_read_reg:
|
||||
raise SCons.Errors.InternalError("No Windows registry module was found")
|
||||
try:
|
||||
k=SCons.Util.RegOpenKeyEx(SCons.Util.HKEY_LOCAL_MACHINE,
|
||||
'SOFTWARE\\Pharlap\\ETS')
|
||||
val, type = SCons.Util.RegQueryValueEx(k, 'BaseDir')
|
||||
|
||||
# The following is a hack...there is (not surprisingly)
|
||||
# an odd issue in the Phar Lap plug in that inserts
|
||||
# a bunch of junk data after the phar lap path in the
|
||||
# registry. We must trim it.
|
||||
idx=val.find('\0')
|
||||
if idx >= 0:
|
||||
val = val[:idx]
|
||||
|
||||
return os.path.normpath(val)
|
||||
except SCons.Util.RegError:
|
||||
raise SCons.Errors.UserError("Cannot find Phar Lap ETS path in the registry. Is it installed properly?")
|
||||
|
||||
REGEX_ETS_VER = re.compile(r'#define\s+ETS_VER\s+([0-9]+)')
|
||||
|
||||
def getPharLapVersion():
|
||||
"""Returns the version of the installed ETS Tool Suite as a
|
||||
decimal number. This version comes from the ETS_VER #define in
|
||||
the embkern.h header. For example, '#define ETS_VER 1010' (which
|
||||
is what Phar Lap 10.1 defines) would cause this method to return
|
||||
1010. Phar Lap 9.1 does not have such a #define, but this method
|
||||
will return 910 as a default.
|
||||
|
||||
Raises UserError if no installed version of Phar Lap can
|
||||
be found."""
|
||||
|
||||
include_path = os.path.join(getPharLapPath(), os.path.normpath("include/embkern.h"))
|
||||
if not os.path.exists(include_path):
|
||||
raise SCons.Errors.UserError("Cannot find embkern.h in ETS include directory.\nIs Phar Lap ETS installed properly?")
|
||||
with open(include_path, 'r') as f:
|
||||
mo = REGEX_ETS_VER.search(f.read())
|
||||
if mo:
|
||||
return int(mo.group(1))
|
||||
# Default return for Phar Lap 9.1
|
||||
return 910
|
||||
|
||||
def addPharLapPaths(env):
|
||||
"""This function adds the path to the Phar Lap binaries, includes,
|
||||
and libraries, if they are not already there."""
|
||||
ph_path = getPharLapPath()
|
||||
|
||||
try:
|
||||
env_dict = env['ENV']
|
||||
except KeyError:
|
||||
env_dict = {}
|
||||
env['ENV'] = env_dict
|
||||
SCons.Util.AddPathIfNotExists(env_dict, 'PATH',
|
||||
os.path.join(ph_path, 'bin'))
|
||||
SCons.Util.AddPathIfNotExists(env_dict, 'INCLUDE',
|
||||
os.path.join(ph_path, 'include'))
|
||||
SCons.Util.AddPathIfNotExists(env_dict, 'LIB',
|
||||
os.path.join(ph_path, 'lib'))
|
||||
SCons.Util.AddPathIfNotExists(env_dict, 'LIB',
|
||||
os.path.join(ph_path, os.path.normpath('lib/vclib')))
|
||||
|
||||
env['PHARLAP_PATH'] = getPharLapPath()
|
||||
env['PHARLAP_VERSION'] = str(getPharLapVersion())
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
1331
scons/scons-local-4.0.1/SCons/Tool/__init__.py
Normal file
1331
scons/scons-local-4.0.1/SCons/Tool/__init__.py
Normal file
File diff suppressed because it is too large
Load diff
43
scons/scons-local-4.0.1/SCons/Tool/aixc++.py
Normal file
43
scons/scons-local-4.0.1/SCons/Tool/aixc++.py
Normal file
|
@ -0,0 +1,43 @@
|
|||
"""SCons.Tool.aixc++
|
||||
|
||||
Tool-specific initialization for IBM xlC / Visual Age C++ compiler.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
#forward proxy to the preffered cxx version
|
||||
from SCons.Tool.aixcxx import *
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
74
scons/scons-local-4.0.1/SCons/Tool/aixcc.py
Normal file
74
scons/scons-local-4.0.1/SCons/Tool/aixcc.py
Normal file
|
@ -0,0 +1,74 @@
|
|||
"""SCons.Tool.aixcc
|
||||
|
||||
Tool-specific initialization for IBM xlc / Visual Age C compiler.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import os.path
|
||||
|
||||
import SCons.Platform.aix
|
||||
|
||||
from . import cc
|
||||
|
||||
packages = ['vac.C', 'ibmcxx.cmp']
|
||||
|
||||
def get_xlc(env):
|
||||
xlc = env.get('CC', 'xlc')
|
||||
return SCons.Platform.aix.get_xlc(env, xlc, packages)
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for xlc / Visual Age
|
||||
suite to an Environment."""
|
||||
path, _cc, version = get_xlc(env)
|
||||
if path and _cc:
|
||||
_cc = os.path.join(path, _cc)
|
||||
|
||||
if 'CC' not in env:
|
||||
env['CC'] = _cc
|
||||
|
||||
cc.generate(env)
|
||||
|
||||
if version:
|
||||
env['CCVERSION'] = version
|
||||
|
||||
def exists(env):
|
||||
path, _cc, version = get_xlc(env)
|
||||
if path and _cc:
|
||||
xlc = os.path.join(path, _cc)
|
||||
if os.path.exists(xlc):
|
||||
return xlc
|
||||
return None
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
77
scons/scons-local-4.0.1/SCons/Tool/aixcxx.py
Normal file
77
scons/scons-local-4.0.1/SCons/Tool/aixcxx.py
Normal file
|
@ -0,0 +1,77 @@
|
|||
"""SCons.Tool.aixc++
|
||||
|
||||
Tool-specific initialization for IBM xlC / Visual Age C++ compiler.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import os.path
|
||||
|
||||
import SCons.Platform.aix
|
||||
|
||||
import SCons.Tool.cxx
|
||||
cplusplus = SCons.Tool.cxx
|
||||
#cplusplus = __import__('cxx', globals(), locals(), [])
|
||||
|
||||
packages = ['vacpp.cmp.core', 'vacpp.cmp.batch', 'vacpp.cmp.C', 'ibmcxx.cmp']
|
||||
|
||||
def get_xlc(env):
|
||||
xlc = env.get('CXX', 'xlC')
|
||||
return SCons.Platform.aix.get_xlc(env, xlc, packages)
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for xlC / Visual Age
|
||||
suite to an Environment."""
|
||||
path, _cxx, version = get_xlc(env)
|
||||
if path and _cxx:
|
||||
_cxx = os.path.join(path, _cxx)
|
||||
|
||||
if 'CXX' not in env:
|
||||
env['CXX'] = _cxx
|
||||
|
||||
cplusplus.generate(env)
|
||||
|
||||
if version:
|
||||
env['CXXVERSION'] = version
|
||||
|
||||
def exists(env):
|
||||
path, _cxx, version = get_xlc(env)
|
||||
if path and _cxx:
|
||||
xlc = os.path.join(path, _cxx)
|
||||
if os.path.exists(xlc):
|
||||
return xlc
|
||||
return None
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
80
scons/scons-local-4.0.1/SCons/Tool/aixf77.py
Normal file
80
scons/scons-local-4.0.1/SCons/Tool/aixf77.py
Normal file
|
@ -0,0 +1,80 @@
|
|||
"""SCons.Tool.aixf77
|
||||
|
||||
Tool-specific initialization for IBM Visual Age f77 Fortran compiler.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import os.path
|
||||
|
||||
#import SCons.Platform.aix
|
||||
|
||||
from . import f77
|
||||
|
||||
# It would be good to look for the AIX F77 package the same way we're now
|
||||
# looking for the C and C++ packages. This should be as easy as supplying
|
||||
# the correct package names in the following list and uncommenting the
|
||||
# SCons.Platform.aix_get_xlc() call in the function below.
|
||||
packages = []
|
||||
|
||||
def get_xlf77(env):
|
||||
xlf77 = env.get('F77', 'xlf77')
|
||||
xlf77_r = env.get('SHF77', 'xlf77_r')
|
||||
#return SCons.Platform.aix.get_xlc(env, xlf77, xlf77_r, packages)
|
||||
return (None, xlf77, xlf77_r, None)
|
||||
|
||||
def generate(env):
|
||||
"""
|
||||
Add Builders and construction variables for the Visual Age FORTRAN
|
||||
compiler to an Environment.
|
||||
"""
|
||||
path, _f77, _shf77, version = get_xlf77(env)
|
||||
if path:
|
||||
_f77 = os.path.join(path, _f77)
|
||||
_shf77 = os.path.join(path, _shf77)
|
||||
|
||||
f77.generate(env)
|
||||
|
||||
env['F77'] = _f77
|
||||
env['SHF77'] = _shf77
|
||||
|
||||
def exists(env):
|
||||
path, _f77, _shf77, version = get_xlf77(env)
|
||||
if path and _f77:
|
||||
xlf77 = os.path.join(path, _f77)
|
||||
if os.path.exists(xlf77):
|
||||
return xlf77
|
||||
return None
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
81
scons/scons-local-4.0.1/SCons/Tool/aixlink.py
Normal file
81
scons/scons-local-4.0.1/SCons/Tool/aixlink.py
Normal file
|
@ -0,0 +1,81 @@
|
|||
"""SCons.Tool.aixlink
|
||||
|
||||
Tool-specific initialization for the IBM Visual Age linker.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import os
|
||||
import os.path
|
||||
|
||||
import SCons.Util
|
||||
|
||||
from . import aixcc
|
||||
from . import link
|
||||
|
||||
import SCons.Tool.cxx
|
||||
cplusplus = SCons.Tool.cxx
|
||||
#cplusplus = __import__('cxx', globals(), locals(), [])
|
||||
|
||||
|
||||
def smart_linkflags(source, target, env, for_signature):
|
||||
if cplusplus.iscplusplus(source):
|
||||
build_dir = env.subst('$BUILDDIR', target=target, source=source)
|
||||
if build_dir:
|
||||
return '-qtempinc=' + os.path.join(build_dir, 'tempinc')
|
||||
return ''
|
||||
|
||||
def generate(env):
|
||||
"""
|
||||
Add Builders and construction variables for Visual Age linker to
|
||||
an Environment.
|
||||
"""
|
||||
link.generate(env)
|
||||
|
||||
env['SMARTLINKFLAGS'] = smart_linkflags
|
||||
env['LINKFLAGS'] = SCons.Util.CLVar('$SMARTLINKFLAGS')
|
||||
env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -qmkshrobj -qsuppress=1501-218')
|
||||
env['SHLIBSUFFIX'] = '.a'
|
||||
|
||||
def exists(env):
|
||||
# TODO: sync with link.smart_link() to choose a linker
|
||||
linkers = { 'CXX': ['aixc++'], 'CC': ['aixcc'] }
|
||||
alltools = []
|
||||
for langvar, linktools in linkers.items():
|
||||
if langvar in env: # use CC over CXX when user specified CC but not CXX
|
||||
return SCons.Tool.FindTool(linktools, env)
|
||||
alltools.extend(linktools)
|
||||
return SCons.Tool.FindTool(alltools, env)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
224
scons/scons-local-4.0.1/SCons/Tool/applelink.py
Normal file
224
scons/scons-local-4.0.1/SCons/Tool/applelink.py
Normal file
|
@ -0,0 +1,224 @@
|
|||
"""SCons.Tool.applelink
|
||||
|
||||
Tool-specific initialization for Apple's gnu-like linker.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import SCons.Util
|
||||
|
||||
# Even though the Mac is based on the GNU toolchain, it doesn't understand
|
||||
# the -rpath option, so we use the "link" tool instead of "gnulink".
|
||||
from . import link
|
||||
|
||||
from SCons.Tool import ShLibSonameGenerator
|
||||
|
||||
class AppleLinkInvalidCurrentVersionException(Exception):
|
||||
pass
|
||||
|
||||
class AppleLinkInvalidCompatibilityVersionException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def _applelib_versioned_lib_suffix(env, suffix, version):
|
||||
"""For suffix='.dylib' and version='0.1.2' it returns '.0.1.2.dylib'"""
|
||||
Verbose = False
|
||||
if Verbose:
|
||||
print("_applelib_versioned_lib_suffix: suffix={!r}".format(suffix))
|
||||
print("_applelib_versioned_lib_suffix: version={!r}".format(version))
|
||||
if version not in suffix:
|
||||
suffix = "." + version + suffix
|
||||
if Verbose:
|
||||
print("_applelib_versioned_lib_suffix: return suffix={!r}".format(suffix))
|
||||
return suffix
|
||||
|
||||
|
||||
def _applelib_versioned_lib_soname(env, libnode, version, prefix, suffix, name_func):
|
||||
"""For libnode='/optional/dir/libfoo.X.Y.Z.dylib' it returns 'libfoo.X.dylib'"""
|
||||
Verbose = False
|
||||
if Verbose:
|
||||
print("_applelib_versioned_lib_soname: version={!r}".format(version))
|
||||
name = name_func(env, libnode, version, prefix, suffix)
|
||||
if Verbose:
|
||||
print("_applelib_versioned_lib_soname: name={!r}".format(name))
|
||||
major = version.split('.')[0]
|
||||
(libname,_suffix) = name.split('.')
|
||||
# if a desired SONAME was supplied, use that, otherwise create
|
||||
# a default from the major version
|
||||
if env.get('SONAME'):
|
||||
soname = ShLibSonameGenerator(env, libnode)
|
||||
else:
|
||||
soname = '.'.join([libname, major, _suffix])
|
||||
if Verbose:
|
||||
print("_applelib_versioned_lib_soname: soname={!r}".format(soname))
|
||||
return soname
|
||||
|
||||
def _applelib_versioned_shlib_soname(env, libnode, version, prefix, suffix):
|
||||
return _applelib_versioned_lib_soname(env, libnode, version, prefix, suffix, link._versioned_shlib_name)
|
||||
|
||||
|
||||
# User programmatically describes how SHLIBVERSION maps to values for compat/current.
|
||||
_applelib_max_version_values = (65535, 255, 255)
|
||||
def _applelib_check_valid_version(version_string):
|
||||
"""
|
||||
Check that the version # is valid.
|
||||
X[.Y[.Z]]
|
||||
where X 0-65535
|
||||
where Y either not specified or 0-255
|
||||
where Z either not specified or 0-255
|
||||
:param version_string:
|
||||
:return:
|
||||
"""
|
||||
parts = version_string.split('.')
|
||||
if len(parts) > 3:
|
||||
return False, "Version string has too many periods [%s]"%version_string
|
||||
if len(parts) <= 0:
|
||||
return False, "Version string unspecified [%s]"%version_string
|
||||
|
||||
for (i, p) in enumerate(parts):
|
||||
try:
|
||||
p_i = int(p)
|
||||
except ValueError:
|
||||
return False, "Version component %s (from %s) is not a number"%(p, version_string)
|
||||
if p_i < 0 or p_i > _applelib_max_version_values[i]:
|
||||
return False, "Version component %s (from %s) is not valid value should be between 0 and %d"%(p, version_string, _applelib_max_version_values[i])
|
||||
|
||||
return True, ""
|
||||
|
||||
|
||||
def _applelib_currentVersionFromSoVersion(source, target, env, for_signature):
|
||||
"""
|
||||
A generator function to create the -Wl,-current_version flag if needed.
|
||||
If env['APPLELINK_NO_CURRENT_VERSION'] contains a true value no flag will be generated
|
||||
Otherwise if APPLELINK_CURRENT_VERSION is not specified, env['SHLIBVERSION']
|
||||
will be used.
|
||||
|
||||
:param source:
|
||||
:param target:
|
||||
:param env:
|
||||
:param for_signature:
|
||||
:return: A string providing the flag to specify the current_version of the shared library
|
||||
"""
|
||||
if env.get('APPLELINK_NO_CURRENT_VERSION', False):
|
||||
return ""
|
||||
elif env.get('APPLELINK_CURRENT_VERSION', False):
|
||||
version_string = env['APPLELINK_CURRENT_VERSION']
|
||||
elif env.get('SHLIBVERSION', False):
|
||||
version_string = env['SHLIBVERSION']
|
||||
else:
|
||||
return ""
|
||||
|
||||
version_string = ".".join(version_string.split('.')[:3])
|
||||
|
||||
valid, reason = _applelib_check_valid_version(version_string)
|
||||
if not valid:
|
||||
raise AppleLinkInvalidCurrentVersionException(reason)
|
||||
|
||||
return "-Wl,-current_version,%s" % version_string
|
||||
|
||||
|
||||
def _applelib_compatVersionFromSoVersion(source, target, env, for_signature):
|
||||
"""
|
||||
A generator function to create the -Wl,-compatibility_version flag if needed.
|
||||
If env['APPLELINK_NO_COMPATIBILITY_VERSION'] contains a true value no flag will be generated
|
||||
Otherwise if APPLELINK_COMPATIBILITY_VERSION is not specified
|
||||
the first two parts of env['SHLIBVERSION'] will be used with a .0 appended.
|
||||
|
||||
:param source:
|
||||
:param target:
|
||||
:param env:
|
||||
:param for_signature:
|
||||
:return: A string providing the flag to specify the compatibility_version of the shared library
|
||||
"""
|
||||
if env.get('APPLELINK_NO_COMPATIBILITY_VERSION', False):
|
||||
return ""
|
||||
elif env.get('APPLELINK_COMPATIBILITY_VERSION', False):
|
||||
version_string = env['APPLELINK_COMPATIBILITY_VERSION']
|
||||
elif env.get('SHLIBVERSION', False):
|
||||
version_string = ".".join(env['SHLIBVERSION'].split('.')[:2] + ['0'])
|
||||
else:
|
||||
return ""
|
||||
|
||||
if version_string is None:
|
||||
return ""
|
||||
|
||||
valid, reason = _applelib_check_valid_version(version_string)
|
||||
if not valid:
|
||||
raise AppleLinkInvalidCompatibilityVersionException(reason)
|
||||
|
||||
return "-Wl,-compatibility_version,%s" % version_string
|
||||
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for applelink to an
|
||||
Environment."""
|
||||
link.generate(env)
|
||||
|
||||
env['FRAMEWORKPATHPREFIX'] = '-F'
|
||||
env['_FRAMEWORKPATH'] = '${_concat(FRAMEWORKPATHPREFIX, FRAMEWORKPATH, "", __env__, RDirs)}'
|
||||
|
||||
env['_FRAMEWORKS'] = '${_concat("-framework ", FRAMEWORKS, "", __env__)}'
|
||||
env['LINKCOM'] = env['LINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
|
||||
env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -dynamiclib')
|
||||
env['SHLINKCOM'] = env['SHLINKCOM'] + ' $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
|
||||
|
||||
|
||||
# see: http://docstore.mik.ua/orelly/unix3/mac/ch05_04.htm for proper naming
|
||||
link._setup_versioned_lib_variables(env, tool = 'applelink')#, use_soname = use_soname)
|
||||
env['LINKCALLBACKS'] = link._versioned_lib_callbacks()
|
||||
env['LINKCALLBACKS']['VersionedShLibSuffix'] = _applelib_versioned_lib_suffix
|
||||
env['LINKCALLBACKS']['VersionedShLibSoname'] = _applelib_versioned_shlib_soname
|
||||
|
||||
env['_APPLELINK_CURRENT_VERSION'] = _applelib_currentVersionFromSoVersion
|
||||
env['_APPLELINK_COMPATIBILITY_VERSION'] = _applelib_compatVersionFromSoVersion
|
||||
env['_SHLIBVERSIONFLAGS'] = '$_APPLELINK_CURRENT_VERSION $_APPLELINK_COMPATIBILITY_VERSION '
|
||||
env['_LDMODULEVERSIONFLAGS'] = '$_APPLELINK_CURRENT_VERSION $_APPLELINK_COMPATIBILITY_VERSION '
|
||||
|
||||
# override the default for loadable modules, which are different
|
||||
# on OS X than dynamic shared libs. echoing what XCode does for
|
||||
# pre/suffixes:
|
||||
env['LDMODULEPREFIX'] = ''
|
||||
env['LDMODULESUFFIX'] = ''
|
||||
env['LDMODULEFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -bundle')
|
||||
env['LDMODULECOM'] = '$LDMODULE -o ${TARGET} $LDMODULEFLAGS $SOURCES $_LIBDIRFLAGS $_LIBFLAGS $_FRAMEWORKPATH $_FRAMEWORKS $FRAMEWORKSFLAGS'
|
||||
|
||||
env['__SHLIBVERSIONFLAGS'] = '${__libversionflags(__env__,"SHLIBVERSION","_SHLIBVERSIONFLAGS")}'
|
||||
|
||||
|
||||
|
||||
def exists(env):
|
||||
return env['PLATFORM'] == 'darwin'
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
63
scons/scons-local-4.0.1/SCons/Tool/ar.py
Normal file
63
scons/scons-local-4.0.1/SCons/Tool/ar.py
Normal file
|
@ -0,0 +1,63 @@
|
|||
"""SCons.Tool.ar
|
||||
|
||||
Tool-specific initialization for ar (library archive).
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import SCons.Defaults
|
||||
import SCons.Tool
|
||||
import SCons.Util
|
||||
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for ar to an Environment."""
|
||||
SCons.Tool.createStaticLibBuilder(env)
|
||||
|
||||
env['AR'] = 'ar'
|
||||
env['ARFLAGS'] = SCons.Util.CLVar('rc')
|
||||
env['ARCOM'] = '$AR $ARFLAGS $TARGET $SOURCES'
|
||||
env['LIBPREFIX'] = 'lib'
|
||||
env['LIBSUFFIX'] = '.a'
|
||||
|
||||
if env.get('RANLIB',env.Detect('ranlib')) :
|
||||
env['RANLIB'] = env.get('RANLIB','ranlib')
|
||||
env['RANLIBFLAGS'] = SCons.Util.CLVar('')
|
||||
env['RANLIBCOM'] = '$RANLIB $RANLIBFLAGS $TARGET'
|
||||
|
||||
def exists(env):
|
||||
return env.Detect('ar')
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
49
scons/scons-local-4.0.1/SCons/Tool/as.py
Normal file
49
scons/scons-local-4.0.1/SCons/Tool/as.py
Normal file
|
@ -0,0 +1,49 @@
|
|||
"""SCons.Tool.as
|
||||
|
||||
Tool-specific initialization for generic assembler.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
#
|
||||
# forward proxy to the preferred asm version
|
||||
#
|
||||
import SCons.Tool.asm
|
||||
|
||||
# Resolve FLAKE8 F401 (make sider happy)
|
||||
generate = SCons.Tool.asm.generate
|
||||
exists = SCons.Tool.asm.exists
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
78
scons/scons-local-4.0.1/SCons/Tool/asm.py
Normal file
78
scons/scons-local-4.0.1/SCons/Tool/asm.py
Normal file
|
@ -0,0 +1,78 @@
|
|||
"""SCons.Tool.as
|
||||
|
||||
Tool-specific initialization for as, the generic Posix assembler.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import SCons.Defaults
|
||||
import SCons.Tool
|
||||
import SCons.Util
|
||||
|
||||
assemblers = ['as']
|
||||
|
||||
ASSuffixes = ['.s', '.asm', '.ASM']
|
||||
ASPPSuffixes = ['.spp', '.SPP', '.sx']
|
||||
if SCons.Util.case_sensitive_suffixes('.s', '.S'):
|
||||
ASPPSuffixes.extend(['.S'])
|
||||
else:
|
||||
ASSuffixes.extend(['.S'])
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for as to an Environment."""
|
||||
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
|
||||
|
||||
for suffix in ASSuffixes:
|
||||
static_obj.add_action(suffix, SCons.Defaults.ASAction)
|
||||
shared_obj.add_action(suffix, SCons.Defaults.ASAction)
|
||||
static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter)
|
||||
shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter)
|
||||
|
||||
for suffix in ASPPSuffixes:
|
||||
static_obj.add_action(suffix, SCons.Defaults.ASPPAction)
|
||||
shared_obj.add_action(suffix, SCons.Defaults.ASPPAction)
|
||||
static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter)
|
||||
shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter)
|
||||
|
||||
env['AS'] = env.Detect(assemblers) or 'as'
|
||||
env['ASFLAGS'] = SCons.Util.CLVar('')
|
||||
env['ASCOM'] = '$AS $ASFLAGS -o $TARGET $SOURCES'
|
||||
env['ASPPFLAGS'] = '$ASFLAGS'
|
||||
env['ASPPCOM'] = '$CC $ASPPFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o $TARGET $SOURCES'
|
||||
|
||||
def exists(env):
|
||||
return env.Detect(assemblers)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
81
scons/scons-local-4.0.1/SCons/Tool/bcc32.py
Normal file
81
scons/scons-local-4.0.1/SCons/Tool/bcc32.py
Normal file
|
@ -0,0 +1,81 @@
|
|||
"""SCons.Tool.bcc32
|
||||
|
||||
XXX
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import os
|
||||
import os.path
|
||||
|
||||
import SCons.Defaults
|
||||
import SCons.Tool
|
||||
import SCons.Util
|
||||
|
||||
def findIt(program, env):
|
||||
# First search in the SCons path and then the OS path:
|
||||
borwin = env.WhereIs(program) or SCons.Util.WhereIs(program)
|
||||
if borwin:
|
||||
dir = os.path.dirname(borwin)
|
||||
env.PrependENVPath('PATH', dir)
|
||||
return borwin
|
||||
|
||||
def generate(env):
|
||||
findIt('bcc32', env)
|
||||
"""Add Builders and construction variables for bcc to an
|
||||
Environment."""
|
||||
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
|
||||
for suffix in ['.c', '.cpp']:
|
||||
static_obj.add_action(suffix, SCons.Defaults.CAction)
|
||||
shared_obj.add_action(suffix, SCons.Defaults.ShCAction)
|
||||
static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter)
|
||||
shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter)
|
||||
|
||||
env['CC'] = 'bcc32'
|
||||
env['CCFLAGS'] = SCons.Util.CLVar('')
|
||||
env['CFLAGS'] = SCons.Util.CLVar('')
|
||||
env['CCCOM'] = '$CC -q $CFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o$TARGET $SOURCES'
|
||||
env['SHCC'] = '$CC'
|
||||
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
|
||||
env['SHCFLAGS'] = SCons.Util.CLVar('$CFLAGS')
|
||||
env['SHCCCOM'] = '$SHCC -WD $SHCFLAGS $SHCCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS -c -o$TARGET $SOURCES'
|
||||
env['CPPDEFPREFIX'] = '-D'
|
||||
env['CPPDEFSUFFIX'] = ''
|
||||
env['INCPREFIX'] = '-I'
|
||||
env['INCSUFFIX'] = ''
|
||||
env['SHOBJSUFFIX'] = '.dll'
|
||||
env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 0
|
||||
env['CFILESUFFIX'] = '.cpp'
|
||||
|
||||
def exists(env):
|
||||
return findIt('bcc32', env)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
44
scons/scons-local-4.0.1/SCons/Tool/c++.py
Normal file
44
scons/scons-local-4.0.1/SCons/Tool/c++.py
Normal file
|
@ -0,0 +1,44 @@
|
|||
"""SCons.Tool.c++
|
||||
|
||||
Tool-specific initialization for generic Posix C++ compilers.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
|
||||
#forward proxy to the preffered cxx version
|
||||
from SCons.Tool.cxx import *
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
105
scons/scons-local-4.0.1/SCons/Tool/cc.py
Normal file
105
scons/scons-local-4.0.1/SCons/Tool/cc.py
Normal file
|
@ -0,0 +1,105 @@
|
|||
"""SCons.Tool.cc
|
||||
|
||||
Tool-specific initialization for generic Posix C compilers.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import SCons.Tool
|
||||
import SCons.Defaults
|
||||
import SCons.Util
|
||||
|
||||
CSuffixes = ['.c', '.m']
|
||||
if not SCons.Util.case_sensitive_suffixes('.c', '.C'):
|
||||
CSuffixes.append('.C')
|
||||
|
||||
def add_common_cc_variables(env):
|
||||
"""
|
||||
Add underlying common "C compiler" variables that
|
||||
are used by multiple tools (specifically, c++).
|
||||
"""
|
||||
if '_CCCOMCOM' not in env:
|
||||
env['_CCCOMCOM'] = '$CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS'
|
||||
# It's a hack to test for darwin here, but the alternative
|
||||
# of creating an applecc.py to contain this seems overkill.
|
||||
# Maybe someday the Apple platform will require more setup and
|
||||
# this logic will be moved.
|
||||
env['FRAMEWORKS'] = SCons.Util.CLVar('')
|
||||
env['FRAMEWORKPATH'] = SCons.Util.CLVar('')
|
||||
if env['PLATFORM'] == 'darwin':
|
||||
env['_CCCOMCOM'] = env['_CCCOMCOM'] + ' $_FRAMEWORKPATH'
|
||||
|
||||
if 'CCFLAGS' not in env:
|
||||
env['CCFLAGS'] = SCons.Util.CLVar('')
|
||||
|
||||
if 'SHCCFLAGS' not in env:
|
||||
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
|
||||
|
||||
compilers = ['cc']
|
||||
|
||||
def generate(env):
|
||||
"""
|
||||
Add Builders and construction variables for C compilers to an Environment.
|
||||
"""
|
||||
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
|
||||
|
||||
for suffix in CSuffixes:
|
||||
static_obj.add_action(suffix, SCons.Defaults.CAction)
|
||||
shared_obj.add_action(suffix, SCons.Defaults.ShCAction)
|
||||
static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter)
|
||||
shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter)
|
||||
|
||||
add_common_cc_variables(env)
|
||||
|
||||
if 'CC' not in env:
|
||||
env['CC'] = env.Detect(compilers) or compilers[0]
|
||||
env['CFLAGS'] = SCons.Util.CLVar('')
|
||||
env['CCCOM'] = '$CC -o $TARGET -c $CFLAGS $CCFLAGS $_CCCOMCOM $SOURCES'
|
||||
env['SHCC'] = '$CC'
|
||||
env['SHCFLAGS'] = SCons.Util.CLVar('$CFLAGS')
|
||||
env['SHCCCOM'] = '$SHCC -o $TARGET -c $SHCFLAGS $SHCCFLAGS $_CCCOMCOM $SOURCES'
|
||||
|
||||
env['CPPDEFPREFIX'] = '-D'
|
||||
env['CPPDEFSUFFIX'] = ''
|
||||
env['INCPREFIX'] = '-I'
|
||||
env['INCSUFFIX'] = ''
|
||||
env['SHOBJSUFFIX'] = '.os'
|
||||
env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 0
|
||||
|
||||
env['CFILESUFFIX'] = '.c'
|
||||
|
||||
def exists(env):
|
||||
return env.Detect(env.get('CC', compilers))
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
100
scons/scons-local-4.0.1/SCons/Tool/clang.py
Normal file
100
scons/scons-local-4.0.1/SCons/Tool/clang.py
Normal file
|
@ -0,0 +1,100 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
|
||||
"""SCons.Tool.clang
|
||||
|
||||
Tool-specific initialization for clang.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
# Based on SCons/Tool/gcc.py by Paweł Tomulik 2014 as a separate tool.
|
||||
# Brought into the SCons mainline by Russel Winder 2017.
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import SCons.Util
|
||||
import SCons.Tool.cc
|
||||
from SCons.Tool.clangCommon import get_clang_install_dirs
|
||||
from SCons.Tool.MSCommon import msvc_setup_env_once
|
||||
|
||||
|
||||
compilers = ['clang']
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for clang to an Environment."""
|
||||
SCons.Tool.cc.generate(env)
|
||||
|
||||
if env['PLATFORM'] == 'win32':
|
||||
# Ensure that we have a proper path for clang
|
||||
clang = SCons.Tool.find_program_path(env, compilers[0],
|
||||
default_paths=get_clang_install_dirs(env['PLATFORM']))
|
||||
if clang:
|
||||
clang_bin_dir = os.path.dirname(clang)
|
||||
env.AppendENVPath('PATH', clang_bin_dir)
|
||||
|
||||
# Set-up ms tools paths
|
||||
msvc_setup_env_once(env)
|
||||
|
||||
|
||||
env['CC'] = env.Detect(compilers) or 'clang'
|
||||
if env['PLATFORM'] in ['cygwin', 'win32']:
|
||||
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS')
|
||||
else:
|
||||
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS -fPIC')
|
||||
|
||||
# determine compiler version
|
||||
if env['CC']:
|
||||
#pipe = SCons.Action._subproc(env, [env['CC'], '-dumpversion'],
|
||||
pipe = SCons.Action._subproc(env, [env['CC'], '--version'],
|
||||
stdin='devnull',
|
||||
stderr='devnull',
|
||||
stdout=subprocess.PIPE)
|
||||
if pipe.wait() != 0: return
|
||||
# clang -dumpversion is of no use
|
||||
with pipe.stdout:
|
||||
line = pipe.stdout.readline()
|
||||
if sys.version_info[0] > 2:
|
||||
line = line.decode()
|
||||
match = re.search(r'clang +version +([0-9]+(?:\.[0-9]+)+)', line)
|
||||
if match:
|
||||
env['CCVERSION'] = match.group(1)
|
||||
|
||||
def exists(env):
|
||||
return env.Detect(compilers)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
18
scons/scons-local-4.0.1/SCons/Tool/clangCommon/__init__.py
Normal file
18
scons/scons-local-4.0.1/SCons/Tool/clangCommon/__init__.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
"""
|
||||
Common routines and data for clang tools
|
||||
"""
|
||||
|
||||
clang_win32_dirs = [
|
||||
r'C:\Program Files\LLVM\bin',
|
||||
r'C:\cygwin64\bin',
|
||||
r'C:\msys64',
|
||||
r'C:\msys64\mingw64\bin',
|
||||
r'C:\cygwin\bin',
|
||||
r'C:\msys',
|
||||
]
|
||||
|
||||
def get_clang_install_dirs(platform):
|
||||
if platform == 'win32':
|
||||
return clang_win32_dirs
|
||||
else:
|
||||
return []
|
108
scons/scons-local-4.0.1/SCons/Tool/clangxx.py
Normal file
108
scons/scons-local-4.0.1/SCons/Tool/clangxx.py
Normal file
|
@ -0,0 +1,108 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
|
||||
"""SCons.Tool.clang++
|
||||
|
||||
Tool-specific initialization for clang++.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
# Based on SCons/Tool/g++.py by Paweł Tomulik 2014 as a separate tool.
|
||||
# Brought into the SCons mainline by Russel Winder 2017.
|
||||
|
||||
import os.path
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import SCons.Tool
|
||||
import SCons.Util
|
||||
import SCons.Tool.cxx
|
||||
from SCons.Tool.clangCommon import get_clang_install_dirs
|
||||
from SCons.Tool.MSCommon import msvc_setup_env_once
|
||||
|
||||
|
||||
compilers = ['clang++']
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for clang++ to an Environment."""
|
||||
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
|
||||
|
||||
SCons.Tool.cxx.generate(env)
|
||||
|
||||
env['CXX'] = env.Detect(compilers) or 'clang++'
|
||||
|
||||
# platform specific settings
|
||||
if env['PLATFORM'] == 'aix':
|
||||
env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS -mminimal-toc')
|
||||
env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1
|
||||
env['SHOBJSUFFIX'] = '$OBJSUFFIX'
|
||||
elif env['PLATFORM'] == 'hpux':
|
||||
env['SHOBJSUFFIX'] = '.pic.o'
|
||||
elif env['PLATFORM'] == 'sunos':
|
||||
env['SHOBJSUFFIX'] = '.pic.o'
|
||||
elif env['PLATFORM'] == 'win32':
|
||||
# Ensure that we have a proper path for clang++
|
||||
clangxx = SCons.Tool.find_program_path(env, compilers[0], default_paths=get_clang_install_dirs(env['PLATFORM']))
|
||||
if clangxx:
|
||||
clangxx_bin_dir = os.path.dirname(clangxx)
|
||||
env.AppendENVPath('PATH', clangxx_bin_dir)
|
||||
|
||||
# Set-up ms tools paths
|
||||
msvc_setup_env_once(env)
|
||||
|
||||
|
||||
# determine compiler version
|
||||
if env['CXX']:
|
||||
pipe = SCons.Action._subproc(env, [env['CXX'], '--version'],
|
||||
stdin='devnull',
|
||||
stderr='devnull',
|
||||
stdout=subprocess.PIPE)
|
||||
if pipe.wait() != 0:
|
||||
return
|
||||
|
||||
# clang -dumpversion is of no use
|
||||
with pipe.stdout:
|
||||
line = pipe.stdout.readline()
|
||||
if sys.version_info[0] > 2:
|
||||
line = line.decode()
|
||||
match = re.search(r'clang +version +([0-9]+(?:\.[0-9]+)+)', line)
|
||||
if match:
|
||||
env['CXXVERSION'] = match.group(1)
|
||||
|
||||
def exists(env):
|
||||
return env.Detect(compilers)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
250
scons/scons-local-4.0.1/SCons/Tool/compilation_db.py
Normal file
250
scons/scons-local-4.0.1/SCons/Tool/compilation_db.py
Normal file
|
@ -0,0 +1,250 @@
|
|||
"""
|
||||
Implements the ability for SCons to emit a compilation database for the MongoDB project. See
|
||||
http://clang.llvm.org/docs/JSONCompilationDatabase.html for details on what a compilation
|
||||
database is, and why you might want one. The only user visible entry point here is
|
||||
'env.CompilationDatabase'. This method takes an optional 'target' to name the file that
|
||||
should hold the compilation database, otherwise, the file defaults to compile_commands.json,
|
||||
which is the name that most clang tools search for by default.
|
||||
"""
|
||||
|
||||
# Copyright 2020 MongoDB Inc.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
import json
|
||||
import itertools
|
||||
import SCons
|
||||
|
||||
from .cxx import CXXSuffixes
|
||||
from .cc import CSuffixes
|
||||
from .asm import ASSuffixes, ASPPSuffixes
|
||||
|
||||
# TODO: Is there a better way to do this than this global? Right now this exists so that the
|
||||
# emitter we add can record all of the things it emits, so that the scanner for the top level
|
||||
# compilation database can access the complete list, and also so that the writer has easy
|
||||
# access to write all of the files. But it seems clunky. How can the emitter and the scanner
|
||||
# communicate more gracefully?
|
||||
__COMPILATION_DB_ENTRIES = []
|
||||
|
||||
|
||||
# We make no effort to avoid rebuilding the entries. Someday, perhaps we could and even
|
||||
# integrate with the cache, but there doesn't seem to be much call for it.
|
||||
class __CompilationDbNode(SCons.Node.Python.Value):
|
||||
def __init__(self, value):
|
||||
SCons.Node.Python.Value.__init__(self, value)
|
||||
self.Decider(changed_since_last_build_node)
|
||||
|
||||
|
||||
def changed_since_last_build_node(child, target, prev_ni, node):
|
||||
""" Dummy decider to force always building"""
|
||||
return True
|
||||
|
||||
|
||||
def make_emit_compilation_DB_entry(comstr):
|
||||
"""
|
||||
Effectively this creates a lambda function to capture:
|
||||
* command line
|
||||
* source
|
||||
* target
|
||||
:param comstr: unevaluated command line
|
||||
:return: an emitter which has captured the above
|
||||
"""
|
||||
user_action = SCons.Action.Action(comstr)
|
||||
|
||||
def emit_compilation_db_entry(target, source, env):
|
||||
"""
|
||||
This emitter will be added to each c/c++ object build to capture the info needed
|
||||
for clang tools
|
||||
:param target: target node(s)
|
||||
:param source: source node(s)
|
||||
:param env: Environment for use building this node
|
||||
:return: target(s), source(s)
|
||||
"""
|
||||
|
||||
dbtarget = __CompilationDbNode(source)
|
||||
|
||||
entry = env.__COMPILATIONDB_Entry(
|
||||
target=dbtarget,
|
||||
source=[],
|
||||
__COMPILATIONDB_UOUTPUT=target,
|
||||
__COMPILATIONDB_USOURCE=source,
|
||||
__COMPILATIONDB_UACTION=user_action,
|
||||
__COMPILATIONDB_ENV=env,
|
||||
)
|
||||
|
||||
# TODO: Technically, these next two lines should not be required: it should be fine to
|
||||
# cache the entries. However, they don't seem to update properly. Since they are quick
|
||||
# to re-generate disable caching and sidestep this problem.
|
||||
env.AlwaysBuild(entry)
|
||||
env.NoCache(entry)
|
||||
|
||||
__COMPILATION_DB_ENTRIES.append(dbtarget)
|
||||
|
||||
return target, source
|
||||
|
||||
return emit_compilation_db_entry
|
||||
|
||||
|
||||
def compilation_db_entry_action(target, source, env, **kw):
|
||||
"""
|
||||
Create a dictionary with evaluated command line, target, source
|
||||
and store that info as an attribute on the target
|
||||
(Which has been stored in __COMPILATION_DB_ENTRIES array
|
||||
:param target: target node(s)
|
||||
:param source: source node(s)
|
||||
:param env: Environment for use building this node
|
||||
:param kw:
|
||||
:return: None
|
||||
"""
|
||||
|
||||
command = env["__COMPILATIONDB_UACTION"].strfunction(
|
||||
target=env["__COMPILATIONDB_UOUTPUT"],
|
||||
source=env["__COMPILATIONDB_USOURCE"],
|
||||
env=env["__COMPILATIONDB_ENV"],
|
||||
)
|
||||
|
||||
entry = {
|
||||
"directory": env.Dir("#").abspath,
|
||||
"command": command,
|
||||
"file": env["__COMPILATIONDB_USOURCE"][0],
|
||||
"output": env['__COMPILATIONDB_UOUTPUT'][0]
|
||||
}
|
||||
|
||||
target[0].write(entry)
|
||||
|
||||
|
||||
def write_compilation_db(target, source, env):
|
||||
entries = []
|
||||
|
||||
use_abspath = env['COMPILATIONDB_USE_ABSPATH'] in [True, 1, 'True', 'true']
|
||||
|
||||
for s in __COMPILATION_DB_ENTRIES:
|
||||
entry = s.read()
|
||||
source_file = entry['file']
|
||||
output_file = entry['output']
|
||||
|
||||
if use_abspath:
|
||||
source_file = source_file.srcnode().abspath
|
||||
output_file = output_file.abspath
|
||||
else:
|
||||
source_file = source_file.srcnode().path
|
||||
output_file = output_file.path
|
||||
|
||||
path_entry = {'directory': entry['directory'],
|
||||
'command': entry['command'],
|
||||
'file': source_file,
|
||||
'output': output_file}
|
||||
|
||||
entries.append(path_entry)
|
||||
|
||||
with open(target[0].path, "w") as output_file:
|
||||
json.dump(
|
||||
entries, output_file, sort_keys=True, indent=4, separators=(",", ": ")
|
||||
)
|
||||
|
||||
|
||||
def scan_compilation_db(node, env, path):
|
||||
return __COMPILATION_DB_ENTRIES
|
||||
|
||||
|
||||
def compilation_db_emitter(target, source, env):
|
||||
""" fix up the source/targets """
|
||||
|
||||
# Someone called env.CompilationDatabase('my_targetname.json')
|
||||
if not target and len(source) == 1:
|
||||
target = source
|
||||
|
||||
# Default target name is compilation_db.json
|
||||
if not target:
|
||||
target = ['compile_commands.json', ]
|
||||
|
||||
# No source should have been passed. Drop it.
|
||||
if source:
|
||||
source = []
|
||||
|
||||
return target, source
|
||||
|
||||
|
||||
def generate(env, **kwargs):
|
||||
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
|
||||
|
||||
env["COMPILATIONDB_COMSTR"] = kwargs.get(
|
||||
"COMPILATIONDB_COMSTR", "Building compilation database $TARGET"
|
||||
)
|
||||
|
||||
components_by_suffix = itertools.chain(
|
||||
itertools.product(
|
||||
CSuffixes,
|
||||
[
|
||||
(static_obj, SCons.Defaults.StaticObjectEmitter, "$CCCOM"),
|
||||
(shared_obj, SCons.Defaults.SharedObjectEmitter, "$SHCCCOM"),
|
||||
],
|
||||
),
|
||||
itertools.product(
|
||||
CXXSuffixes,
|
||||
[
|
||||
(static_obj, SCons.Defaults.StaticObjectEmitter, "$CXXCOM"),
|
||||
(shared_obj, SCons.Defaults.SharedObjectEmitter, "$SHCXXCOM"),
|
||||
],
|
||||
),
|
||||
itertools.product(
|
||||
ASSuffixes,
|
||||
[(static_obj, SCons.Defaults.StaticObjectEmitter, "$ASCOM")],
|
||||
[(shared_obj, SCons.Defaults.SharedObjectEmitter, "$ASCOM")],
|
||||
),
|
||||
itertools.product(
|
||||
ASPPSuffixes,
|
||||
[(static_obj, SCons.Defaults.StaticObjectEmitter, "$ASPPCOM")],
|
||||
[(shared_obj, SCons.Defaults.SharedObjectEmitter, "$ASPPCOM")],
|
||||
),
|
||||
)
|
||||
|
||||
for entry in components_by_suffix:
|
||||
suffix = entry[0]
|
||||
builder, base_emitter, command = entry[1]
|
||||
|
||||
# Assumes a dictionary emitter
|
||||
emitter = builder.emitter.get(suffix, False)
|
||||
if emitter:
|
||||
# We may not have tools installed which initialize all or any of
|
||||
# cxx, cc, or assembly. If not skip resetting the respective emitter.
|
||||
builder.emitter[suffix] = SCons.Builder.ListEmitter(
|
||||
[emitter, make_emit_compilation_DB_entry(command), ]
|
||||
)
|
||||
|
||||
env["BUILDERS"]["__COMPILATIONDB_Entry"] = SCons.Builder.Builder(
|
||||
action=SCons.Action.Action(compilation_db_entry_action, None),
|
||||
)
|
||||
|
||||
env["BUILDERS"]["CompilationDatabase"] = SCons.Builder.Builder(
|
||||
action=SCons.Action.Action(write_compilation_db, "$COMPILATIONDB_COMSTR"),
|
||||
target_scanner=SCons.Scanner.Scanner(
|
||||
function=scan_compilation_db, node_class=None
|
||||
),
|
||||
emitter=compilation_db_emitter,
|
||||
suffix='json',
|
||||
)
|
||||
|
||||
env['COMPILATIONDB_USE_ABSPATH'] = False
|
||||
|
||||
|
||||
def exists(env):
|
||||
return True
|
58
scons/scons-local-4.0.1/SCons/Tool/cvf.py
Normal file
58
scons/scons-local-4.0.1/SCons/Tool/cvf.py
Normal file
|
@ -0,0 +1,58 @@
|
|||
"""SCons.Tool.cvf
|
||||
|
||||
Tool-specific initialization for the Compaq Visual Fortran compiler.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
from . import fortran
|
||||
|
||||
compilers = ['f90']
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for compaq visual fortran to an Environment."""
|
||||
|
||||
fortran.generate(env)
|
||||
|
||||
env['FORTRAN'] = 'f90'
|
||||
env['FORTRANCOM'] = '$FORTRAN $FORTRANFLAGS $_FORTRANMODFLAG $_FORTRANINCFLAGS /compile_only ${SOURCES.windows} /object:${TARGET.windows}'
|
||||
env['FORTRANPPCOM'] = '$FORTRAN $FORTRANFLAGS $CPPFLAGS $_CPPDEFFLAGS $_FORTRANMODFLAG $_FORTRANINCFLAGS /compile_only ${SOURCES.windows} /object:${TARGET.windows}'
|
||||
env['SHFORTRANCOM'] = '$SHFORTRAN $SHFORTRANFLAGS $_FORTRANMODFLAG $_FORTRANINCFLAGS /compile_only ${SOURCES.windows} /object:${TARGET.windows}'
|
||||
env['SHFORTRANPPCOM'] = '$SHFORTRAN $SHFORTRANFLAGS $CPPFLAGS $_CPPDEFFLAGS $_FORTRANMODFLAG $_FORTRANINCFLAGS /compile_only ${SOURCES.windows} /object:${TARGET.windows}'
|
||||
env['OBJSUFFIX'] = '.obj'
|
||||
env['FORTRANMODDIR'] = '${TARGET.dir}'
|
||||
env['FORTRANMODDIRPREFIX'] = '/module:'
|
||||
env['FORTRANMODDIRSUFFIX'] = ''
|
||||
|
||||
def exists(env):
|
||||
return env.Detect(compilers)
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
100
scons/scons-local-4.0.1/SCons/Tool/cxx.py
Normal file
100
scons/scons-local-4.0.1/SCons/Tool/cxx.py
Normal file
|
@ -0,0 +1,100 @@
|
|||
"""SCons.Tool.c++
|
||||
|
||||
Tool-specific initialization for generic Posix C++ compilers.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import os.path
|
||||
|
||||
import SCons.Tool
|
||||
import SCons.Defaults
|
||||
import SCons.Util
|
||||
|
||||
compilers = ['CC', 'c++']
|
||||
|
||||
CXXSuffixes = ['.cpp', '.cc', '.cxx', '.c++', '.C++', '.mm']
|
||||
if SCons.Util.case_sensitive_suffixes('.c', '.C'):
|
||||
CXXSuffixes.append('.C')
|
||||
|
||||
def iscplusplus(source):
|
||||
if not source:
|
||||
# Source might be None for unusual cases like SConf.
|
||||
return 0
|
||||
for s in source:
|
||||
if s.sources:
|
||||
ext = os.path.splitext(str(s.sources[0]))[1]
|
||||
if ext in CXXSuffixes:
|
||||
return 1
|
||||
return 0
|
||||
|
||||
def generate(env):
|
||||
"""
|
||||
Add Builders and construction variables for Visual Age C++ compilers
|
||||
to an Environment.
|
||||
"""
|
||||
import SCons.Tool
|
||||
import SCons.Tool.cc
|
||||
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
|
||||
|
||||
for suffix in CXXSuffixes:
|
||||
static_obj.add_action(suffix, SCons.Defaults.CXXAction)
|
||||
shared_obj.add_action(suffix, SCons.Defaults.ShCXXAction)
|
||||
static_obj.add_emitter(suffix, SCons.Defaults.StaticObjectEmitter)
|
||||
shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter)
|
||||
|
||||
SCons.Tool.cc.add_common_cc_variables(env)
|
||||
|
||||
if 'CXX' not in env:
|
||||
env['CXX'] = env.Detect(compilers) or compilers[0]
|
||||
env['CXXFLAGS'] = SCons.Util.CLVar('')
|
||||
env['CXXCOM'] = '$CXX -o $TARGET -c $CXXFLAGS $CCFLAGS $_CCCOMCOM $SOURCES'
|
||||
env['SHCXX'] = '$CXX'
|
||||
env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS')
|
||||
env['SHCXXCOM'] = '$SHCXX -o $TARGET -c $SHCXXFLAGS $SHCCFLAGS $_CCCOMCOM $SOURCES'
|
||||
|
||||
env['CPPDEFPREFIX'] = '-D'
|
||||
env['CPPDEFSUFFIX'] = ''
|
||||
env['INCPREFIX'] = '-I'
|
||||
env['INCSUFFIX'] = ''
|
||||
env['SHOBJSUFFIX'] = '.os'
|
||||
env['OBJSUFFIX'] = '.o'
|
||||
env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 0
|
||||
|
||||
env['CXXFILESUFFIX'] = '.cc'
|
||||
|
||||
def exists(env):
|
||||
return env.Detect(env.get('CXX', compilers))
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
234
scons/scons-local-4.0.1/SCons/Tool/cyglink.py
Normal file
234
scons/scons-local-4.0.1/SCons/Tool/cyglink.py
Normal file
|
@ -0,0 +1,234 @@
|
|||
"""SCons.Tool.cyglink
|
||||
|
||||
Customization of gnulink for Cygwin (http://www.cygwin.com/)
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
|
||||
"""
|
||||
|
||||
import re
|
||||
import os
|
||||
|
||||
import SCons.Action
|
||||
import SCons.Util
|
||||
import SCons.Tool
|
||||
|
||||
#MAYBE: from . import gnulink
|
||||
from . import gnulink
|
||||
from . import link
|
||||
|
||||
def _lib_generator(target, source, env, for_signature, **kw):
|
||||
try: cmd = kw['cmd']
|
||||
except KeyError: cmd = SCons.Util.CLVar(['$SHLINK'])
|
||||
|
||||
try: vp = kw['varprefix']
|
||||
except KeyError: vp = 'SHLIB'
|
||||
|
||||
dll = env.FindIxes(target, '%sPREFIX' % vp, '%sSUFFIX' % vp)
|
||||
if dll: cmd.extend(['-o', dll])
|
||||
|
||||
cmd.extend(['$SHLINKFLAGS', '$__%sVERSIONFLAGS' % vp, '$__RPATH'])
|
||||
|
||||
implib = env.FindIxes(target, 'IMPLIBPREFIX', 'IMPLIBSUFFIX')
|
||||
if implib:
|
||||
cmd.extend([
|
||||
'-Wl,--out-implib='+implib.get_string(for_signature),
|
||||
'-Wl,--export-all-symbols',
|
||||
'-Wl,--enable-auto-import',
|
||||
'-Wl,--whole-archive', '$SOURCES',
|
||||
'-Wl,--no-whole-archive', '$_LIBDIRFLAGS', '$_LIBFLAGS'
|
||||
])
|
||||
else:
|
||||
cmd.extend(['$SOURCES', '$_LIBDIRFLAGS', '$_LIBFLAGS'])
|
||||
|
||||
return [cmd]
|
||||
|
||||
|
||||
def shlib_generator(target, source, env, for_signature):
|
||||
return _lib_generator(target, source, env, for_signature,
|
||||
varprefix='SHLIB',
|
||||
cmd = SCons.Util.CLVar(['$SHLINK']))
|
||||
|
||||
def ldmod_generator(target, source, env, for_signature):
|
||||
return _lib_generator(target, source, env, for_signature,
|
||||
varprefix='LDMODULE',
|
||||
cmd = SCons.Util.CLVar(['$LDMODULE']))
|
||||
|
||||
def _lib_emitter(target, source, env, **kw):
|
||||
Verbose = False
|
||||
|
||||
if Verbose:
|
||||
print("_lib_emitter: target[0]=%r" % target[0].get_path())
|
||||
|
||||
try: vp = kw['varprefix']
|
||||
except KeyError: vp = 'SHLIB'
|
||||
|
||||
try: libtype = kw['libtype']
|
||||
except KeyError: libtype = 'ShLib'
|
||||
|
||||
dll = env.FindIxes(target, '%sPREFIX' % vp, '%sSUFFIX' % vp)
|
||||
no_import_lib = env.get('no_import_lib', 0)
|
||||
|
||||
if Verbose:
|
||||
print("_lib_emitter: dll=%r" % dll.get_path())
|
||||
|
||||
if not dll or len(target) > 1:
|
||||
raise SCons.Errors.UserError("A shared library should have exactly one target with the suffix: %s" % env.subst("$%sSUFFIX" % vp))
|
||||
|
||||
# Remove any "lib" after the prefix
|
||||
pre = env.subst('$%sPREFIX' % vp)
|
||||
if dll.name[len(pre):len(pre)+3] == 'lib':
|
||||
dll.name = pre + dll.name[len(pre)+3:]
|
||||
|
||||
if Verbose:
|
||||
print("_lib_emitter: dll.name=%r" % dll.name)
|
||||
|
||||
orig_target = target
|
||||
target = [env.fs.File(dll)]
|
||||
target[0].attributes.shared = 1
|
||||
|
||||
if Verbose:
|
||||
print("_lib_emitter: after target=[env.fs.File(dll)]: target[0]=%r" % target[0].get_path())
|
||||
|
||||
# Append an import lib target
|
||||
if not no_import_lib:
|
||||
# Create list of target libraries as strings
|
||||
target_strings = env.ReplaceIxes(orig_target[0],
|
||||
'%sPREFIX' % vp, '%sSUFFIX' % vp,
|
||||
'IMPLIBPREFIX', 'IMPLIBSUFFIX')
|
||||
if Verbose:
|
||||
print("_lib_emitter: target_strings=%r" % target_strings)
|
||||
|
||||
implib_target = env.fs.File(target_strings)
|
||||
if Verbose:
|
||||
print("_lib_emitter: implib_target=%r" % implib_target.get_path())
|
||||
implib_target.attributes.shared = 1
|
||||
target.append(implib_target)
|
||||
|
||||
symlinks = SCons.Tool.ImpLibSymlinkGenerator(env, implib_target,
|
||||
implib_libtype=libtype,
|
||||
generator_libtype=libtype+'ImpLib')
|
||||
if Verbose:
|
||||
print("_lib_emitter: implib symlinks=%r" % SCons.Tool.StringizeLibSymlinks(symlinks))
|
||||
if symlinks:
|
||||
SCons.Tool.EmitLibSymlinks(env, symlinks, implib_target, clean_targets = target[0])
|
||||
implib_target.attributes.shliblinks = symlinks
|
||||
|
||||
return (target, source)
|
||||
|
||||
def shlib_emitter(target, source, env):
|
||||
return _lib_emitter(target, source, env, varprefix='SHLIB', libtype='ShLib')
|
||||
|
||||
def ldmod_emitter(target, source, env):
|
||||
return _lib_emitter(target, source, env, varprefix='LDMODULE', libtype='LdMod')
|
||||
|
||||
def _versioned_lib_suffix(env, suffix, version):
|
||||
"""Generate versioned shared library suffix from a unversioned one.
|
||||
If suffix='.dll', and version='0.1.2', then it returns '-0-1-2.dll'"""
|
||||
Verbose = False
|
||||
if Verbose:
|
||||
print("_versioned_lib_suffix: suffix= ", suffix)
|
||||
print("_versioned_lib_suffix: version= ", version)
|
||||
cygversion = re.sub(r'\.', '-', version)
|
||||
if not suffix.startswith('-' + cygversion):
|
||||
suffix = '-' + cygversion + suffix
|
||||
if Verbose:
|
||||
print("_versioned_lib_suffix: return suffix= ", suffix)
|
||||
return suffix
|
||||
|
||||
def _versioned_implib_name(env, libnode, version, prefix, suffix, **kw):
|
||||
return link._versioned_lib_name(env, libnode, version, prefix, suffix,
|
||||
SCons.Tool.ImpLibPrefixGenerator,
|
||||
SCons.Tool.ImpLibSuffixGenerator,
|
||||
implib_libtype=kw['libtype'])
|
||||
|
||||
def _versioned_implib_symlinks(env, libnode, version, prefix, suffix, **kw):
|
||||
"""Generate link names that should be created for a versioned shared library.
|
||||
Returns a list in the form [ (link, linktarget), ... ]
|
||||
"""
|
||||
Verbose = False
|
||||
|
||||
if Verbose:
|
||||
print("_versioned_implib_symlinks: libnode=%r" % libnode.get_path())
|
||||
print("_versioned_implib_symlinks: version=%r" % version)
|
||||
|
||||
try: libtype = kw['libtype']
|
||||
except KeyError: libtype = 'ShLib'
|
||||
|
||||
|
||||
linkdir = os.path.dirname(libnode.get_path())
|
||||
if Verbose:
|
||||
print("_versioned_implib_symlinks: linkdir=%r" % linkdir)
|
||||
|
||||
name = SCons.Tool.ImpLibNameGenerator(env, libnode,
|
||||
implib_libtype=libtype,
|
||||
generator_libtype=libtype+'ImpLib')
|
||||
if Verbose:
|
||||
print("_versioned_implib_symlinks: name=%r" % name)
|
||||
|
||||
major = version.split('.')[0]
|
||||
|
||||
link0 = env.fs.File(os.path.join(linkdir, name))
|
||||
symlinks = [(link0, libnode)]
|
||||
|
||||
if Verbose:
|
||||
print("_versioned_implib_symlinks: return symlinks=%r" % SCons.Tool.StringizeLibSymlinks(symlinks))
|
||||
|
||||
return symlinks
|
||||
|
||||
shlib_action = SCons.Action.Action(shlib_generator, generator=1)
|
||||
ldmod_action = SCons.Action.Action(ldmod_generator, generator=1)
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for cyglink to an Environment."""
|
||||
gnulink.generate(env)
|
||||
|
||||
env['LINKFLAGS'] = SCons.Util.CLVar('-Wl,-no-undefined')
|
||||
|
||||
env['SHLINKCOM'] = shlib_action
|
||||
env['LDMODULECOM'] = ldmod_action
|
||||
env.Append(SHLIBEMITTER = [shlib_emitter])
|
||||
env.Append(LDMODULEEMITTER = [ldmod_emitter])
|
||||
|
||||
env['SHLIBPREFIX'] = 'cyg'
|
||||
env['SHLIBSUFFIX'] = '.dll'
|
||||
|
||||
env['IMPLIBPREFIX'] = 'lib'
|
||||
env['IMPLIBSUFFIX'] = '.dll.a'
|
||||
|
||||
# Variables used by versioned shared libraries
|
||||
env['_SHLIBVERSIONFLAGS'] = '$SHLIBVERSIONFLAGS'
|
||||
env['_LDMODULEVERSIONFLAGS'] = '$LDMODULEVERSIONFLAGS'
|
||||
|
||||
# SHLIBVERSIONFLAGS and LDMODULEVERSIONFLAGS are same as in gnulink...
|
||||
|
||||
# LINKCALLBACKS are NOT inherited from gnulink
|
||||
env['LINKCALLBACKS'] = {
|
||||
'VersionedShLibSuffix' : _versioned_lib_suffix,
|
||||
'VersionedLdModSuffix' : _versioned_lib_suffix,
|
||||
'VersionedImpLibSuffix' : _versioned_lib_suffix,
|
||||
'VersionedShLibName' : link._versioned_shlib_name,
|
||||
'VersionedLdModName' : link._versioned_ldmod_name,
|
||||
'VersionedShLibImpLibName' : lambda *args: _versioned_implib_name(*args, libtype='ShLib'),
|
||||
'VersionedLdModImpLibName' : lambda *args: _versioned_implib_name(*args, libtype='LdMod'),
|
||||
'VersionedShLibImpLibSymlinks' : lambda *args: _versioned_implib_symlinks(*args, libtype='ShLib'),
|
||||
'VersionedLdModImpLibSymlinks' : lambda *args: _versioned_implib_symlinks(*args, libtype='LdMod'),
|
||||
}
|
||||
|
||||
# these variables were set by gnulink but are not used in cyglink
|
||||
try: del env['_SHLIBSONAME']
|
||||
except KeyError: pass
|
||||
try: del env['_LDMODULESONAME']
|
||||
except KeyError: pass
|
||||
|
||||
def exists(env):
|
||||
return gnulink.exists(env)
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
50
scons/scons-local-4.0.1/SCons/Tool/default.py
Normal file
50
scons/scons-local-4.0.1/SCons/Tool/default.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
"""SCons.Tool.default
|
||||
|
||||
Initialization with a default tool list.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import SCons.Tool
|
||||
|
||||
def generate(env):
|
||||
"""Add default tools."""
|
||||
for t in SCons.Tool.tool_list(env['PLATFORM'], env):
|
||||
SCons.Tool.Tool(t)(env)
|
||||
|
||||
def exists(env):
|
||||
return 1
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
180
scons/scons-local-4.0.1/SCons/Tool/dmd.py
Normal file
180
scons/scons-local-4.0.1/SCons/Tool/dmd.py
Normal file
|
@ -0,0 +1,180 @@
|
|||
"""SCons.Tool.dmd
|
||||
|
||||
Tool-specific initialization for the Digital Mars D compiler.
|
||||
(http://digitalmars.com/d)
|
||||
|
||||
Originally coded by Andy Friesen (andy@ikagames.com)
|
||||
15 November 2003
|
||||
|
||||
Evolved by Russel Winder (russel@winder.org.uk)
|
||||
2010-02-07 onwards
|
||||
|
||||
Compiler variables:
|
||||
|
||||
DC
|
||||
The name of the D compiler to use.
|
||||
Defaults to dmd or gdmd, whichever is found.
|
||||
|
||||
DPATH
|
||||
List of paths to search for import modules.
|
||||
|
||||
DVERSIONS
|
||||
List of version tags to enable when compiling.
|
||||
|
||||
DDEBUG
|
||||
List of debug tags to enable when compiling.
|
||||
|
||||
Linker related variables:
|
||||
|
||||
LIBS
|
||||
List of library files to link in.
|
||||
|
||||
DLINK
|
||||
Name of the linker to use.
|
||||
Defaults to dmd or gdmd, whichever is found.
|
||||
|
||||
DLINKFLAGS
|
||||
List of linker flags.
|
||||
|
||||
Lib tool variables:
|
||||
|
||||
DLIB
|
||||
Name of the lib tool to use. Defaults to lib.
|
||||
|
||||
DLIBFLAGS
|
||||
List of flags to pass to the lib tool.
|
||||
|
||||
LIBS
|
||||
Same as for the linker. (libraries to pull into the .lib)
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
import SCons.Action
|
||||
import SCons.Builder
|
||||
import SCons.Defaults
|
||||
import SCons.Scanner.D
|
||||
import SCons.Tool
|
||||
|
||||
import SCons.Tool.DCommon as DCommon
|
||||
|
||||
|
||||
def generate(env):
|
||||
static_obj, shared_obj = SCons.Tool.createObjBuilders(env)
|
||||
|
||||
static_obj.add_action('.d', SCons.Defaults.DAction)
|
||||
shared_obj.add_action('.d', SCons.Defaults.ShDAction)
|
||||
static_obj.add_emitter('.d', SCons.Defaults.StaticObjectEmitter)
|
||||
shared_obj.add_emitter('.d', SCons.Defaults.SharedObjectEmitter)
|
||||
|
||||
env['DC'] = env.Detect(['dmd', 'ldmd2', 'gdmd']) or 'dmd'
|
||||
env['DCOM'] = '$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -c -of$TARGET $SOURCES'
|
||||
env['_DINCFLAGS'] = '${_concat(DINCPREFIX, DPATH, DINCSUFFIX, __env__, RDirs, TARGET, SOURCE)}'
|
||||
env['_DVERFLAGS'] = '${_concat(DVERPREFIX, DVERSIONS, DVERSUFFIX, __env__)}'
|
||||
env['_DDEBUGFLAGS'] = '${_concat(DDEBUGPREFIX, DDEBUG, DDEBUGSUFFIX, __env__)}'
|
||||
env['_DFLAGS'] = '${_concat(DFLAGPREFIX, DFLAGS, DFLAGSUFFIX, __env__)}'
|
||||
|
||||
env['SHDC'] = '$DC'
|
||||
env['SHDCOM'] = '$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -c -fPIC -of$TARGET $SOURCES'
|
||||
|
||||
env['DPATH'] = ['#/']
|
||||
env['DFLAGS'] = []
|
||||
env['DVERSIONS'] = []
|
||||
env['DDEBUG'] = []
|
||||
|
||||
if env['DC']:
|
||||
DCommon.addDPATHToEnv(env, env['DC'])
|
||||
|
||||
env['DINCPREFIX'] = '-I'
|
||||
env['DINCSUFFIX'] = ''
|
||||
env['DVERPREFIX'] = '-version='
|
||||
env['DVERSUFFIX'] = ''
|
||||
env['DDEBUGPREFIX'] = '-debug='
|
||||
env['DDEBUGSUFFIX'] = ''
|
||||
env['DFLAGPREFIX'] = '-'
|
||||
env['DFLAGSUFFIX'] = ''
|
||||
env['DFILESUFFIX'] = '.d'
|
||||
|
||||
env['DLINK'] = '$DC'
|
||||
env['DLINKFLAGS'] = SCons.Util.CLVar('')
|
||||
env['DLINKCOM'] = '$DLINK -of$TARGET $DLINKFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS'
|
||||
|
||||
env['SHDLINK'] = '$DC'
|
||||
env['SHDLINKFLAGS'] = SCons.Util.CLVar('$DLINKFLAGS -shared -defaultlib=libphobos2.so')
|
||||
env['SHDLINKCOM'] = '$DLINK -of$TARGET $SHDLINKFLAGS $__SHDLIBVERSIONFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS'
|
||||
|
||||
env['DLIBLINKPREFIX'] = '' if env['PLATFORM'] == 'win32' else '-L-l'
|
||||
env['DLIBLINKSUFFIX'] = '.lib' if env['PLATFORM'] == 'win32' else ''
|
||||
env['_DLIBFLAGS'] = '${_stripixes(DLIBLINKPREFIX, LIBS, DLIBLINKSUFFIX, LIBPREFIXES, LIBSUFFIXES, __env__)}'
|
||||
|
||||
env['DLIBDIRPREFIX'] = '-L-L'
|
||||
env['DLIBDIRSUFFIX'] = ''
|
||||
env['_DLIBDIRFLAGS'] = '${_concat(DLIBDIRPREFIX, LIBPATH, DLIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)}'
|
||||
|
||||
env['DLIB'] = 'lib' if env['PLATFORM'] == 'win32' else 'ar cr'
|
||||
env['DLIBCOM'] = '$DLIB $_DLIBFLAGS {0}$TARGET $SOURCES $_DLIBFLAGS'.format('-c ' if env['PLATFORM'] == 'win32' else '')
|
||||
|
||||
# env['_DLIBFLAGS'] = '${_concat(DLIBFLAGPREFIX, DLIBFLAGS, DLIBFLAGSUFFIX, __env__)}'
|
||||
|
||||
env['DLIBFLAGPREFIX'] = '-'
|
||||
env['DLIBFLAGSUFFIX'] = ''
|
||||
|
||||
# __RPATH is set to $_RPATH in the platform specification if that
|
||||
# platform supports it.
|
||||
env['DRPATHPREFIX'] = '-L-rpath,' if env['PLATFORM'] == 'darwin' else '-L-rpath='
|
||||
env['DRPATHSUFFIX'] = ''
|
||||
env['_DRPATH'] = '${_concat(DRPATHPREFIX, RPATH, DRPATHSUFFIX, __env__)}'
|
||||
|
||||
# Support for versioned libraries
|
||||
env['_SHDLIBVERSIONFLAGS'] = '$SHDLIBVERSIONFLAGS -L-soname=$_SHDLIBSONAME'
|
||||
env['_SHDLIBSONAME'] = '${DShLibSonameGenerator(__env__,TARGET)}'
|
||||
# NOTE: this is a quick hack, the soname will only work if there is
|
||||
# c/c++ linker loaded which provides callback for the ShLibSonameGenerator
|
||||
env['DShLibSonameGenerator'] = SCons.Tool.ShLibSonameGenerator
|
||||
# NOTE: this is only for further reference, currently $SHDLIBVERSION does
|
||||
# not work, the user must use $SHLIBVERSION
|
||||
env['SHDLIBVERSION'] = '$SHLIBVERSION'
|
||||
env['SHDLIBVERSIONFLAGS'] = []
|
||||
|
||||
env['BUILDERS']['ProgramAllAtOnce'] = SCons.Builder.Builder(
|
||||
action='$DC $_DINCFLAGS $_DVERFLAGS $_DDEBUGFLAGS $_DFLAGS -of$TARGET $DLINKFLAGS $__DRPATH $SOURCES $_DLIBDIRFLAGS $_DLIBFLAGS',
|
||||
emitter=DCommon.allAtOnceEmitter,
|
||||
)
|
||||
|
||||
|
||||
def exists(env):
|
||||
return env.Detect(['dmd', 'ldmd2', 'gdmd'])
|
||||
|
||||
|
||||
# Local Variables:
|
||||
# tab-width:4
|
||||
# indent-tabs-mode:nil
|
||||
# End:
|
||||
# vim: set expandtab tabstop=4 shiftwidth=4:
|
830
scons/scons-local-4.0.1/SCons/Tool/docbook/__init__.py
Normal file
830
scons/scons-local-4.0.1/SCons/Tool/docbook/__init__.py
Normal file
|
@ -0,0 +1,830 @@
|
|||
|
||||
"""SCons.Tool.docbook
|
||||
|
||||
Tool-specific initialization for Docbook.
|
||||
|
||||
There normally shouldn't be any need to import this module directly.
|
||||
It will usually be imported through the generic SCons.Tool.Tool()
|
||||
selection method.
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
# __COPYRIGHT__
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
import os
|
||||
import glob
|
||||
import re
|
||||
|
||||
import SCons.Action
|
||||
import SCons.Builder
|
||||
import SCons.Defaults
|
||||
import SCons.Script
|
||||
import SCons.Tool
|
||||
import SCons.Util
|
||||
|
||||
|
||||
__debug_tool_location = False
|
||||
# Get full path to this script
|
||||
scriptpath = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
# Local folder for the collection of DocBook XSLs
|
||||
db_xsl_folder = 'docbook-xsl-1.76.1'
|
||||
|
||||
# Do we have lxml?
|
||||
has_lxml = True
|
||||
try:
|
||||
import lxml
|
||||
except Exception:
|
||||
has_lxml = False
|
||||
|
||||
# Set this to True, to prefer xsltproc over lxml
|
||||
prefer_xsltproc = False
|
||||
|
||||
# Regexs for parsing Docbook XML sources of MAN pages
|
||||
re_manvolnum = re.compile("<manvolnum>([^<]*)</manvolnum>")
|
||||
re_refname = re.compile("<refname>([^<]*)</refname>")
|
||||
|
||||
#
|
||||
# Helper functions
|
||||
#
|
||||
def __extend_targets_sources(target, source):
|
||||
""" Prepare the lists of target and source files. """
|
||||
if not SCons.Util.is_List(target):
|
||||
target = [target]
|
||||
if not source:
|
||||
source = target[:]
|
||||
elif not SCons.Util.is_List(source):
|
||||
source = [source]
|
||||
if len(target) < len(source):
|
||||
target.extend(source[len(target):])
|
||||
|
||||
return target, source
|
||||
|
||||
def __init_xsl_stylesheet(kw, env, user_xsl_var, default_path):
|
||||
if kw.get('DOCBOOK_XSL','') == '':
|
||||
xsl_style = kw.get('xsl', env.subst(user_xsl_var))
|
||||
if xsl_style == '':
|
||||
path_args = [scriptpath, db_xsl_folder] + default_path
|
||||
xsl_style = os.path.join(*path_args)
|
||||
kw['DOCBOOK_XSL'] = xsl_style
|
||||
|
||||
def __select_builder(lxml_builder, cmdline_builder):
|
||||
""" Selects a builder, based on which Python modules are present. """
|
||||
if has_lxml and not prefer_xsltproc:
|
||||
return lxml_builder
|
||||
|
||||
return cmdline_builder
|
||||
|
||||
def __ensure_suffix(t, suffix):
|
||||
""" Ensure that the target t has the given suffix. """
|
||||
tpath = str(t)
|
||||
if not tpath.endswith(suffix):
|
||||
return tpath+suffix
|
||||
|
||||
return t
|
||||
|
||||
def __ensure_suffix_stem(t, suffix):
|
||||
""" Ensure that the target t has the given suffix, and return the file's stem. """
|
||||
tpath = str(t)
|
||||
if not tpath.endswith(suffix):
|
||||
stem = tpath
|
||||
tpath += suffix
|
||||
|
||||
return tpath, stem
|
||||
else:
|
||||
stem, ext = os.path.splitext(tpath)
|
||||
|
||||
return t, stem
|
||||
|
||||
def __get_xml_text(root):
|
||||
""" Return the text for the given root node (xml.dom.minidom). """
|
||||
txt = ""
|
||||
for e in root.childNodes:
|
||||
if e.nodeType == e.TEXT_NODE:
|
||||
txt += e.data
|
||||
return txt
|
||||
|
||||
def __create_output_dir(base_dir):
|
||||
""" Ensure that the output directory base_dir exists. """
|
||||
root, tail = os.path.split(base_dir)
|
||||
dir = None
|
||||
if tail:
|
||||
if base_dir.endswith('/'):
|
||||
dir = base_dir
|
||||
else:
|
||||
dir = root
|
||||
else:
|
||||
if base_dir.endswith('/'):
|
||||
dir = base_dir
|
||||
|
||||
if dir and not os.path.isdir(dir):
|
||||
os.makedirs(dir)
|
||||
|
||||
|
||||
#
|
||||
# Supported command line tools and their call "signature"
|
||||
#
|
||||
xsltproc_com_priority = ['xsltproc', 'saxon', 'saxon-xslt', 'xalan']
|
||||
|
||||
# TODO: Set minimum version of saxon-xslt to be 8.x (lower than this only supports xslt 1.0.
|
||||
# see: http://saxon.sourceforge.net/saxon6.5.5/
|
||||
# see: http://saxon.sourceforge.net/
|
||||
xsltproc_com = {'xsltproc' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE',
|
||||
'saxon' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE $DOCBOOK_XSLTPROCPARAMS',
|
||||
# Note if saxon-xslt is version 5.5 the proper arguments are: (swap order of docbook_xsl and source)
|
||||
# 'saxon-xslt' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $SOURCE $DOCBOOK_XSL $DOCBOOK_XSLTPROCPARAMS',
|
||||
'saxon-xslt' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -o $TARGET $DOCBOOK_XSL $SOURCE $DOCBOOK_XSLTPROCPARAMS',
|
||||
'xalan' : '$DOCBOOK_XSLTPROC $DOCBOOK_XSLTPROCFLAGS -q -out $TARGET -xsl $DOCBOOK_XSL -in $SOURCE'}
|
||||
xmllint_com = {'xmllint' : '$DOCBOOK_XMLLINT $DOCBOOK_XMLLINTFLAGS --xinclude $SOURCE > $TARGET'}
|
||||
fop_com = {'fop' : '$DOCBOOK_FOP $DOCBOOK_FOPFLAGS -fo $SOURCE -pdf $TARGET',
|
||||
'xep' : '$DOCBOOK_FOP $DOCBOOK_FOPFLAGS -valid -fo $SOURCE -pdf $TARGET',
|
||||
'jw' : '$DOCBOOK_FOP $DOCBOOK_FOPFLAGS -f docbook -b pdf $SOURCE -o $TARGET'}
|
||||
|
||||
def __detect_cl_tool(env, chainkey, cdict, cpriority=None):
|
||||
"""
|
||||
Helper function, picks a command line tool from the list
|
||||
and initializes its environment variables.
|
||||
"""
|
||||
if env.get(chainkey,'') == '':
|
||||
clpath = ''
|
||||
|
||||
if cpriority is None:
|
||||
cpriority = cdict.keys()
|
||||
for cltool in cpriority:
|
||||
if __debug_tool_location:
|
||||
print("DocBook: Looking for %s"%cltool)
|
||||
clpath = env.WhereIs(cltool)
|
||||
if clpath:
|
||||
if __debug_tool_location:
|
||||
print("DocBook: Found:%s"%cltool)
|
||||
env[chainkey] = clpath
|
||||
if not env[chainkey + 'COM']:
|
||||
env[chainkey + 'COM'] = cdict[cltool]
|
||||
break
|
||||
|
||||
def _detect(env):
|
||||
"""
|
||||
Detect all the command line tools that we might need for creating
|
||||
the requested output formats.
|
||||
"""
|
||||
global prefer_xsltproc
|
||||
|
||||
if env.get('DOCBOOK_PREFER_XSLTPROC',''):
|
||||
prefer_xsltproc = True
|
||||
|
||||
if (not has_lxml) or prefer_xsltproc:
|
||||
# Try to find the XSLT processors
|
||||
__detect_cl_tool(env, 'DOCBOOK_XSLTPROC', xsltproc_com, xsltproc_com_priority)
|
||||
__detect_cl_tool(env, 'DOCBOOK_XMLLINT', xmllint_com)
|
||||
|
||||
__detect_cl_tool(env, 'DOCBOOK_FOP', fop_com, ['fop','xep','jw'])
|
||||
|
||||
#
|
||||
# Scanners
|
||||
#
|
||||
include_re = re.compile('fileref\\s*=\\s*["|\']([^\\n]*)["|\']')
|
||||
sentity_re = re.compile('<!ENTITY\\s+%*\\s*[^\\s]+\\s+SYSTEM\\s+["|\']([^\\n]*)["|\']>')
|
||||
|
||||
def __xml_scan(node, env, path, arg):
|
||||
""" Simple XML file scanner, detecting local images and XIncludes as implicit dependencies. """
|
||||
# Does the node exist yet?
|
||||
if not os.path.isfile(str(node)):
|
||||
return []
|
||||
|
||||
if env.get('DOCBOOK_SCANENT',''):
|
||||
# Use simple pattern matching for system entities..., no support
|
||||
# for recursion yet.
|
||||
contents = node.get_text_contents()
|
||||
return sentity_re.findall(contents)
|
||||
|
||||
xsl_file = os.path.join(scriptpath,'utils','xmldepend.xsl')
|
||||
if not has_lxml or prefer_xsltproc:
|
||||
# Try to call xsltproc
|
||||
xsltproc = env.subst("$DOCBOOK_XSLTPROC")
|
||||
if xsltproc and xsltproc.endswith('xsltproc'):
|
||||
result = env.backtick(' '.join([xsltproc, xsl_file, str(node)]))
|
||||
depfiles = [x.strip() for x in str(result).splitlines() if x.strip() != "" and not x.startswith("<?xml ")]
|
||||
return depfiles
|
||||
else:
|
||||
# Use simple pattern matching, there is currently no support
|
||||
# for xi:includes...
|
||||
contents = node.get_text_contents()
|
||||
return include_re.findall(contents)
|
||||
|
||||
from lxml import etree
|
||||
|
||||
xsl_tree = etree.parse(xsl_file)
|
||||
doc = etree.parse(str(node))
|
||||
result = doc.xslt(xsl_tree)
|
||||
|
||||
depfiles = [x.strip() for x in str(result).splitlines() if x.strip() != "" and not x.startswith("<?xml ")]
|
||||
return depfiles
|
||||
|
||||
# Creating the instance of our XML dependency scanner
|
||||
docbook_xml_scanner = SCons.Script.Scanner(function = __xml_scan,
|
||||
argument = None)
|
||||
|
||||
|
||||
#
|
||||
# Action generators
|
||||
#
|
||||
def __generate_xsltproc_action(source, target, env, for_signature):
|
||||
cmd = env['DOCBOOK_XSLTPROCCOM']
|
||||
# Does the environment have a base_dir defined?
|
||||
base_dir = env.subst('$base_dir')
|
||||
if base_dir:
|
||||
# Yes, so replace target path by its filename
|
||||
return cmd.replace('$TARGET', os.path.join(base_dir, '${TARGET.file}'))
|
||||
return cmd
|
||||
|
||||
def __generate_xsltproc_nobase_action(source, target, env, for_signature):
|
||||
cmd = env['DOCBOOK_XSLTPROCCOM']
|
||||
# Does the environment have a base_dir defined?
|
||||
base_dir = env.subst('$base_dir')
|
||||
if base_dir:
|
||||
# Yes, so replace target path by its filename
|
||||
return cmd.replace('$TARGET', '${TARGET.file}')
|
||||
return cmd
|
||||
|
||||
|
||||
#
|
||||
# Emitters
|
||||
#
|
||||
def __emit_xsl_basedir(target, source, env):
|
||||
# Does the environment have a base_dir defined?
|
||||
base_dir = env.subst('$base_dir')
|
||||
if base_dir:
|
||||
# Yes, so prepend it to each target
|
||||
return [os.path.join(base_dir, str(t)) for t in target], source
|
||||
|
||||
# No, so simply pass target and source names through
|
||||
return target, source
|
||||
|
||||
|
||||
#
|
||||
# Builders
|
||||
#
|
||||
def __build_lxml(target, source, env):
|
||||
"""
|
||||
General XSLT builder (HTML/FO), using the lxml module.
|
||||
"""
|
||||
from lxml import etree
|
||||
|
||||
xslt_ac = etree.XSLTAccessControl(read_file=True,
|
||||
write_file=True,
|
||||
create_dir=True,
|
||||
read_network=False,
|
||||
write_network=False)
|
||||
xsl_style = env.subst('$DOCBOOK_XSL')
|
||||
xsl_tree = etree.parse(xsl_style)
|
||||
transform = etree.XSLT(xsl_tree, access_control=xslt_ac)
|
||||
doc = etree.parse(str(source[0]))
|
||||
# Support for additional parameters
|
||||
parampass = {}
|
||||
if parampass:
|
||||
result = transform(doc, **parampass)
|
||||
else:
|
||||
result = transform(doc)
|
||||
|
||||
try:
|
||||
with open(str(target[0]), "wb") as of:
|
||||
of.write(etree.tostring(result, encoding="utf-8", pretty_print=True))
|
||||
except Exception as e:
|
||||
print("ERROR: Failed to write {}".format(str(target[0])))
|
||||
print(e)
|
||||
|
||||
return None
|
||||
|
||||
def __build_lxml_noresult(target, source, env):
|
||||
"""
|
||||
Specialized XSLT builder for transformations without a direct result where the Docbook
|
||||
stylesheet itself creates the target file, using the lxml module.
|
||||
"""
|
||||
from lxml import etree
|
||||
|
||||
xslt_ac = etree.XSLTAccessControl(read_file=True,
|
||||
write_file=True,
|
||||
create_dir=True,
|
||||
read_network=False,
|
||||
write_network=False)
|
||||
xsl_style = env.subst('$DOCBOOK_XSL')
|
||||
xsl_tree = etree.parse(xsl_style)
|
||||
transform = etree.XSLT(xsl_tree, access_control=xslt_ac)
|
||||
doc = etree.parse(str(source[0]))
|
||||
# Support for additional parameters
|
||||
parampass = {}
|
||||
if parampass:
|
||||
result = transform(doc, **parampass)
|
||||
else:
|
||||
result = transform(doc)
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def __xinclude_lxml(target, source, env):
|
||||
"""
|
||||
Resolving XIncludes, using the lxml module.
|
||||
"""
|
||||
from lxml import etree
|
||||
|
||||
doc = etree.parse(str(source[0]))
|
||||
doc.xinclude()
|
||||
try:
|
||||
doc.write(str(target[0]), xml_declaration=True,
|
||||
encoding="UTF-8", pretty_print=True)
|
||||
except Exception as e:
|
||||
print("ERROR: Failed to write {}".format(str(target[0])))
|
||||
print(e)
|
||||
|
||||
return None
|
||||
|
||||
__lxml_builder = SCons.Builder.Builder(
|
||||
action = __build_lxml,
|
||||
src_suffix = '.xml',
|
||||
source_scanner = docbook_xml_scanner,
|
||||
emitter = __emit_xsl_basedir)
|
||||
|
||||
__lxml_noresult_builder = SCons.Builder.Builder(
|
||||
action = __build_lxml_noresult,
|
||||
src_suffix = '.xml',
|
||||
source_scanner = docbook_xml_scanner,
|
||||
emitter = __emit_xsl_basedir)
|
||||
|
||||
__xinclude_lxml_builder = SCons.Builder.Builder(
|
||||
action = __xinclude_lxml,
|
||||
suffix = '.xml',
|
||||
src_suffix = '.xml',
|
||||
source_scanner = docbook_xml_scanner)
|
||||
|
||||
__xsltproc_builder = SCons.Builder.Builder(
|
||||
action = SCons.Action.CommandGeneratorAction(__generate_xsltproc_action,
|
||||
{'cmdstr' : '$DOCBOOK_XSLTPROCCOMSTR'}),
|
||||
src_suffix = '.xml',
|
||||
source_scanner = docbook_xml_scanner,
|
||||
emitter = __emit_xsl_basedir)
|
||||
__xsltproc_nobase_builder = SCons.Builder.Builder(
|
||||
action = SCons.Action.CommandGeneratorAction(__generate_xsltproc_nobase_action,
|
||||
{'cmdstr' : '$DOCBOOK_XSLTPROCCOMSTR'}),
|
||||
src_suffix = '.xml',
|
||||
source_scanner = docbook_xml_scanner,
|
||||
emitter = __emit_xsl_basedir)
|
||||
__xmllint_builder = SCons.Builder.Builder(
|
||||
action = SCons.Action.Action('$DOCBOOK_XMLLINTCOM','$DOCBOOK_XMLLINTCOMSTR'),
|
||||
suffix = '.xml',
|
||||
src_suffix = '.xml',
|
||||
source_scanner = docbook_xml_scanner)
|
||||
__fop_builder = SCons.Builder.Builder(
|
||||
action = SCons.Action.Action('$DOCBOOK_FOPCOM','$DOCBOOK_FOPCOMSTR'),
|
||||
suffix = '.pdf',
|
||||
src_suffix = '.fo',
|
||||
ensure_suffix=1)
|
||||
|
||||
def DocbookEpub(env, target, source=None, *args, **kw):
|
||||
"""
|
||||
A pseudo-Builder, providing a Docbook toolchain for ePub output.
|
||||
"""
|
||||
import zipfile
|
||||
import shutil
|
||||
|
||||
def build_open_container(target, source, env):
|
||||
"""Generate the *.epub file from intermediate outputs
|
||||
|
||||
Constructs the epub file according to the Open Container Format. This
|
||||
function could be replaced by a call to the SCons Zip builder if support
|
||||
was added for different compression formats for separate source nodes.
|
||||
"""
|
||||
with zipfile.ZipFile(str(target[0]), 'w') as zf:
|
||||
with open('mimetype', 'w') as mime_file:
|
||||
mime_file.write('application/epub+zip')
|
||||
zf.write(mime_file.name, compress_type = zipfile.ZIP_STORED)
|
||||
for s in source:
|
||||
if os.path.isfile(str(s)):
|
||||
head, tail = os.path.split(str(s))
|
||||
if not head:
|
||||
continue
|
||||
s = head
|
||||
for dirpath, dirnames, filenames in os.walk(str(s)):
|
||||
for fname in filenames:
|
||||
path = os.path.join(dirpath, fname)
|
||||
if os.path.isfile(path):
|
||||
zf.write(path, os.path.relpath(path, str(env.get('ZIPROOT', ''))),
|
||||
zipfile.ZIP_DEFLATED)
|
||||
|
||||
def add_resources(target, source, env):
|
||||
"""Add missing resources to the OEBPS directory
|
||||
|
||||
Ensure all the resources in the manifest are present in the OEBPS directory.
|
||||
"""
|
||||
hrefs = []
|
||||
content_file = os.path.join(source[0].get_abspath(), 'content.opf')
|
||||
if not os.path.isfile(content_file):
|
||||
return
|
||||
|
||||
hrefs = []
|
||||
if has_lxml:
|
||||
from lxml import etree
|
||||
|
||||
opf = etree.parse(content_file)
|
||||
# All the opf:item elements are resources
|
||||
for item in opf.xpath('//opf:item',
|
||||
namespaces= { 'opf': 'http://www.idpf.org/2007/opf' }):
|
||||
hrefs.append(item.attrib['href'])
|
||||
|
||||
for href in hrefs:
|
||||
# If the resource was not already created by DocBook XSL itself,
|
||||
# copy it into the OEBPS folder
|
||||
referenced_file = os.path.join(source[0].get_abspath(), href)
|
||||
if not os.path.exists(referenced_file):
|
||||
shutil.copy(href, os.path.join(source[0].get_abspath(), href))
|
||||
|
||||
# Init list of targets/sources
|
||||
target, source = __extend_targets_sources(target, source)
|
||||
|
||||
# Init XSL stylesheet
|
||||
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_EPUB', ['epub','docbook.xsl'])
|
||||
|
||||
# Setup builder
|
||||
__builder = __select_builder(__lxml_noresult_builder, __xsltproc_nobase_builder)
|
||||
|
||||
# Create targets
|
||||
result = []
|
||||
if not env.GetOption('clean'):
|
||||
# Ensure that the folders OEBPS and META-INF exist
|
||||
__create_output_dir('OEBPS/')
|
||||
__create_output_dir('META-INF/')
|
||||
dirs = env.Dir(['OEBPS', 'META-INF'])
|
||||
|
||||
# Set the fixed base_dir
|
||||
kw['base_dir'] = 'OEBPS/'
|
||||
tocncx = __builder.__call__(env, 'toc.ncx', source[0], **kw)
|
||||
cxml = env.File('META-INF/container.xml')
|
||||
env.SideEffect(cxml, tocncx)
|
||||
|
||||
env.Depends(tocncx, kw['DOCBOOK_XSL'])
|
||||
result.extend(tocncx+[cxml])
|
||||
|
||||
container = env.Command(__ensure_suffix(str(target[0]), '.epub'),
|
||||
tocncx+[cxml], [add_resources, build_open_container])
|
||||
mimetype = env.File('mimetype')
|
||||
env.SideEffect(mimetype, container)
|
||||
|
||||
result.extend(container)
|
||||
# Add supporting files for cleanup
|
||||
env.Clean(tocncx, dirs)
|
||||
|
||||
return result
|
||||
|
||||
def DocbookHtml(env, target, source=None, *args, **kw):
|
||||
"""
|
||||
A pseudo-Builder, providing a Docbook toolchain for HTML output.
|
||||
"""
|
||||
# Init list of targets/sources
|
||||
target, source = __extend_targets_sources(target, source)
|
||||
|
||||
# Init XSL stylesheet
|
||||
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_HTML', ['html','docbook.xsl'])
|
||||
|
||||
# Setup builder
|
||||
__builder = __select_builder(__lxml_builder, __xsltproc_builder)
|
||||
|
||||
# Create targets
|
||||
result = []
|
||||
for t,s in zip(target,source):
|
||||
r = __builder.__call__(env, __ensure_suffix(t,'.html'), s, **kw)
|
||||
env.Depends(r, kw['DOCBOOK_XSL'])
|
||||
result.extend(r)
|
||||
|
||||
return result
|
||||
|
||||
def DocbookHtmlChunked(env, target, source=None, *args, **kw):
|
||||
"""
|
||||
A pseudo-Builder, providing a Docbook toolchain for chunked HTML output.
|
||||
"""
|
||||
# Init target/source
|
||||
if not SCons.Util.is_List(target):
|
||||
target = [target]
|
||||
if not source:
|
||||
source = target
|
||||
target = ['index.html']
|
||||
elif not SCons.Util.is_List(source):
|
||||
source = [source]
|
||||
|
||||
# Init XSL stylesheet
|
||||
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_HTMLCHUNKED', ['html','chunkfast.xsl'])
|
||||
|
||||
# Setup builder
|
||||
__builder = __select_builder(__lxml_noresult_builder, __xsltproc_nobase_builder)
|
||||
|
||||
# Detect base dir
|
||||
base_dir = kw.get('base_dir', '')
|
||||
if base_dir:
|
||||
__create_output_dir(base_dir)
|
||||
|
||||
# Create targets
|
||||
result = []
|
||||
r = __builder.__call__(env, __ensure_suffix(str(target[0]), '.html'), source[0], **kw)
|
||||
env.Depends(r, kw['DOCBOOK_XSL'])
|
||||
result.extend(r)
|
||||
# Add supporting files for cleanup
|
||||
env.Clean(r, glob.glob(os.path.join(base_dir, '*.html')))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def DocbookHtmlhelp(env, target, source=None, *args, **kw):
|
||||
"""
|
||||
A pseudo-Builder, providing a Docbook toolchain for HTMLHELP output.
|
||||
"""
|
||||
# Init target/source
|
||||
if not SCons.Util.is_List(target):
|
||||
target = [target]
|
||||
if not source:
|
||||
source = target
|
||||
target = ['index.html']
|
||||
elif not SCons.Util.is_List(source):
|
||||
source = [source]
|
||||
|
||||
# Init XSL stylesheet
|
||||
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_HTMLHELP', ['htmlhelp','htmlhelp.xsl'])
|
||||
|
||||
# Setup builder
|
||||
__builder = __select_builder(__lxml_noresult_builder, __xsltproc_nobase_builder)
|
||||
|
||||
# Detect base dir
|
||||
base_dir = kw.get('base_dir', '')
|
||||
if base_dir:
|
||||
__create_output_dir(base_dir)
|
||||
|
||||
# Create targets
|
||||
result = []
|
||||
r = __builder.__call__(env, __ensure_suffix(str(target[0]), '.html'), source[0], **kw)
|
||||
env.Depends(r, kw['DOCBOOK_XSL'])
|
||||
result.extend(r)
|
||||
# Add supporting files for cleanup
|
||||
env.Clean(r, ['toc.hhc', 'htmlhelp.hhp', 'index.hhk'] +
|
||||
glob.glob(os.path.join(base_dir, '[ar|bk|ch]*.html')))
|
||||
|
||||
return result
|
||||
|
||||
def DocbookPdf(env, target, source=None, *args, **kw):
|
||||
"""
|
||||
A pseudo-Builder, providing a Docbook toolchain for PDF output.
|
||||
"""
|
||||
# Init list of targets/sources
|
||||
target, source = __extend_targets_sources(target, source)
|
||||
|
||||
# Init XSL stylesheet
|
||||
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_PDF', ['fo','docbook.xsl'])
|
||||
|
||||
# Setup builder
|
||||
__builder = __select_builder(__lxml_builder, __xsltproc_builder)
|
||||
|
||||
# Create targets
|
||||
result = []
|
||||
for t,s in zip(target,source):
|
||||
t, stem = __ensure_suffix_stem(t, '.pdf')
|
||||
xsl = __builder.__call__(env, stem+'.fo', s, **kw)
|
||||
result.extend(xsl)
|
||||
env.Depends(xsl, kw['DOCBOOK_XSL'])
|
||||
result.extend(__fop_builder.__call__(env, t, xsl, **kw))
|
||||
|
||||
return result
|
||||
|
||||
def DocbookMan(env, target, source=None, *args, **kw):
|
||||
"""
|
||||
A pseudo-Builder, providing a Docbook toolchain for Man page output.
|
||||
"""
|
||||
# Init list of targets/sources
|
||||
target, source = __extend_targets_sources(target, source)
|
||||
|
||||
# Init XSL stylesheet
|
||||
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_MAN', ['manpages','docbook.xsl'])
|
||||
|
||||
# Setup builder
|
||||
__builder = __select_builder(__lxml_noresult_builder, __xsltproc_builder)
|
||||
|
||||
# Create targets
|
||||
result = []
|
||||
for t,s in zip(target,source):
|
||||
volnum = "1"
|
||||
outfiles = []
|
||||
srcfile = __ensure_suffix(str(s),'.xml')
|
||||
if os.path.isfile(srcfile):
|
||||
try:
|
||||
import xml.dom.minidom
|
||||
|
||||
dom = xml.dom.minidom.parse(__ensure_suffix(str(s),'.xml'))
|
||||
# Extract volume number, default is 1
|
||||
for node in dom.getElementsByTagName('refmeta'):
|
||||
for vol in node.getElementsByTagName('manvolnum'):
|
||||
volnum = __get_xml_text(vol)
|
||||
|
||||
# Extract output filenames
|
||||
for node in dom.getElementsByTagName('refnamediv'):
|
||||
for ref in node.getElementsByTagName('refname'):
|
||||
outfiles.append(__get_xml_text(ref)+'.'+volnum)
|
||||
|
||||
except Exception:
|
||||
# Use simple regex parsing
|
||||
with open(__ensure_suffix(str(s),'.xml'), 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
for m in re_manvolnum.finditer(content):
|
||||
volnum = m.group(1)
|
||||
|
||||
for m in re_refname.finditer(content):
|
||||
outfiles.append(m.group(1)+'.'+volnum)
|
||||
|
||||
if not outfiles:
|
||||
# Use stem of the source file
|
||||
spath = str(s)
|
||||
if not spath.endswith('.xml'):
|
||||
outfiles.append(spath+'.'+volnum)
|
||||
else:
|
||||
stem, ext = os.path.splitext(spath)
|
||||
outfiles.append(stem+'.'+volnum)
|
||||
else:
|
||||
# We have to completely rely on the given target name
|
||||
outfiles.append(t)
|
||||
|
||||
__builder.__call__(env, outfiles[0], s, **kw)
|
||||
env.Depends(outfiles[0], kw['DOCBOOK_XSL'])
|
||||
result.append(outfiles[0])
|
||||
if len(outfiles) > 1:
|
||||
env.Clean(outfiles[0], outfiles[1:])
|
||||
|
||||
|
||||
return result
|
||||
|
||||
def DocbookSlidesPdf(env, target, source=None, *args, **kw):
|
||||
"""
|
||||
A pseudo-Builder, providing a Docbook toolchain for PDF slides output.
|
||||
"""
|
||||
# Init list of targets/sources
|
||||
target, source = __extend_targets_sources(target, source)
|
||||
|
||||
# Init XSL stylesheet
|
||||
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_SLIDESPDF', ['slides','fo','plain.xsl'])
|
||||
|
||||
# Setup builder
|
||||
__builder = __select_builder(__lxml_builder, __xsltproc_builder)
|
||||
|
||||
# Create targets
|
||||
result = []
|
||||
for t,s in zip(target,source):
|
||||
t, stem = __ensure_suffix_stem(t, '.pdf')
|
||||
xsl = __builder.__call__(env, stem+'.fo', s, **kw)
|
||||
env.Depends(xsl, kw['DOCBOOK_XSL'])
|
||||
result.extend(xsl)
|
||||
result.extend(__fop_builder.__call__(env, t, xsl, **kw))
|
||||
|
||||
return result
|
||||
|
||||
def DocbookSlidesHtml(env, target, source=None, *args, **kw):
|
||||
"""
|
||||
A pseudo-Builder, providing a Docbook toolchain for HTML slides output.
|
||||
"""
|
||||
# Init list of targets/sources
|
||||
if not SCons.Util.is_List(target):
|
||||
target = [target]
|
||||
if not source:
|
||||
source = target
|
||||
target = ['index.html']
|
||||
elif not SCons.Util.is_List(source):
|
||||
source = [source]
|
||||
|
||||
# Init XSL stylesheet
|
||||
__init_xsl_stylesheet(kw, env, '$DOCBOOK_DEFAULT_XSL_SLIDESHTML', ['slides','xhtml','plain.xsl'])
|
||||
|
||||
# Setup builder
|
||||
__builder = __select_builder(__lxml_builder, __xsltproc_builder)
|
||||
|
||||
# Detect base dir
|
||||
base_dir = kw.get('base_dir', '')
|
||||
if base_dir:
|
||||
__create_output_dir(base_dir)
|
||||
|
||||
# Create targets
|
||||
result = []
|
||||
r = __builder.__call__(env, __ensure_suffix(str(target[0]), '.html'), source[0], **kw)
|
||||
env.Depends(r, kw['DOCBOOK_XSL'])
|
||||
result.extend(r)
|
||||
# Add supporting files for cleanup
|
||||
env.Clean(r, [os.path.join(base_dir, 'toc.html')] +
|
||||
glob.glob(os.path.join(base_dir, 'foil*.html')))
|
||||
|
||||
return result
|
||||
|
||||
def DocbookXInclude(env, target, source, *args, **kw):
|
||||
"""
|
||||
A pseudo-Builder, for resolving XIncludes in a separate processing step.
|
||||
"""
|
||||
# Init list of targets/sources
|
||||
target, source = __extend_targets_sources(target, source)
|
||||
|
||||
# Setup builder
|
||||
__builder = __select_builder(__xinclude_lxml_builder,__xmllint_builder)
|
||||
|
||||
# Create targets
|
||||
result = []
|
||||
for t,s in zip(target,source):
|
||||
result.extend(__builder.__call__(env, t, s, **kw))
|
||||
|
||||
return result
|
||||
|
||||
def DocbookXslt(env, target, source=None, *args, **kw):
|
||||
"""
|
||||
A pseudo-Builder, applying a simple XSL transformation to the input file.
|
||||
"""
|
||||
# Init list of targets/sources
|
||||
target, source = __extend_targets_sources(target, source)
|
||||
|
||||
# Init XSL stylesheet
|
||||
kw['DOCBOOK_XSL'] = kw.get('xsl', 'transform.xsl')
|
||||
|
||||
# Setup builder
|
||||
__builder = __select_builder(__lxml_builder, __xsltproc_builder)
|
||||
|
||||
# Create targets
|
||||
result = []
|
||||
for t,s in zip(target,source):
|
||||
r = __builder.__call__(env, t, s, **kw)
|
||||
env.Depends(r, kw['DOCBOOK_XSL'])
|
||||
result.extend(r)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def generate(env):
|
||||
"""Add Builders and construction variables for docbook to an Environment."""
|
||||
|
||||
env.SetDefault(
|
||||
# Default names for customized XSL stylesheets
|
||||
DOCBOOK_DEFAULT_XSL_EPUB = '',
|
||||
DOCBOOK_DEFAULT_XSL_HTML = '',
|
||||
DOCBOOK_DEFAULT_XSL_HTMLCHUNKED = '',
|
||||
DOCBOOK_DEFAULT_XSL_HTMLHELP = '',
|
||||
DOCBOOK_DEFAULT_XSL_PDF = '',
|
||||
DOCBOOK_DEFAULT_XSL_MAN = '',
|
||||
DOCBOOK_DEFAULT_XSL_SLIDESPDF = '',
|
||||
DOCBOOK_DEFAULT_XSL_SLIDESHTML = '',
|
||||
|
||||
# Paths to the detected executables
|
||||
DOCBOOK_XSLTPROC = '',
|
||||
DOCBOOK_XMLLINT = '',
|
||||
DOCBOOK_FOP = '',
|
||||
|
||||
# Additional flags for the text processors
|
||||
DOCBOOK_XSLTPROCFLAGS = SCons.Util.CLVar(''),
|
||||
DOCBOOK_XMLLINTFLAGS = SCons.Util.CLVar(''),
|
||||
DOCBOOK_FOPFLAGS = SCons.Util.CLVar(''),
|
||||
DOCBOOK_XSLTPROCPARAMS = SCons.Util.CLVar(''),
|
||||
|
||||
# Default command lines for the detected executables
|
||||
DOCBOOK_XSLTPROCCOM = xsltproc_com['xsltproc'],
|
||||
DOCBOOK_XMLLINTCOM = xmllint_com['xmllint'],
|
||||
DOCBOOK_FOPCOM = fop_com['fop'],
|
||||
|
||||
# Screen output for the text processors
|
||||
DOCBOOK_XSLTPROCCOMSTR = None,
|
||||
DOCBOOK_XMLLINTCOMSTR = None,
|
||||
DOCBOOK_FOPCOMSTR = None,
|
||||
|
||||
)
|
||||
_detect(env)
|
||||
|
||||
env.AddMethod(DocbookEpub, "DocbookEpub")
|
||||
env.AddMethod(DocbookHtml, "DocbookHtml")
|
||||
env.AddMethod(DocbookHtmlChunked, "DocbookHtmlChunked")
|
||||
env.AddMethod(DocbookHtmlhelp, "DocbookHtmlhelp")
|
||||
env.AddMethod(DocbookPdf, "DocbookPdf")
|
||||
env.AddMethod(DocbookMan, "DocbookMan")
|
||||
env.AddMethod(DocbookSlidesPdf, "DocbookSlidesPdf")
|
||||
env.AddMethod(DocbookSlidesHtml, "DocbookSlidesHtml")
|
||||
env.AddMethod(DocbookXInclude, "DocbookXInclude")
|
||||
env.AddMethod(DocbookXslt, "DocbookXslt")
|
||||
|
||||
|
||||
def exists(env):
|
||||
return 1
|
605
scons/scons-local-4.0.1/SCons/Tool/docbook/__init__.xml
Normal file
605
scons/scons-local-4.0.1/SCons/Tool/docbook/__init__.xml
Normal file
|
@ -0,0 +1,605 @@
|
|||
<?xml version="1.0"?>
|
||||
<!--
|
||||
__COPYRIGHT__
|
||||
|
||||
This file is processed by the bin/SConsDoc.py module.
|
||||
See its __doc__ string for a discussion of the format.
|
||||
-->
|
||||
|
||||
<!DOCTYPE sconsdoc [
|
||||
<!ENTITY % scons SYSTEM '../../../doc/scons.mod'>
|
||||
%scons;
|
||||
<!ENTITY % builders-mod SYSTEM '../../../doc/generated/builders.mod'>
|
||||
%builders-mod;
|
||||
<!ENTITY % functions-mod SYSTEM '../../../doc/generated/functions.mod'>
|
||||
%functions-mod;
|
||||
<!ENTITY % tools-mod SYSTEM '../../../doc/generated/tools.mod'>
|
||||
%tools-mod;
|
||||
<!ENTITY % variables-mod SYSTEM '../../../doc/generated/variables.mod'>
|
||||
%variables-mod;
|
||||
]>
|
||||
|
||||
<sconsdoc xmlns="http://www.scons.org/dbxsd/v1.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.scons.org/dbxsd/v1.0 http://www.scons.org/dbxsd/v1.0/scons.xsd">
|
||||
|
||||
<tool name="docbook">
|
||||
<summary>
|
||||
<para>This tool tries to make working with Docbook in SCons a little easier.
|
||||
It provides several toolchains for creating different output formats,
|
||||
like HTML or PDF. Contained in the package is
|
||||
a distribution of the Docbook XSL stylesheets as of version 1.76.1.
|
||||
As long as you don't specify your own stylesheets for customization,
|
||||
these official versions are picked as default...which should reduce
|
||||
the inevitable setup hassles for you.
|
||||
</para>
|
||||
<para>Implicit dependencies to images and XIncludes are detected automatically
|
||||
if you meet the HTML requirements. The additional
|
||||
stylesheet <filename>utils/xmldepend.xsl</filename> by Paul DuBois is used for this purpose.
|
||||
</para>
|
||||
<para>Note, that there is no support for XML catalog resolving offered! This tool calls
|
||||
the XSLT processors and PDF renderers with the stylesheets you specified, that's it.
|
||||
The rest lies in your hands and you still have to know what you're doing when
|
||||
resolving names via a catalog.
|
||||
</para>
|
||||
<para>For activating the tool "docbook", you have to add its name to the Environment constructor,
|
||||
like this
|
||||
</para>
|
||||
<screen>env = Environment(tools=['docbook'])
|
||||
</screen>
|
||||
<para>On its startup, the Docbook tool tries to find a required <literal>xsltproc</literal> processor, and
|
||||
a PDF renderer, e.g. <literal>fop</literal>. So make sure that these are added to your system's environment
|
||||
<literal>PATH</literal> and can be called directly, without specifying their full path.
|
||||
</para>
|
||||
<para>For the most basic processing of Docbook to HTML, you need to have installed
|
||||
</para>
|
||||
<itemizedlist><listitem><para>the Python <literal>lxml</literal> binding to <literal>libxml2</literal>, or
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem><para>a standalone XSLT processor, currently detected are <literal>xsltproc</literal>, <literal>saxon</literal>, <literal>saxon-xslt</literal>
|
||||
and <literal>xalan</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>Rendering to PDF requires you to have one of the applications
|
||||
<literal>fop</literal> or <literal>xep</literal> installed.
|
||||
</para>
|
||||
|
||||
<para>Creating a HTML or PDF document is very simple and straightforward. Say
|
||||
</para>
|
||||
<screen>env = Environment(tools=['docbook'])
|
||||
env.DocbookHtml('manual.html', 'manual.xml')
|
||||
env.DocbookPdf('manual.pdf', 'manual.xml')
|
||||
</screen>
|
||||
<para>to get both outputs from your XML source <filename>manual.xml</filename>. As a shortcut, you can
|
||||
give the stem of the filenames alone, like this:
|
||||
</para>
|
||||
<screen>env = Environment(tools=['docbook'])
|
||||
env.DocbookHtml('manual')
|
||||
env.DocbookPdf('manual')
|
||||
</screen>
|
||||
<para>and get the same result. Target and source lists are also supported:
|
||||
</para>
|
||||
<screen>env = Environment(tools=['docbook'])
|
||||
env.DocbookHtml(['manual.html','reference.html'], ['manual.xml','reference.xml'])
|
||||
</screen>
|
||||
<para>or even
|
||||
</para>
|
||||
<screen>env = Environment(tools=['docbook'])
|
||||
env.DocbookHtml(['manual','reference'])
|
||||
</screen>
|
||||
<important><para>Whenever you leave out the list of sources, you may not specify a file extension! The
|
||||
Tool uses the given names as file stems, and adds the suffixes for target and source files
|
||||
accordingly.
|
||||
</para>
|
||||
</important>
|
||||
<para>The rules given above are valid for the Builders &b-link-DocbookHtml;,
|
||||
&b-link-DocbookPdf;, &b-link-DocbookEpub;, &b-link-DocbookSlidesPdf; and &b-link-DocbookXInclude;. For the
|
||||
&b-link-DocbookMan; transformation you
|
||||
can specify a target name, but the actual output names are automatically
|
||||
set from the <literal>refname</literal> entries in your XML source.
|
||||
</para>
|
||||
|
||||
<para>The Builders &b-link-DocbookHtmlChunked;, &b-link-DocbookHtmlhelp; and
|
||||
&b-link-DocbookSlidesHtml; are special, in that:
|
||||
</para>
|
||||
<orderedlist><listitem><para>they create a large set of files, where the exact names and their number depend
|
||||
on the content of the source file, and
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem><para>the main target is always named <filename>index.html</filename>, i.e. the output name for the
|
||||
XSL transformation is not picked up by the stylesheets.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
<para>As a result, there is simply no use in specifying a target HTML name.
|
||||
So the basic syntax for these builders is always:
|
||||
</para>
|
||||
<screen>env = Environment(tools=['docbook'])
|
||||
env.DocbookHtmlhelp('manual')
|
||||
</screen>
|
||||
|
||||
<para>If you want to use a specific XSL file, you can set the
|
||||
additional <literal>xsl</literal> parameter to your
|
||||
Builder call as follows:
|
||||
</para>
|
||||
<screen>env.DocbookHtml('other.html', 'manual.xml', xsl='html.xsl')
|
||||
</screen>
|
||||
<para>Since this may get tedious if you always use the same local naming for your customized XSL files,
|
||||
e.g. <filename>html.xsl</filename> for HTML and <filename>pdf.xsl</filename> for PDF output, a set of
|
||||
variables for setting the default XSL name is provided. These are:
|
||||
</para>
|
||||
<screen>DOCBOOK_DEFAULT_XSL_HTML
|
||||
DOCBOOK_DEFAULT_XSL_HTMLCHUNKED
|
||||
DOCBOOK_DEFAULT_XSL_HTMLHELP
|
||||
DOCBOOK_DEFAULT_XSL_PDF
|
||||
DOCBOOK_DEFAULT_XSL_EPUB
|
||||
DOCBOOK_DEFAULT_XSL_MAN
|
||||
DOCBOOK_DEFAULT_XSL_SLIDESPDF
|
||||
DOCBOOK_DEFAULT_XSL_SLIDESHTML
|
||||
</screen>
|
||||
<para>and you can set them when constructing your environment:
|
||||
</para>
|
||||
<screen>env = Environment(tools=['docbook'],
|
||||
DOCBOOK_DEFAULT_XSL_HTML='html.xsl',
|
||||
DOCBOOK_DEFAULT_XSL_PDF='pdf.xsl')
|
||||
env.DocbookHtml('manual') # now uses html.xsl
|
||||
</screen>
|
||||
</summary>
|
||||
<sets>
|
||||
<item>DOCBOOK_DEFAULT_XSL_HTML</item>
|
||||
<item>DOCBOOK_DEFAULT_XSL_HTMLCHUNKED</item>
|
||||
<item>DOCBOOK_DEFAULT_XSL_HTMLHELP</item>
|
||||
<item>DOCBOOK_DEFAULT_XSL_PDF</item>
|
||||
<item>DOCBOOK_DEFAULT_XSL_EPUB</item>
|
||||
<item>DOCBOOK_DEFAULT_XSL_MAN</item>
|
||||
<item>DOCBOOK_DEFAULT_XSL_SLIDESPDF</item>
|
||||
<item>DOCBOOK_DEFAULT_XSL_SLIDESHTML</item>
|
||||
<item>DOCBOOK_XSLTPROC</item>
|
||||
<item>DOCBOOK_XMLLINT</item>
|
||||
<item>DOCBOOK_FOP</item>
|
||||
<item>DOCBOOK_XSLTPROCFLAGS</item>
|
||||
<item>DOCBOOK_XMLLINTFLAGS</item>
|
||||
<item>DOCBOOK_FOPFLAGS</item>
|
||||
<item>DOCBOOK_XSLTPROCPARAMS</item>
|
||||
<item>DOCBOOK_XSLTPROCCOM</item>
|
||||
<item>DOCBOOK_XMLLINTCOM</item>
|
||||
<item>DOCBOOK_FOPCOM</item>
|
||||
</sets>
|
||||
<uses>
|
||||
<item>DOCBOOK_XSLTPROCCOMSTR</item>
|
||||
<item>DOCBOOK_XMLLINTCOMSTR</item>
|
||||
<item>DOCBOOK_FOPCOMSTR</item>
|
||||
</uses>
|
||||
</tool>
|
||||
|
||||
|
||||
<cvar name="DOCBOOK_DEFAULT_XSL_HTML">
|
||||
<summary>
|
||||
<para>
|
||||
The default XSLT file for the &b-link-DocbookHtml; builder within the
|
||||
current environment, if no other XSLT gets specified via keyword.
|
||||
</para>
|
||||
</summary>
|
||||
</cvar>
|
||||
|
||||
|
||||
<cvar name="DOCBOOK_DEFAULT_XSL_HTMLCHUNKED">
|
||||
<summary>
|
||||
<para>
|
||||
The default XSLT file for the &b-link-DocbookHtmlChunked; builder within the
|
||||
current environment, if no other XSLT gets specified via keyword.
|
||||
</para>
|
||||
</summary>
|
||||
</cvar>
|
||||
|
||||
<cvar name="DOCBOOK_DEFAULT_XSL_HTMLHELP">
|
||||
<summary>
|
||||
<para>
|
||||
The default XSLT file for the &b-link-DocbookHtmlhelp; builder within the
|
||||
current environment, if no other XSLT gets specified via keyword.
|
||||
</para>
|
||||
</summary>
|
||||
</cvar>
|
||||
|
||||
<cvar name="DOCBOOK_DEFAULT_XSL_PDF">
|
||||
<summary>
|
||||
<para>
|
||||
The default XSLT file for the &b-link-DocbookPdf; builder within the
|
||||
current environment, if no other XSLT gets specified via keyword.
|
||||
</para>
|
||||
</summary>
|
||||
</cvar>
|
||||
|
||||
<cvar name="DOCBOOK_DEFAULT_XSL_EPUB">
|
||||
<summary>
|
||||
<para>
|
||||
The default XSLT file for the &b-link-DocbookEpub; builder within the
|
||||
current environment, if no other XSLT gets specified via keyword.
|
||||
</para>
|
||||
</summary>
|
||||
</cvar>
|
||||
|
||||
<cvar name="DOCBOOK_DEFAULT_XSL_MAN">
|
||||
<summary>
|
||||
<para>
|
||||
The default XSLT file for the &b-link-DocbookMan; builder within the
|
||||
current environment, if no other XSLT gets specified via keyword.
|
||||
</para>
|
||||
</summary>
|
||||
</cvar>
|
||||
|
||||
<cvar name="DOCBOOK_DEFAULT_XSL_SLIDESPDF">
|
||||
<summary>
|
||||
<para>
|
||||
The default XSLT file for the &b-link-DocbookSlidesPdf; builder within the
|
||||
current environment, if no other XSLT gets specified via keyword.
|
||||
</para>
|
||||
</summary>
|
||||
</cvar>
|
||||
|
||||
<cvar name="DOCBOOK_DEFAULT_XSL_SLIDESHTML">
|
||||
<summary>
|
||||
<para>
|
||||
The default XSLT file for the &b-link-DocbookSlidesHtml; builder within the
|
||||
current environment, if no other XSLT gets specified via keyword.
|
||||
</para>
|
||||
</summary>
|
||||
</cvar>
|
||||
|
||||
<cvar name="DOCBOOK_XSLTPROC">
|
||||
<summary>
|
||||
<para>
|
||||
The path to the external executable <literal>xsltproc</literal>
|
||||
(or <literal>saxon</literal>, <literal>xalan</literal>), if one of them
|
||||
is installed.
|
||||
Note, that this is only used as last fallback for XSL transformations, if
|
||||
no lxml Python binding can be imported in the current system.
|
||||
</para>
|
||||
</summary>
|
||||
</cvar>
|
||||
|
||||
<cvar name="DOCBOOK_XMLLINT">
|
||||
<summary>
|
||||
<para>
|
||||
The path to the external executable <literal>xmllint</literal>, if it's installed.
|
||||
Note, that this is only used as last fallback for resolving
|
||||
XIncludes, if no lxml Python binding can be imported
|
||||
in the current system.
|
||||
</para>
|
||||
</summary>
|
||||
</cvar>
|
||||
|
||||
<cvar name="DOCBOOK_FOP">
|
||||
<summary>
|
||||
<para>
|
||||
The path to the PDF renderer <literal>fop</literal> or <literal>xep</literal>,
|
||||
if one of them is installed (<literal>fop</literal> gets checked first).
|
||||
</para>
|
||||
</summary>
|
||||
</cvar>
|
||||
|
||||
<cvar name="DOCBOOK_XSLTPROCFLAGS">
|
||||
<summary>
|
||||
<para>
|
||||
Additonal command-line flags for the external executable
|
||||
<literal>xsltproc</literal> (or <literal>saxon</literal>,
|
||||
<literal>xalan</literal>).
|
||||
</para>
|
||||
</summary>
|
||||
</cvar>
|
||||
|
||||
<cvar name="DOCBOOK_XMLLINTFLAGS">
|
||||
<summary>
|
||||
<para>
|
||||
Additonal command-line flags for the external executable
|
||||
<literal>xmllint</literal>.
|
||||
</para>
|
||||
</summary>
|
||||
</cvar>
|
||||
|
||||
<cvar name="DOCBOOK_FOPFLAGS">
|
||||
<summary>
|
||||
<para>
|
||||
Additonal command-line flags for the
|
||||
PDF renderer <literal>fop</literal> or <literal>xep</literal>.
|
||||
</para>
|
||||
</summary>
|
||||
</cvar>
|
||||
|
||||
<cvar name="DOCBOOK_XSLTPROCPARAMS">
|
||||
<summary>
|
||||
<para>
|
||||
Additonal parameters that are not intended for the XSLT processor executable, but
|
||||
the XSL processing itself. By default, they get appended at the end of the command line
|
||||
for <literal>saxon</literal> and <literal>saxon-xslt</literal>, respectively.
|
||||
</para>
|
||||
</summary>
|
||||
</cvar>
|
||||
|
||||
<cvar name="DOCBOOK_XSLTPROCCOM">
|
||||
<summary>
|
||||
<para>
|
||||
The full command-line for the external executable
|
||||
<literal>xsltproc</literal> (or <literal>saxon</literal>,
|
||||
<literal>xalan</literal>).
|
||||
</para>
|
||||
</summary>
|
||||
</cvar>
|
||||
|
||||
<cvar name="DOCBOOK_XMLLINTCOM">
|
||||
<summary>
|
||||
<para>
|
||||
The full command-line for the external executable
|
||||
<literal>xmllint</literal>.
|
||||
</para>
|
||||
</summary>
|
||||
</cvar>
|
||||
|
||||
<cvar name="DOCBOOK_FOPCOM">
|
||||
<summary>
|
||||
<para>
|
||||
The full command-line for the
|
||||
PDF renderer <literal>fop</literal> or <literal>xep</literal>.
|
||||
</para>
|
||||
</summary>
|
||||
</cvar>
|
||||
|
||||
<cvar name="DOCBOOK_XSLTPROCCOMSTR">
|
||||
<summary>
|
||||
<para>
|
||||
The string displayed when <literal>xsltproc</literal> is used to transform
|
||||
an XML file via a given XSLT stylesheet.
|
||||
</para>
|
||||
</summary>
|
||||
</cvar>
|
||||
|
||||
<cvar name="DOCBOOK_XMLLINTCOMSTR">
|
||||
<summary>
|
||||
<para>
|
||||
The string displayed when <literal>xmllint</literal> is used to resolve
|
||||
XIncludes for a given XML file.
|
||||
</para>
|
||||
</summary>
|
||||
</cvar>
|
||||
|
||||
<cvar name="DOCBOOK_FOPCOMSTR">
|
||||
<summary>
|
||||
<para>
|
||||
The string displayed when a renderer like <literal>fop</literal> or
|
||||
<literal>xep</literal> is used to create PDF output from an XML file.
|
||||
</para>
|
||||
</summary>
|
||||
</cvar>
|
||||
|
||||
<builder name="DocbookHtml">
|
||||
<summary>
|
||||
<para>
|
||||
A pseudo-Builder, providing a Docbook toolchain for HTML output.
|
||||
</para>
|
||||
<example_commands>env = Environment(tools=['docbook'])
|
||||
env.DocbookHtml('manual.html', 'manual.xml')
|
||||
</example_commands>
|
||||
<para>
|
||||
or simply
|
||||
</para>
|
||||
<example_commands>env = Environment(tools=['docbook'])
|
||||
env.DocbookHtml('manual')
|
||||
</example_commands>
|
||||
</summary>
|
||||
</builder>
|
||||
|
||||
<builder name="DocbookHtmlChunked">
|
||||
<summary>
|
||||
<para>
|
||||
A pseudo-Builder, providing a Docbook toolchain for chunked HTML output.
|
||||
It supports the <literal>base.dir</literal> parameter. The
|
||||
<filename>chunkfast.xsl</filename> file (requires "EXSLT") is used as the
|
||||
default stylesheet. Basic syntax:
|
||||
</para>
|
||||
|
||||
<example_commands>env = Environment(tools=['docbook'])
|
||||
env.DocbookHtmlChunked('manual')
|
||||
</example_commands>
|
||||
<para>
|
||||
where <filename>manual.xml</filename> is the input file.
|
||||
</para>
|
||||
<para>If you use the <literal>root.filename</literal>
|
||||
parameter in your own stylesheets you have to specify the new target name.
|
||||
This ensures that the dependencies get correct, especially for the cleanup via <quote><literal>scons -c</literal></quote>:
|
||||
</para>
|
||||
<screen>env = Environment(tools=['docbook'])
|
||||
env.DocbookHtmlChunked('mymanual.html', 'manual', xsl='htmlchunk.xsl')
|
||||
</screen>
|
||||
<para>Some basic support for the <literal>base.dir</literal> is provided. You
|
||||
can add the <literal>base_dir</literal> keyword to your Builder
|
||||
call, and the given prefix gets prepended to all the created filenames:
|
||||
</para>
|
||||
<screen>env = Environment(tools=['docbook'])
|
||||
env.DocbookHtmlChunked('manual', xsl='htmlchunk.xsl', base_dir='output/')
|
||||
</screen>
|
||||
<para>Make sure that you don't forget the trailing slash for the base folder, else
|
||||
your files get renamed only!
|
||||
</para>
|
||||
</summary>
|
||||
</builder>
|
||||
|
||||
<builder name="DocbookHtmlhelp">
|
||||
<summary>
|
||||
<para>
|
||||
A pseudo-Builder, providing a Docbook toolchain for HTMLHELP output.
|
||||
Its basic syntax is:
|
||||
</para>
|
||||
|
||||
<example_commands>env = Environment(tools=['docbook'])
|
||||
env.DocbookHtmlhelp('manual')
|
||||
</example_commands>
|
||||
<para>
|
||||
where <filename>manual.xml</filename> is the input file.
|
||||
</para>
|
||||
|
||||
<para>If you use the <literal>root.filename</literal>
|
||||
parameter in your own stylesheets you have to specify the new target name.
|
||||
This ensures that the dependencies get correct, especially for the cleanup via <quote><literal>scons -c</literal></quote>:
|
||||
</para>
|
||||
<screen>env = Environment(tools=['docbook'])
|
||||
env.DocbookHtmlhelp('mymanual.html', 'manual', xsl='htmlhelp.xsl')
|
||||
</screen>
|
||||
<para>Some basic support for the <literal>base.dir</literal> parameter
|
||||
is provided. You can add the <literal>base_dir</literal> keyword to
|
||||
your Builder call, and the given prefix gets prepended to all the
|
||||
created filenames:
|
||||
</para>
|
||||
<screen>env = Environment(tools=['docbook'])
|
||||
env.DocbookHtmlhelp('manual', xsl='htmlhelp.xsl', base_dir='output/')
|
||||
</screen>
|
||||
<para>Make sure that you don't forget the trailing slash for the base folder, else
|
||||
your files get renamed only!
|
||||
</para>
|
||||
|
||||
</summary>
|
||||
</builder>
|
||||
|
||||
<builder name="DocbookPdf">
|
||||
<summary>
|
||||
<para>
|
||||
A pseudo-Builder, providing a Docbook toolchain for PDF output.
|
||||
</para>
|
||||
|
||||
<example_commands>env = Environment(tools=['docbook'])
|
||||
env.DocbookPdf('manual.pdf', 'manual.xml')
|
||||
</example_commands>
|
||||
|
||||
<para>
|
||||
or simply
|
||||
</para>
|
||||
|
||||
<example_commands>env = Environment(tools=['docbook'])
|
||||
env.DocbookPdf('manual')
|
||||
</example_commands>
|
||||
|
||||
</summary>
|
||||
</builder>
|
||||
|
||||
<builder name="DocbookEpub">
|
||||
<summary>
|
||||
<para>
|
||||
A pseudo-Builder, providing a Docbook toolchain for EPUB output.
|
||||
</para>
|
||||
|
||||
<example_commands>env = Environment(tools=['docbook'])
|
||||
env.DocbookEpub('manual.epub', 'manual.xml')
|
||||
</example_commands>
|
||||
|
||||
<para>
|
||||
or simply
|
||||
</para>
|
||||
|
||||
<example_commands>env = Environment(tools=['docbook'])
|
||||
env.DocbookEpub('manual')
|
||||
</example_commands>
|
||||
|
||||
</summary>
|
||||
</builder>
|
||||
|
||||
<builder name="DocbookMan">
|
||||
<summary>
|
||||
<para>
|
||||
A pseudo-Builder, providing a Docbook toolchain for Man page output.
|
||||
Its basic syntax is:
|
||||
</para>
|
||||
|
||||
<example_commands>env = Environment(tools=['docbook'])
|
||||
env.DocbookMan('manual')
|
||||
</example_commands>
|
||||
<para>
|
||||
where <filename>manual.xml</filename> is the input file. Note, that
|
||||
you can specify a target name, but the actual output names are automatically
|
||||
set from the <literal>refname</literal> entries in your XML source.
|
||||
</para>
|
||||
</summary>
|
||||
</builder>
|
||||
|
||||
<builder name="DocbookSlidesPdf">
|
||||
<summary>
|
||||
<para>
|
||||
A pseudo-Builder, providing a Docbook toolchain for PDF slides output.
|
||||
</para>
|
||||
|
||||
<example_commands>env = Environment(tools=['docbook'])
|
||||
env.DocbookSlidesPdf('manual.pdf', 'manual.xml')
|
||||
</example_commands>
|
||||
|
||||
<para>
|
||||
or simply
|
||||
</para>
|
||||
|
||||
<example_commands>env = Environment(tools=['docbook'])
|
||||
env.DocbookSlidesPdf('manual')
|
||||
</example_commands>
|
||||
</summary>
|
||||
</builder>
|
||||
|
||||
<builder name="DocbookSlidesHtml">
|
||||
<summary>
|
||||
<para>
|
||||
A pseudo-Builder, providing a Docbook toolchain for HTML slides output.
|
||||
</para>
|
||||
|
||||
<example_commands>env = Environment(tools=['docbook'])
|
||||
env.DocbookSlidesHtml('manual')
|
||||
</example_commands>
|
||||
|
||||
<para>If you use the <literal>titlefoil.html</literal> parameter in
|
||||
your own stylesheets you have to give the new target name. This ensures
|
||||
that the dependencies get correct, especially for the cleanup via
|
||||
<quote><literal>scons -c</literal></quote>:
|
||||
</para>
|
||||
<screen>env = Environment(tools=['docbook'])
|
||||
env.DocbookSlidesHtml('mymanual.html','manual', xsl='slideshtml.xsl')
|
||||
</screen>
|
||||
|
||||
<para>Some basic support for the <literal>base.dir</literal> parameter
|
||||
is provided. You
|
||||
can add the <literal>base_dir</literal> keyword to your Builder
|
||||
call, and the given prefix gets prepended to all the created filenames:
|
||||
</para>
|
||||
<screen>env = Environment(tools=['docbook'])
|
||||
env.DocbookSlidesHtml('manual', xsl='slideshtml.xsl', base_dir='output/')
|
||||
</screen>
|
||||
<para>Make sure that you don't forget the trailing slash for the base folder, else
|
||||
your files get renamed only!
|
||||
</para>
|
||||
|
||||
</summary>
|
||||
</builder>
|
||||
|
||||
<builder name="DocbookXInclude">
|
||||
<summary>
|
||||
<para>
|
||||
A pseudo-Builder, for resolving XIncludes in a separate processing step.
|
||||
</para>
|
||||
|
||||
<example_commands>env = Environment(tools=['docbook'])
|
||||
env.DocbookXInclude('manual_xincluded.xml', 'manual.xml')
|
||||
</example_commands>
|
||||
</summary>
|
||||
</builder>
|
||||
|
||||
<builder name="DocbookXslt">
|
||||
<summary>
|
||||
<para>
|
||||
A pseudo-Builder, applying a given XSL transformation to the input file.
|
||||
</para>
|
||||
|
||||
<example_commands>env = Environment(tools=['docbook'])
|
||||
env.DocbookXslt('manual_transformed.xml', 'manual.xml', xsl='transform.xslt')
|
||||
</example_commands>
|
||||
|
||||
<para>Note, that this builder requires the <literal>xsl</literal> parameter
|
||||
to be set.
|
||||
</para>
|
||||
</summary>
|
||||
</builder>
|
||||
|
||||
</sconsdoc>
|
|
@ -0,0 +1,4 @@
|
|||
The DocBook XSL stylesheets are maintained by Norman Walsh,
|
||||
<ndw@nwalsh.com>, and members of the DocBook Project,
|
||||
<docbook-developers@sf.net>
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
To view a list of all open DocBook Project XSL stylesheet bugs:
|
||||
|
||||
http://docbook.sf.net/tracker/xsl/bugs
|
||||
|
||||
To submit a bug report against the stylesheets:
|
||||
|
||||
http://docbook.sf.net/tracker/submit/bug
|
||||
|
||||
To do a full-text search of all DocBook Project issues:
|
||||
|
||||
http://docbook.sf.net/tracker/search
|
||||
|
||||
Discussion about the DocBook Project XSL stylesheets takes place
|
||||
on the docbook-apps mailing list:
|
||||
|
||||
http://wiki.docbook.org/topic/DocBookAppsMailingList
|
||||
|
||||
Real-time discussion takes place on IRC:
|
||||
|
||||
http://wiki.docbook.org/topic/DocBookIrcChannel
|
||||
irc://irc.freenode.net/docbook
|
|
@ -0,0 +1,47 @@
|
|||
Copyright
|
||||
---------
|
||||
Copyright (C) 1999-2007 Norman Walsh
|
||||
Copyright (C) 2003 Jiří Kosek
|
||||
Copyright (C) 2004-2007 Steve Ball
|
||||
Copyright (C) 2005-2008 The DocBook Project
|
||||
|
||||
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.
|
||||
|
||||
Except as contained in this notice, the names of individuals
|
||||
credited with contribution to this software shall not be used in
|
||||
advertising or otherwise to promote the sale, use or other
|
||||
dealings in this Software without prior written authorization
|
||||
from the individuals in question.
|
||||
|
||||
Any stylesheet derived from this Software that is publically
|
||||
distributed will be identified with a different name and the
|
||||
version strings in any derived Software will be changed so that
|
||||
no possibility of confusion between the derived package and this
|
||||
Software will exist.
|
||||
|
||||
Warranty
|
||||
--------
|
||||
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 NORMAN WALSH OR ANY OTHER
|
||||
CONTRIBUTOR 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.
|
||||
|
||||
Contacting the Author
|
||||
---------------------
|
||||
The DocBook XSL stylesheets are maintained by Norman Walsh,
|
||||
<ndw@nwalsh.com>, and members of the DocBook Project,
|
||||
<docbook-developers@sf.net>
|
|
@ -0,0 +1,88 @@
|
|||
$Id: INSTALL 6145 2006-08-06 13:13:03Z xmldoc $
|
||||
|
||||
INSTALL file for the DocBook XSL stylesheets distribution
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Case #1: Installation using a package management system
|
||||
----------------------------------------------------------------------
|
||||
If you have installed the DocBook XSL distribution using "apt-get",
|
||||
"yum", "urpmi", or some similar package-management front-end,
|
||||
then, as part of the package installation, the stylesheets have
|
||||
already been automatically installed in the appropriate location
|
||||
for your system, and your XML catalog environment has probably
|
||||
been updated to use that location.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Case #2: Installing manually
|
||||
----------------------------------------------------------------------
|
||||
If you have downloaded a docbook-xsl zip, tar.gz, or tar.bz2
|
||||
file, use the following steps to install it.
|
||||
|
||||
1. Move the zip, tar.gz, or tar.bz2 file to the directory where
|
||||
you'd like to install it (not to a temporary directory).
|
||||
|
||||
2. unzip or untar/uncompress the file
|
||||
|
||||
That will create a docbook-xsl-$VERSION directory (where
|
||||
$VERSION is the version number for the release).
|
||||
|
||||
The remaining steps are all OPTIONAL. They are intended to
|
||||
automatically update your user environment with XML Catalog
|
||||
information about the DocBook XSL distribution. You are NOT
|
||||
REQUIRED to complete these remaining steps. However, if you do
|
||||
not, and you want to use XML catalogs with the DocBook XSL
|
||||
stylesheets, you will need to manually update your XML catalog
|
||||
environment
|
||||
|
||||
3. Change to the docbook-xsl-$VERSION directory and execute the
|
||||
install.sh script:
|
||||
|
||||
./install.sh
|
||||
|
||||
That will launch an interactive installer, which will emit a
|
||||
series of prompts for you to respond to.
|
||||
|
||||
To instead run it non-interactively without being prompted
|
||||
for confirmation of the changes it makes, invoke it with the
|
||||
"--batch" switch, like this:
|
||||
|
||||
./install.sh --batch
|
||||
|
||||
After the process is complete, the installer will emit a
|
||||
message with a command you need to run in order to source
|
||||
your environment for use with the stylesheets.
|
||||
|
||||
4. To test that he installation has updated your environment
|
||||
correctly, execute the test.sh script:
|
||||
|
||||
./test.sh
|
||||
|
||||
That will test your XML catalog environment, using both the
|
||||
xmlcatalog application and the Apache XML Commons Resolver.
|
||||
|
||||
NOTE: The test.sh file is not created until the install.sh
|
||||
file is run for the first time.
|
||||
|
||||
5. (UNINSTALLING) If/when you want to uninstall the release,
|
||||
execute the uninstall.sh script.
|
||||
|
||||
./uninstall.sh
|
||||
|
||||
To instead run it non-interactively without being prompted
|
||||
for confirmation of the changes it makes, invoke it with the
|
||||
"--batch" switch, like this:
|
||||
|
||||
./uninstall.sh --batch
|
||||
|
||||
NOTE: The uninstall.sh file is not created until the install.sh
|
||||
file is run for the first time.
|
||||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Note to packagers
|
||||
----------------------------------------------------------------------
|
||||
The install.sh, .CatalogManager.properties.example, and .urilist
|
||||
files should not be packaged. They are useful only to users who
|
||||
are installing the stylesheets manually.
|
||||
|
||||
The catalog.xml file should be packaged.
|
|
@ -0,0 +1,89 @@
|
|||
# $Id: Makefile.tests 8481 2009-07-13 20:18:41Z abdelazer $
|
||||
#
|
||||
# This makefile does a "smoketest" of stylesheets for various
|
||||
# output formats in the DocBook XSL Stylesheets release package.
|
||||
# It doesn't actually check the output -- it's just useful for
|
||||
# confirming whether each XSLT transformation actually executes
|
||||
# successfully without any errors.
|
||||
#
|
||||
# To use it, run "make check" or just "make"
|
||||
|
||||
XSLTPROC=xsltproc
|
||||
XSLTPROC_FLAGS=
|
||||
|
||||
TESTFILE=tests/refentry.007.xml
|
||||
TESTFILE_NS=tests/refentry.007.ns.xml
|
||||
|
||||
NORMAL_STYLES=fo/docbook.xsl html/docbook.xsl xhtml/docbook.xsl
|
||||
NORMAL_PROFILE_STYLES=fo/profile-docbook.xsl html/profile-docbook.xsl xhtml/profile-docbook.xsl
|
||||
CHUNK_STYLES=html/chunk.xsl html/onechunk.xsl xhtml/chunk.xsl xhtml/onechunk.xsl
|
||||
HELP_STYLES=htmlhelp/htmlhelp.xsl javahelp/javahelp.xsl eclipse/eclipse.xsl
|
||||
MULTIFILE_STYLES=$(CHUNK_STYLES) $(HELP_STYLES)
|
||||
CHUNK_PROFILE_STYLES=html/profile-chunk.xsl html/profile-onechunk.xsl xhtml/profile-chunk.xsl xhtml/profile-onechunk.xsl
|
||||
HELP_PROFILE_STYLES=htmlhelp/profile-htmlhelp.xsl eclipse/profile-eclipse.xsl javahelp/profile-javahelp.xsl
|
||||
MULTIFILE_PROFILE_STYLES=$(CHUNK_PROFILE_STYLES) $(HELP_PROFILE_STYLES)
|
||||
|
||||
MAN_STYLE=manpages/docbook.xsl
|
||||
MAN_PROFILE_STYLE=manpages/profile-docbook.xsl
|
||||
|
||||
TWO_PROFILE_STYLE=profiling/profile.xsl
|
||||
|
||||
ROUNDTRIP_STYLES=roundtrip/dbk2ooo.xsl roundtrip/dbk2pages.xsl roundtrip/dbk2wordml.xsl
|
||||
SLIDES_STYLES=slides/html/default.xsl slides/xhtml/default.xsl slides/fo/plain.xsl
|
||||
WEBSITE_STYLES=website/website.xsl
|
||||
WEBSITE_CHUNK_STYLES=website/chunk-website.xsl
|
||||
|
||||
# chunked output gets written to TMP_OUTPUT_DIR
|
||||
TMP_OUTPUT_DIR=/tmp/smoketest-output/
|
||||
# if you don't want TMP_OUTPUT_DIR and its contents deleted, unset
|
||||
# SMOKETEST_CLEAN_TARGET; e.g. "make check SMOKETEST_CLEAN_TARGET=''"
|
||||
SMOKETEST_CLEAN_TARGET=smoketest-clean
|
||||
|
||||
check: smoketest-make-tmp-dir smoketest-normal smoketest-normal-profile smoketest-chunk smoketest-chunk-profile smoketest-man smoketest-man-profile smoketest-two-profile $(SMOKETEST_CLEAN_TARGET)
|
||||
|
||||
smoketest-make-tmp-dir:
|
||||
$(RM) -r $(TMP_OUTPUT_DIR)
|
||||
mkdir '$(TMP_OUTPUT_DIR)'
|
||||
|
||||
smoketest-normal:
|
||||
for stylesheet in $(NORMAL_STYLES); do \
|
||||
echo "$(XSLT) $(TESTFILE) $$stylesheet > /dev/null"; \
|
||||
$(XSLT) $(TESTFILE) $$stylesheet > /dev/null; \
|
||||
echo "$(XSLT) $(TESTFILE_NS) $$stylesheet > /dev/null"; \
|
||||
$(XSLT) $(TESTFILE_NS) $$stylesheet > /dev/null; \
|
||||
done
|
||||
|
||||
smoketest-normal-profile:
|
||||
for stylesheet in $(NORMAL_PROFILE_STYLES); do \
|
||||
echo "$(XSLT) $(TESTFILE) $$stylesheet > /dev/null"; \
|
||||
$(XSLT) $(TESTFILE) $$stylesheet > /dev/null; \
|
||||
echo "$(XSLT) $(TESTFILE_NS) $$stylesheet > /dev/null"; \
|
||||
$(XSLT) $(TESTFILE_NS) $$stylesheet > /dev/null; \
|
||||
done
|
||||
|
||||
smoketest-chunk:
|
||||
for stylesheet in $(MULTIFILE_STYLES) ; do \
|
||||
$(XSLT) $(TESTFILE) $$stylesheet manifest.in.base.dir=1 base.dir=$(TMP_OUTPUT_DIR) ; \
|
||||
$(XSLT) $(TESTFILE_NS) $$stylesheet manifest.in.base.dir=1 base.dir=$(TMP_OUTPUT_DIR) ; \
|
||||
done;
|
||||
|
||||
smoketest-chunk-profile:
|
||||
for stylesheet in $(MULTIFILE_PROFILE_STYLES) ; do \
|
||||
$(XSLT) $(TESTFILE) $$stylesheet manifest.in.base.dir=1 base.dir=$(TMP_OUTPUT_DIR) ; \
|
||||
$(XSLT) $(TESTFILE_NS) $$stylesheet manifest.in.base.dir=1 base.dir=$(TMP_OUTPUT_DIR) ; \
|
||||
done;
|
||||
|
||||
smoketest-man:
|
||||
$(XSLT) $(TESTFILE) $(MAN_STYLE) man.output.in.separate.dir=1 man.output.base.dir=$(TMP_OUTPUT_DIR) ; \
|
||||
$(XSLT) $(TESTFILE_NS) $(MAN_STYLE) man.output.in.separate.dir=1 man.output.base.dir=$(TMP_OUTPUT_DIR) ;
|
||||
|
||||
smoketest-man-profile:
|
||||
$(XSLT) $(TESTFILE) $(MAN_PROFILE_STYLE) man.output.in.separate.dir=1 man.output.base.dir=$(TMP_OUTPUT_DIR) ; \
|
||||
$(XSLT) $(TESTFILE_NS) $(MAN_PROFILE_STYLE) man.output.in.separate.dir=1 man.output.base.dir=$(TMP_OUTPUT_DIR) ;
|
||||
|
||||
smoketest-two-profile:
|
||||
$(XSLT) $(TESTFILE_NS) $(TWO_PROFILE_STYLE) > /dev/null ;
|
||||
|
||||
smoketest-clean:
|
||||
$(RM) -r $(TMP_OUTPUT_DIR)
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
Changes since the 1.76.0 release
|
||||
|
||||
Note: This document lists changes only since the 1.76.0 release. If you instead
|
||||
want a record of the complete list of changes for the codebase over its entire
|
||||
history, you can obtain one by running the following commands:
|
||||
|
||||
svn checkout https://docbook.svn.sourceforge.net/svnroot/docbook/trunk/xsl
|
||||
svn log --xml --verbose xsl > ChangeHistory.xml
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
Table of Contents
|
||||
|
||||
Release Notes: 1.76.1
|
||||
|
||||
Common
|
||||
FO
|
||||
HTML
|
||||
Epub
|
||||
Webhelp
|
||||
Params
|
||||
Extensions
|
||||
|
||||
Release Notes: 1.76.1
|
||||
|
||||
The following is a list of changes that have been made since the 1.76.0
|
||||
release.
|
||||
|
||||
Common
|
||||
|
||||
The following changes have been made to the common code since the 1.76.0
|
||||
release.
|
||||
|
||||
● Mauritz Jeanson: Makefile
|
||||
|
||||
Added eu.xml and gl.xml to SOURCES.
|
||||
|
||||
● Jirka Kosek: l10n.xsl
|
||||
|
||||
Fixed bug when context was lost due to usage of xsl:key
|
||||
|
||||
FO
|
||||
|
||||
The following changes have been made to the fo code since the 1.76.0 release.
|
||||
|
||||
● Robert Stayton: docbook.xsl; xref.xsl; fop1.xsl
|
||||
|
||||
Apply patch to support named destination in fop1.xsl, per Sourceforge
|
||||
bug report #3029845.
|
||||
|
||||
● dleidert: pagesetup.xsl
|
||||
|
||||
Remove the namespace mistakingly added with the last upload.
|
||||
|
||||
HTML
|
||||
|
||||
The following changes have been made to the html code since the 1.76.0 release.
|
||||
|
||||
● Keith Fahlgren: highlight.xsl
|
||||
|
||||
Implementing handling for <b> and <i>: transform to <strong> and <em> for XHTML outputs and do not use in the highliting output (per Mauritz Jeanson)
|
||||
|
||||
Epub
|
||||
|
||||
The following changes have been made to the epub code since the 1.76.0 release.
|
||||
|
||||
● Keith Fahlgren: docbook.xsl
|
||||
|
||||
Bugfix for [#3071521] to ensure that NCX navPoints are generated for d:book root nodes with the -NS version of the stylesheets
|
||||
|
||||
● Keith Fahlgren: docbook.xsl
|
||||
|
||||
Remove unused NCX metadata elements
|
||||
|
||||
● Keith Fahlgren: bin/spec/epub_regressions_spec.rb; docbook.xsl; bin/spec/
|
||||
files/test_cust.x⋯
|
||||
|
||||
Normalizing identifier lookup between NCX and OPF
|
||||
|
||||
● Keith Fahlgren: bin/dbtoepub
|
||||
|
||||
Reduce logging verbosity
|
||||
|
||||
● Keith Fahlgren: bin/dbtoepub; bin/lib/docbook.rb
|
||||
|
||||
Only copy images once for the DocBook to EPUB tool to correct Windows bug reported in [#3065489]
|
||||
|
||||
Webhelp
|
||||
|
||||
The following changes have been made to the webhelp code since the 1.76.0
|
||||
release.
|
||||
|
||||
● David Cramer: indexer
|
||||
|
||||
More webhelp indexer refactoring
|
||||
|
||||
● David Cramer: build.xml
|
||||
|
||||
Removed cruft from before webhelp indexer refactoring
|
||||
|
||||
● David Cramer: indexer/src
|
||||
|
||||
Refactoring webhelp to separate more cleanly the xsl and java code.
|
||||
|
||||
● David Cramer: indexer/lib
|
||||
|
||||
Refactoring webhelp to separate more cleanly the xsl and java code.
|
||||
|
||||
● David Cramer: Makefile; build.xml
|
||||
|
||||
Refactoring webhelp to separate more cleanly the xsl and java code.
|
||||
|
||||
● David Cramer: indexer/src/com/nexwave/nquindexer/IndexerTask.java;
|
||||
build.xml; indexer/src/⋯
|
||||
|
||||
Merged in changes from webhelp branch to address issue #3058244 regarding the xx.html temp file that was being created
|
||||
|
||||
Params
|
||||
|
||||
The following changes have been made to the params code since the 1.76.0
|
||||
release.
|
||||
|
||||
● Robert Stayton: draft.mode.xml
|
||||
|
||||
Change default for draft.mode to 'no'.
|
||||
|
||||
Extensions
|
||||
|
||||
The following changes have been made to the extensions code since the 1.76.0
|
||||
release.
|
||||
|
||||
● David Cramer: Makefile
|
||||
|
||||
More webhelp refactoring
|
||||
|
||||
● David Cramer: Makefile
|
||||
|
||||
Refactoring webhelp to separate more cleanly the xsl and java code.
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<html><head><meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"><title>Changes since the 1.76.0 release</title><meta name="generator" content="DocBook XSL Stylesheets V1.76.1"><meta name="description" content="Note: This document lists changes only since the 1.76.0 release. If you instead want a record of the complete list of changes for the codebase over its entire history, you can obtain one by running the following commands: svn checkout https://docbook.svn.sourceforge.net/svnroot/docbook/trunk/xsl svn log --xml --verbose xsl > ChangeHistory.xml"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="article" title="Changes since the 1.76.0 release"><div class="titlepage"><div><div><h2 class="title"><a name="id36089309"></a>Changes since the 1.76.0 release</h2></div><div><div class="abstract" title="Abstract"><p><span class="strong"><strong>Note:</strong></span> This
|
||||
document lists changes only since the 1.76.0 release.
|
||||
If you instead want a record of the complete list of
|
||||
changes for the codebase over its entire history, you
|
||||
can obtain one by running the following commands:
|
||||
|
||||
</p><pre class="screen"> <code class="code">svn checkout https://docbook.svn.sourceforge.net/svnroot/docbook/trunk/xsl</code>
|
||||
<code class="code">svn log --xml --verbose xsl > ChangeHistory.xml</code></pre></div></div></div><hr></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="sect1"><a href="#V1.76.1">Release Notes: 1.76.1</a></span></dt><dd><dl><dt><span class="sect2"><a href="#V1.76.1_Common">Common</a></span></dt><dt><span class="sect2"><a href="#V1.76.1_FO">FO</a></span></dt><dt><span class="sect2"><a href="#V1.76.1_HTML">HTML</a></span></dt><dt><span class="sect2"><a href="#V1.76.1_Epub">Epub</a></span></dt><dt><span class="sect2"><a href="#V1.76.1_Webhelp">Webhelp</a></span></dt><dt><span class="sect2"><a href="#V1.76.1_Params">Params</a></span></dt><dt><span class="sect2"><a href="#V1.76.1_Extensions">Extensions</a></span></dt></dl></dd></dl></div><div class="sect1" title="Release Notes: 1.76.1"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="V1.76.1"></a>Release Notes: 1.76.1</h2></div></div></div><p>The following is a list of changes that have been made
|
||||
since the 1.76.0 release.</p><div class="sect2" title="Common"><div class="titlepage"><div><div><h3 class="title"><a name="V1.76.1_Common"></a>Common</h3></div></div></div><p>The following changes have been made to the
|
||||
<code class="filename">common</code> code
|
||||
since the 1.76.0 release.</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="literal">Mauritz Jeanson: Makefile</code></p><pre class="screen"><span class="commit-message">Added eu.xml and gl.xml to SOURCES.</span></pre></li><li class="listitem"><p><code class="literal">Jirka Kosek: l10n.xsl</code></p><pre class="screen"><span class="commit-message">Fixed bug when context was lost due to usage of xsl:key</span></pre></li></ul></div></div><div class="sect2" title="FO"><div class="titlepage"><div><div><h3 class="title"><a name="V1.76.1_FO"></a>FO</h3></div></div></div><p>The following changes have been made to the
|
||||
<code class="filename">fo</code> code
|
||||
since the 1.76.0 release.</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="literal">Robert Stayton: docbook.xsl; xref.xsl; fop1.xsl</code></p><pre class="screen"><span class="commit-message">Apply patch to support named destination in fop1.xsl, per Sourceforge
|
||||
bug report #3029845.</span></pre></li><li class="listitem"><p><code class="literal">dleidert: pagesetup.xsl</code></p><pre class="screen"><span class="commit-message">Remove the namespace mistakingly added with the last upload.</span></pre></li></ul></div></div><div class="sect2" title="HTML"><div class="titlepage"><div><div><h3 class="title"><a name="V1.76.1_HTML"></a>HTML</h3></div></div></div><p>The following changes have been made to the
|
||||
<code class="filename">html</code> code
|
||||
since the 1.76.0 release.</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="literal">Keith Fahlgren: highlight.xsl</code></p><pre class="screen"><span class="commit-message">Implementing handling for <b> and <i>: transform to <strong> and <em> for XHTML outputs and do not use in the highliting output (per Mauritz Jeanson)</span></pre></li></ul></div></div><div class="sect2" title="Epub"><div class="titlepage"><div><div><h3 class="title"><a name="V1.76.1_Epub"></a>Epub</h3></div></div></div><p>The following changes have been made to the
|
||||
<code class="filename">epub</code> code
|
||||
since the 1.76.0 release.</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="literal">Keith Fahlgren: docbook.xsl</code></p><pre class="screen"><span class="commit-message">Bugfix for [#3071521] to ensure that NCX navPoints are generated for d:<a href="http://docbook.org/tdg5/en/html/book.html"><code class="sgmltag-element">book</code></a> root nodes with the -NS version of the stylesheets</span></pre></li><li class="listitem"><p><code class="literal">Keith Fahlgren: docbook.xsl</code></p><pre class="screen"><span class="commit-message">Remove unused NCX metadata elements</span></pre></li><li class="listitem"><p><code class="literal">Keith Fahlgren: bin/spec/epub_regressions_spec.rb; docbook.xsl; bin/spec/files/test_cust.x⋯</code></p><pre class="screen"><span class="commit-message">Normalizing identifier lookup between NCX and OPF</span></pre></li><li class="listitem"><p><code class="literal">Keith Fahlgren: bin/dbtoepub</code></p><pre class="screen"><span class="commit-message">Reduce logging verbosity</span></pre></li><li class="listitem"><p><code class="literal">Keith Fahlgren: bin/dbtoepub; bin/lib/docbook.rb</code></p><pre class="screen"><span class="commit-message">Only copy images once for the DocBook to EPUB tool to correct Windows bug reported in [#3065489]</span></pre></li></ul></div></div><div class="sect2" title="Webhelp"><div class="titlepage"><div><div><h3 class="title"><a name="V1.76.1_Webhelp"></a>Webhelp</h3></div></div></div><p>The following changes have been made to the
|
||||
<code class="filename">webhelp</code> code
|
||||
since the 1.76.0 release.</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="literal">David Cramer: indexer</code></p><pre class="screen"><span class="commit-message">More webhelp indexer refactoring</span></pre></li><li class="listitem"><p><code class="literal">David Cramer: build.xml</code></p><pre class="screen"><span class="commit-message">Removed cruft from before webhelp indexer refactoring</span></pre></li><li class="listitem"><p><code class="literal">David Cramer: indexer/src</code></p><pre class="screen"><span class="commit-message">Refactoring webhelp to separate more cleanly the xsl and java code.</span></pre></li><li class="listitem"><p><code class="literal">David Cramer: indexer/lib</code></p><pre class="screen"><span class="commit-message">Refactoring webhelp to separate more cleanly the xsl and java code.</span></pre></li><li class="listitem"><p><code class="literal">David Cramer: Makefile; build.xml</code></p><pre class="screen"><span class="commit-message">Refactoring webhelp to separate more cleanly the xsl and java code.</span></pre></li><li class="listitem"><p><code class="literal">David Cramer: indexer/src/com/nexwave/nquindexer/IndexerTask.java; build.xml; indexer/src/⋯</code></p><pre class="screen"><span class="commit-message">Merged in changes from webhelp branch to <a href="http://docbook.org/tdg5/en/html/address.html"><code class="sgmltag-element">address</code></a> issue #3058244 regarding the xx.html temp file that was being created</span></pre></li></ul></div></div><div class="sect2" title="Params"><div class="titlepage"><div><div><h3 class="title"><a name="V1.76.1_Params"></a>Params</h3></div></div></div><p>The following changes have been made to the
|
||||
<code class="filename">params</code> code
|
||||
since the 1.76.0 release.</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="literal">Robert Stayton: draft.mode.xml</code></p><pre class="screen"><span class="commit-message">Change default for <a href="http://docbook.sourceforge.net/release/xsl/current/doc/html/draft.mode.html"><em class="parameter"><code>draft.mode</code></em></a> to 'no'.</span></pre></li></ul></div></div><div class="sect2" title="Extensions"><div class="titlepage"><div><div><h3 class="title"><a name="V1.76.1_Extensions"></a>Extensions</h3></div></div></div><p>The following changes have been made to the
|
||||
<code class="filename">extensions</code> code
|
||||
since the 1.76.0 release.</p><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p><code class="literal">David Cramer: Makefile</code></p><pre class="screen"><span class="commit-message">More webhelp refactoring</span></pre></li><li class="listitem"><p><code class="literal">David Cramer: Makefile</code></p><pre class="screen"><span class="commit-message">Refactoring webhelp to separate more cleanly the xsl and java code.</span></pre></li></ul></div></div></div></div></body></html>
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
<?xml version="1.0"?>
|
||||
|
||||
<article>
|
||||
<info>
|
||||
<abstract>
|
||||
<para><emphasis role="strong">Note:</emphasis> This
|
||||
document lists changes only since the 1.76.0 release.
|
||||
If you instead want a record of the complete list of
|
||||
changes for the codebase over its entire history, you
|
||||
can obtain one by running the following commands:
|
||||
|
||||
<screen> <code>svn checkout https://docbook.svn.sourceforge.net/svnroot/docbook/trunk/xsl</code>
|
||||
<code>svn log --xml --verbose xsl > ChangeHistory.xml</code></screen></para>
|
||||
</abstract>
|
||||
</info><title>Changes since the 1.76.0 release</title>
|
||||
|
||||
<sect1 xml:id="V1.76.1">
|
||||
<title>Release Notes: 1.76.1</title>
|
||||
<para>The following is a list of changes that have been made
|
||||
since the 1.76.0 release.</para>
|
||||
|
||||
<sect2 xml:id="V1.76.1_Common">
|
||||
<title>Common</title>
|
||||
<para>The following changes have been made to the
|
||||
<filename>common</filename> code
|
||||
since the 1.76.0 release.</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>Mauritz Jeanson: Makefile</literal></para><screen><phrase role="commit-message">Added eu.xml and gl.xml to SOURCES.</phrase></screen>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>Jirka Kosek: l10n.xsl</literal></para><screen><phrase role="commit-message">Fixed bug when context was lost due to usage of xsl:key</phrase></screen>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2><!--end of Common changes for 1.76.1-->
|
||||
|
||||
<sect2 xml:id="V1.76.1_FO">
|
||||
<title>FO</title>
|
||||
<para>The following changes have been made to the
|
||||
<filename>fo</filename> code
|
||||
since the 1.76.0 release.</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>Robert Stayton: docbook.xsl; xref.xsl; fop1.xsl</literal></para><screen><phrase role="commit-message">Apply patch to support named destination in fop1.xsl, per Sourceforge
|
||||
bug report #3029845.</phrase></screen>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>dleidert: pagesetup.xsl</literal></para><screen><phrase role="commit-message">Remove the namespace mistakingly added with the last upload.</phrase></screen>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2><!--end of FO changes for 1.76.1-->
|
||||
|
||||
<sect2 xml:id="V1.76.1_HTML">
|
||||
<title>HTML</title>
|
||||
<para>The following changes have been made to the
|
||||
<filename>html</filename> code
|
||||
since the 1.76.0 release.</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>Keith Fahlgren: highlight.xsl</literal></para><screen><phrase role="commit-message">Implementing handling for <b> and <i>: transform to <strong> and <em> for XHTML outputs and do not use in the highliting output (per Mauritz Jeanson)</phrase></screen>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2><!--end of HTML changes for 1.76.1-->
|
||||
|
||||
<sect2 xml:id="V1.76.1_Epub">
|
||||
<title>Epub</title>
|
||||
<para>The following changes have been made to the
|
||||
<filename>epub</filename> code
|
||||
since the 1.76.0 release.</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>Keith Fahlgren: docbook.xsl</literal></para><screen><phrase role="commit-message">Bugfix for [#3071521] to ensure that NCX navPoints are generated for d:<tag>book</tag> root nodes with the -NS version of the stylesheets</phrase></screen>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>Keith Fahlgren: docbook.xsl</literal></para><screen><phrase role="commit-message">Remove unused NCX metadata elements</phrase></screen>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>Keith Fahlgren: bin/spec/epub_regressions_spec.rb; docbook.xsl; bin/spec/files/test_cust.x⋯</literal></para><screen><phrase role="commit-message">Normalizing identifier lookup between NCX and OPF</phrase></screen>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>Keith Fahlgren: bin/dbtoepub</literal></para><screen><phrase role="commit-message">Reduce logging verbosity</phrase></screen>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>Keith Fahlgren: bin/dbtoepub; bin/lib/docbook.rb</literal></para><screen><phrase role="commit-message">Only copy images once for the DocBook to EPUB tool to correct Windows bug reported in [#3065489]</phrase></screen>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2><!--end of Epub changes for 1.76.1-->
|
||||
|
||||
<sect2 xml:id="V1.76.1_Webhelp">
|
||||
<title>Webhelp</title>
|
||||
<para>The following changes have been made to the
|
||||
<filename>webhelp</filename> code
|
||||
since the 1.76.0 release.</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>David Cramer: indexer</literal></para><screen><phrase role="commit-message">More webhelp indexer refactoring</phrase></screen>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>David Cramer: build.xml</literal></para><screen><phrase role="commit-message">Removed cruft from before webhelp indexer refactoring</phrase></screen>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>David Cramer: indexer/src</literal></para><screen><phrase role="commit-message">Refactoring webhelp to separate more cleanly the xsl and java code.</phrase></screen>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>David Cramer: indexer/lib</literal></para><screen><phrase role="commit-message">Refactoring webhelp to separate more cleanly the xsl and java code.</phrase></screen>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>David Cramer: Makefile; build.xml</literal></para><screen><phrase role="commit-message">Refactoring webhelp to separate more cleanly the xsl and java code.</phrase></screen>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>David Cramer: indexer/src/com/nexwave/nquindexer/IndexerTask.java; build.xml; indexer/src/⋯</literal></para><screen><phrase role="commit-message">Merged in changes from webhelp branch to <tag>address</tag> issue #3058244 regarding the xx.html temp file that was being created</phrase></screen>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2><!--end of Webhelp changes for 1.76.1-->
|
||||
|
||||
<sect2 xml:id="V1.76.1_Params">
|
||||
<title>Params</title>
|
||||
<para>The following changes have been made to the
|
||||
<filename>params</filename> code
|
||||
since the 1.76.0 release.</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>Robert Stayton: draft.mode.xml</literal></para><screen><phrase role="commit-message">Change default for <parameter>draft.mode</parameter> to 'no'.</phrase></screen>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2><!--end of Params changes for 1.76.1-->
|
||||
|
||||
<sect2 xml:id="V1.76.1_Extensions">
|
||||
<title>Extensions</title>
|
||||
<para>The following changes have been made to the
|
||||
<filename>extensions</filename> code
|
||||
since the 1.76.0 release.</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><literal>David Cramer: Makefile</literal></para><screen><phrase role="commit-message">More webhelp refactoring</phrase></screen>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>David Cramer: Makefile</literal></para><screen><phrase role="commit-message">Refactoring webhelp to separate more cleanly the xsl and java code.</phrase></screen>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</sect2><!--end of Extensions changes for 1.76.1-->
|
||||
|
||||
</sect1>
|
||||
</article>
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
----------------------------------------------------------------------
|
||||
README file for the DocBook XSL Stylesheets
|
||||
----------------------------------------------------------------------
|
||||
$Id: README 8484 2009-07-13 20:35:34Z mzjn $
|
||||
|
||||
These are XSL stylesheets for transforming DocBook XML document
|
||||
instances into various output formats.
|
||||
|
||||
This README file provides only very minimal documentation on using
|
||||
the stylesheets. For more complete information, see Bob Stayton's
|
||||
book "DocBook XSL: The Complete Guide", available online at:
|
||||
|
||||
http://www.sagehill.net/docbookxsl/
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Installation
|
||||
----------------------------------------------------------------------
|
||||
See the INSTALL file for information about installing this release.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
How to use the stylesheets
|
||||
----------------------------------------------------------------------
|
||||
The base canonical URI for these stylesheets is:
|
||||
|
||||
http://docbook.sourceforge.net/release/xsl/current/
|
||||
|
||||
You call any of the stylesheets in this distribution by doing one
|
||||
of the following:
|
||||
|
||||
- Use the base canonical URI in combination with one of the
|
||||
pathnames below. For example, for "chunked" HTML, output:
|
||||
|
||||
http://docbook.sourceforge.net/release/xsl/current/html/chunk.xsl
|
||||
|
||||
If your system has a working XML Catalog or SGML Catalog setup
|
||||
(most Linux systems do), then that URI will automatically be
|
||||
resolved and replaced with a local pathname on your system.
|
||||
|
||||
- Use a "real" local system base path in combination with one of
|
||||
the pathnames below. For example, for "chunked" HTML, output:
|
||||
|
||||
/usr/share/xml/docbook/stylesheet/nwalsh/html/chunk.xsl
|
||||
|
||||
To transform documents created with the standard DocBook
|
||||
schema/DTD, use one of the following stylesheets:
|
||||
|
||||
fo/docbook.xsl - for XSL-FO
|
||||
|
||||
html/docbook.xsl - for HTML (as a single file)
|
||||
html/chunk.xsl - for HTML (chunked into multiple files)
|
||||
html/onechunk.xsl - for HTML (chunked output in single file)
|
||||
|
||||
xhtml/*.xsl - for XHTML versions of the above
|
||||
|
||||
xhtml-1_1/*.xsl - for XHTML 1.1 versions of the above
|
||||
|
||||
epub/docbook.xsl - for .epub
|
||||
|
||||
htmlhelp/htmlhelp.xsl - for HTML Help
|
||||
javahelp/javahelp.xsl - for JavaHelp
|
||||
eclipse/eclipse.xsl - for Eclipse Help
|
||||
|
||||
manpages/docbook.xsl - for groff/nroff man pages
|
||||
|
||||
*/profile-* - single-pass-profiling versions of all above
|
||||
|
||||
roundtrip/*.xsl - for DocBook to WordML, etc., to DocBook
|
||||
|
||||
To transform documents created with the DocBook Slides schema/DTD,
|
||||
use one of the following stylesheets:
|
||||
|
||||
slides/html/*.xsl - for HTML slides of various kinds
|
||||
slides/xhtml/*.xsl - for XHTML slides of various kinds
|
||||
slides/fo/plain.xsl - for XSL-FO slides
|
||||
slides/htmlhelp/... - for HTML Help slides
|
||||
|
||||
To transform documents created with the DocBook Website
|
||||
schema/DTD, use one of the following stylesheets:
|
||||
|
||||
website/website.xsl - for non-tabular, non-chunked output
|
||||
website/tabular.xsl - for tabular, non-chunked output
|
||||
website/chunk-* - for chunked output
|
||||
|
||||
To generate a titlepage customization layer from a titlepage spec:
|
||||
|
||||
template/titlepage.xsl
|
||||
|
||||
For details about creating titlepage spec files and generating and
|
||||
using titlepage customization layers, see "DocBook XSL: The
|
||||
Complete Guide" <http://www.sagehill.net/docbookxsl/>
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Manifest
|
||||
----------------------------------------------------------------------
|
||||
AUTHORS contact information
|
||||
BUGS about known problems
|
||||
COPYING copyright information
|
||||
INSTALL installation instructions
|
||||
README this file
|
||||
RELEASE.* per-release cumulative summaries of user-visible changes
|
||||
TODO about planned features not yet implemented
|
||||
VERSION release metadata, including the current version
|
||||
number (note that the VERSION file is an XSL stylesheet)
|
||||
NEWS changes since the last public release (for a cumulative list of
|
||||
changes, see the ChangeHistory.xml file)
|
||||
|
||||
common/ code used among several output formats (HTML, FO, manpages,...)
|
||||
docsrc/ documentation sources
|
||||
eclipse/ for producing Eclipse Help
|
||||
epub/ for producing .epub
|
||||
extensions/ DocBook XSL Java extensions
|
||||
fo/ for producing XSL-FO
|
||||
highlighting files used for adding source-code syntax highlighting in output
|
||||
html/ for producing HTML
|
||||
htmlhelp/ for producing HTML Help
|
||||
images/ images used in callouts and graphical admonitions
|
||||
javahelp/ for producing Java Help
|
||||
lib/ utility stylesheets with schema-independent functions
|
||||
manpages/ for producing groff/troff man pages
|
||||
profiling/ for profiling (omitting/including conditional text)
|
||||
roundtrip/ for "round trip" conversion among DocBook and
|
||||
various word-processor formats (WordML, etc.)
|
||||
slides/ for producing slides output (from Slides source)
|
||||
template/ templates for building stylesheet customization layers
|
||||
tools/ assorted supplementary tools
|
||||
website/ for producing website output (from Website source)
|
||||
xhtml/ for producing XHTML
|
||||
xhtml-1_1/ for producing (stricter) XHTML 1.1
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Changes
|
||||
----------------------------------------------------------------------
|
||||
See the NEWS file for changes made since the previous release.
|
||||
|
||||
See the RELEASE-NOTES.html or RELEASE-NOTES.txt or RELEASE-NOTES.pdf
|
||||
files for per-release cumulative summaries of significant
|
||||
user-visible changes.
|
||||
|
||||
For online access to a hyperlinked view of all changes made over
|
||||
the entire history of the codebase, see the following:
|
||||
|
||||
http://docbook.svn.sourceforge.net/viewvc/docbook/trunk/xsl/?view=log
|
||||
|
||||
WARNING: That above change history is a very long list and may
|
||||
take a long time to load/download.
|
||||
|
||||
You can also create an XML-formatted "ChangeHistory.xml" copy of
|
||||
the complete change history for the codebase by running the
|
||||
following commands:
|
||||
|
||||
svn checkout https://docbook.svn.sf.net/svnroot/docbook/trunk/xsl
|
||||
svn log --xml --verbose xsl > ChangeHistory.xml
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Copyright information
|
||||
----------------------------------------------------------------------
|
||||
See the accompanying file named COPYING.
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue