mirror of https://github.com/lukechilds/node.git
Ryan
16 years ago
178 changed files with 44921 additions and 8 deletions
File diff suppressed because it is too large
@ -0,0 +1,844 @@ |
|||||
|
"""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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Builder.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import UserDict |
||||
|
import UserList |
||||
|
|
||||
|
import SCons.Action |
||||
|
from SCons.Debug import logInstanceCreation |
||||
|
from SCons.Errors import InternalError, UserError |
||||
|
import SCons.Executor |
||||
|
import SCons.Memoize |
||||
|
import SCons.Node |
||||
|
import SCons.Node.FS |
||||
|
import SCons.Util |
||||
|
import SCons.Warnings |
||||
|
|
||||
|
class _Null: |
||||
|
pass |
||||
|
|
||||
|
_null = _Null |
||||
|
|
||||
|
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 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: |
||||
|
ext = None |
||||
|
for src in map(str, source): |
||||
|
my_ext = SCons.Util.splitext(src)[1] |
||||
|
if ext and my_ext != ext: |
||||
|
raise UserError("While building `%s' from `%s': Cannot build multiple sources with different extensions: %s, %s" % (repr(map(str, target)), src, ext, my_ext)) |
||||
|
ext = my_ext |
||||
|
else: |
||||
|
ext = SCons.Util.splitext(str(source[0]))[1] |
||||
|
|
||||
|
if not ext: |
||||
|
raise UserError("While building `%s': Cannot deduce file extension from source files: %s" % (repr(map(str, target)), repr(map(str, source)))) |
||||
|
|
||||
|
try: |
||||
|
ret = SCons.Util.Selector.__call__(self, env, source) |
||||
|
except KeyError, e: |
||||
|
raise UserError("Ambiguous suffixes after environment substitution: %s == %s == %s" % (e[0], e[1], e[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(map(str, target)), repr(map(str, source)), ext, repr(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.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.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.UserDict.__init__(self, dict) |
||||
|
if __debug__: logInstanceCreation(self, 'Builder.OverrideWarner') |
||||
|
self.already_warned = None |
||||
|
def warn(self): |
||||
|
if self.already_warned: |
||||
|
return |
||||
|
for k in self.keys(): |
||||
|
if misleading_keywords.has_key(k): |
||||
|
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 kw.has_key('generator'): |
||||
|
if kw.has_key('action'): |
||||
|
raise UserError, "You must not specify both an action and a generator." |
||||
|
kw['action'] = SCons.Action.CommandGeneratorAction(kw['generator'], {}) |
||||
|
del kw['generator'] |
||||
|
elif kw.has_key('action'): |
||||
|
source_ext_match = kw.get('source_ext_match', 1) |
||||
|
if kw.has_key('source_ext_match'): |
||||
|
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 kw.has_key('emitter'): |
||||
|
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 = apply(BuilderBase, (), kw) |
||||
|
|
||||
|
if not composite is 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(): |
||||
|
if not t.env is None and not t.env is env: |
||||
|
action = t.builder.action |
||||
|
t_contents = action.get_contents(tlist, slist, t.env) |
||||
|
contents = 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: |
||||
|
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 |
||||
|
if t.get_executor().targets != tlist: |
||||
|
msg = "Two different target lists have a target in common: %s (from %s and from %s)" % (t, map(str, t.get_executor().targets), 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, map(str, t.sources), 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" % (map(str,tlist), 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 env.has_key(emitter): |
||||
|
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 __cmp__(self, other): |
||||
|
return cmp(self.var, other.var) |
||||
|
|
||||
|
class BuilderBase: |
||||
|
"""Base class for Builders, objects that create output |
||||
|
nodes (files) from input nodes (files). |
||||
|
""" |
||||
|
|
||||
|
if SCons.Memoize.use_memoizer: |
||||
|
__metaclass__ = SCons.Memoize.Memoized_Metaclass |
||||
|
|
||||
|
memoizer_counters = [] |
||||
|
|
||||
|
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 __debug__: 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.has_key('overrides'): |
||||
|
SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning, |
||||
|
"The \"overrides\" keyword to Builder() creation has been deprecated;\n" +\ |
||||
|
"\tspecify the items as keyword arguments to the Builder() call instead.") |
||||
|
overrides.update(overrides['overrides']) |
||||
|
del overrides['overrides'] |
||||
|
if overrides.has_key('scanner'): |
||||
|
SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning, |
||||
|
"The \"scanner\" keyword to Builder() creation has been deprecated;\n" |
||||
|
"\tuse: source_scanner or target_scanner as appropriate.") |
||||
|
del overrides['scanner'] |
||||
|
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 not chdir is _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 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 = env['BUILDERS'].values().index(self) |
||||
|
return env['BUILDERS'].keys()[index] |
||||
|
except (AttributeError, KeyError, TypeError, ValueError): |
||||
|
try: |
||||
|
return self.name |
||||
|
except AttributeError: |
||||
|
return str(self.__class__) |
||||
|
|
||||
|
def __cmp__(self, other): |
||||
|
return cmp(self.__dict__, other.__dict__) |
||||
|
|
||||
|
def splitext(self, path, env=None): |
||||
|
if not env: |
||||
|
env = self.env |
||||
|
if env: |
||||
|
matchsuf = filter(lambda S,path=path: path[-len(S):] == S, |
||||
|
self.src_suffixes(env)) |
||||
|
if matchsuf: |
||||
|
suf = max(map(None, map(len, matchsuf), matchsuf))[1] |
||||
|
return [path[:-len(suf)], path[-len(suf):]] |
||||
|
return SCons.Util.splitext(path) |
||||
|
|
||||
|
def get_single_executor(self, env, tlist, slist, executor_kw): |
||||
|
if not self.action: |
||||
|
raise UserError, "Builder %s must have an action to build %s."%(self.get_name(env or self.env), map(str,tlist)) |
||||
|
return self.action.get_executor(env or self.env, |
||||
|
[], # env already has overrides |
||||
|
tlist, |
||||
|
slist, |
||||
|
executor_kw) |
||||
|
|
||||
|
def get_multi_executor(self, env, tlist, slist, executor_kw): |
||||
|
try: |
||||
|
executor = tlist[0].get_executor(create = 0) |
||||
|
except (AttributeError, IndexError): |
||||
|
return self.get_single_executor(env, tlist, slist, executor_kw) |
||||
|
else: |
||||
|
executor.add_sources(slist) |
||||
|
return executor |
||||
|
|
||||
|
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=self,env=env: 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 not tgt is None: tgt = [tgt] |
||||
|
if not src is 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) |
||||
|
|
||||
|
# 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. |
||||
|
if self.multi: |
||||
|
get_executor = self.get_multi_executor |
||||
|
else: |
||||
|
get_executor = self.get_single_executor |
||||
|
executor = get_executor(env, tlist, slist, executor_kw) |
||||
|
|
||||
|
# 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 kw: |
||||
|
if kw.has_key('srcdir'): |
||||
|
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 = 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 |
||||
|
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 ] |
||||
|
adjust = lambda suf, s=self: \ |
||||
|
callable(suf) and suf or s.adjust_suffix(suf) |
||||
|
self.src_suffix = map(adjust, 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 = map(lambda l, n=name: n[-l:], 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: |
||||
|
mss = lambda t, m=match_src_suffix: m(t.name) |
||||
|
tlist = filter(mss, tlist) |
||||
|
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) |
||||
|
|
||||
|
memoizer_counters.append(SCons.Memoize.CountDict('get_src_builders', _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) |
||||
|
|
||||
|
memoizer_counters.append(SCons.Memoize.CountDict('subst_src_suffixes', _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 = map(lambda x, s=self, e=env: e.subst(x), 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 not sdict.has_key(s): |
||||
|
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 __debug__: logInstanceCreation(self, 'Builder.CompositeBuilder') |
||||
|
SCons.Util.Proxy.__init__(self, builder) |
||||
|
|
||||
|
# cmdgen should always be an instance of DictCmdGenerator. |
||||
|
self.cmdgen = cmdgen |
||||
|
self.builder = builder |
||||
|
|
||||
|
def add_action(self, suffix, action): |
||||
|
self.cmdgen.add_action(suffix, action) |
||||
|
self.set_src_suffix(self.cmdgen.src_suffixes()) |
@ -0,0 +1,217 @@ |
|||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/CacheDir.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
__doc__ = """ |
||||
|
CacheDir support |
||||
|
""" |
||||
|
|
||||
|
import os.path |
||||
|
import stat |
||||
|
import string |
||||
|
import sys |
||||
|
|
||||
|
import SCons.Action |
||||
|
|
||||
|
cache_enabled = True |
||||
|
cache_debug = False |
||||
|
cache_force = False |
||||
|
cache_show = False |
||||
|
|
||||
|
def CacheRetrieveFunc(target, source, env): |
||||
|
t = target[0] |
||||
|
fs = t.fs |
||||
|
cd = env.get_CacheDir() |
||||
|
cachedir, cachefile = cd.cachepath(t) |
||||
|
if not fs.exists(cachefile): |
||||
|
cd.CacheDebug('CacheRetrieve(%s): %s not in cache\n', t, cachefile) |
||||
|
return 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.path) |
||||
|
else: |
||||
|
env.copy_from_cache(cachefile, t.path) |
||||
|
st = fs.stat(cachefile) |
||||
|
fs.chmod(t.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.path |
||||
|
return None |
||||
|
|
||||
|
CacheRetrieve = SCons.Action.Action(CacheRetrieveFunc, CacheRetrieveString) |
||||
|
|
||||
|
CacheRetrieveSilent = SCons.Action.Action(CacheRetrieveFunc, None) |
||||
|
|
||||
|
def CachePushFunc(target, source, env): |
||||
|
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.EnvironmentError, msg |
||||
|
|
||||
|
try: |
||||
|
if fs.islink(t.path): |
||||
|
fs.symlink(fs.readlink(t.path), tempfile) |
||||
|
else: |
||||
|
fs.copy2(t.path, tempfile) |
||||
|
fs.rename(tempfile, cachefile) |
||||
|
st = fs.stat(t.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): |
||||
|
try: |
||||
|
import hashlib |
||||
|
except ImportError: |
||||
|
msg = "No hashlib or MD5 module available, CacheDir() not supported" |
||||
|
SCons.Warnings.warn(SCons.Warnings.NoMD5ModuleWarning, msg) |
||||
|
self.path = None |
||||
|
else: |
||||
|
self.path = path |
||||
|
self.current_cache_debug = None |
||||
|
self.debugFP = None |
||||
|
|
||||
|
def CacheDebug(self, fmt, target, cachefile): |
||||
|
if cache_debug != self.current_cache_debug: |
||||
|
if cache_debug == '-': |
||||
|
self.debugFP = sys.stdout |
||||
|
elif cache_debug: |
||||
|
self.debugFP = open(cache_debug, 'w') |
||||
|
else: |
||||
|
self.debugFP = None |
||||
|
self.current_cache_debug = cache_debug |
||||
|
if self.debugFP: |
||||
|
self.debugFP.write(fmt % (target, os.path.split(cachefile)[1])) |
||||
|
|
||||
|
def is_enabled(self): |
||||
|
return (cache_enabled and not self.path is None) |
||||
|
|
||||
|
def cachepath(self, node): |
||||
|
""" |
||||
|
""" |
||||
|
if not self.is_enabled(): |
||||
|
return None, None |
||||
|
|
||||
|
sig = node.get_cachedir_bsig() |
||||
|
subdir = string.upper(sig[0]) |
||||
|
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 |
||||
|
|
||||
|
retrieved = False |
||||
|
|
||||
|
if cache_show: |
||||
|
if CacheRetrieveSilent(node, [], node.get_build_env(), execute=1) == 0: |
||||
|
node.build(presub=0, execute=0) |
||||
|
retrieved = 1 |
||||
|
else: |
||||
|
if CacheRetrieve(node, [], node.get_build_env(), execute=1) == 0: |
||||
|
retrieved = 1 |
||||
|
if retrieved: |
||||
|
# Record build signature information, but don't |
||||
|
# push it out to cache. (We just got it from there!) |
||||
|
node.set_state(SCons.Node.executed) |
||||
|
SCons.Node.Node.built(node) |
||||
|
|
||||
|
return retrieved |
||||
|
|
||||
|
def push(self, node): |
||||
|
if 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) |
@ -0,0 +1,778 @@ |
|||||
|
"""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.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 |
||||
|
import string |
||||
|
from types import IntType |
||||
|
|
||||
|
# |
||||
|
# 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() { |
||||
|
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() |
||||
|
{ |
||||
|
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() |
||||
|
{ |
||||
|
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() |
||||
|
{ |
||||
|
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() |
||||
|
{ |
||||
|
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 not context.env.has_key(comp) 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 |
||||
|
|
||||
|
int main() { |
||||
|
#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() { |
||||
|
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 not expect is 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() |
||||
|
{ |
||||
|
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() { |
||||
|
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" % (type_name, msg)) |
||||
|
return msg |
||||
|
|
||||
|
src = includetext + includes |
||||
|
context.Display('Checking whether %s is declared... ' % symbol) |
||||
|
|
||||
|
src = src + r""" |
||||
|
int main() |
||||
|
{ |
||||
|
#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): |
||||
|
""" |
||||
|
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 = string.find(call, "\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) |
||||
|
oldLIBS = context.AppendLIBS(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 |
||||
|
|
||||
|
# |
||||
|
# END OF PUBLIC FUNCTIONS |
||||
|
# |
||||
|
|
||||
|
def _YesNoResult(context, ret, key, text, comment = None): |
||||
|
""" |
||||
|
Handle the result of a test with a "yes" or "no" result. |
||||
|
"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): |
||||
|
""" |
||||
|
Store result of a test in context.havedict and context.headerfilename. |
||||
|
"key" is a "HAVE_abc" name. It is turned into all CAPITALS and non- |
||||
|
alphanumerics are replaced by an underscore. |
||||
|
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". |
||||
|
Give "have" as is should appear in the header file, include quotes |
||||
|
when desired and escape special characters! |
||||
|
""" |
||||
|
key_up = string.upper(key) |
||||
|
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 type(have) == IntType: |
||||
|
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 = string.split(text, '\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: |
@ -0,0 +1,216 @@ |
|||||
|
"""SCons.Debug |
||||
|
|
||||
|
Code for debugging SCons internal things. Not everything here is |
||||
|
guaranteed to work all the way back to Python 1.5.2, and shouldn't be |
||||
|
needed by most users. |
||||
|
|
||||
|
""" |
||||
|
|
||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Debug.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import os |
||||
|
import string |
||||
|
import sys |
||||
|
|
||||
|
# Recipe 14.10 from the Python Cookbook. |
||||
|
try: |
||||
|
import weakref |
||||
|
except ImportError: |
||||
|
def logInstanceCreation(instance, name=None): |
||||
|
pass |
||||
|
else: |
||||
|
def logInstanceCreation(instance, name=None): |
||||
|
if name is None: |
||||
|
name = instance.__class__.__name__ |
||||
|
if not tracked_classes.has_key(name): |
||||
|
tracked_classes[name] = [] |
||||
|
tracked_classes[name].append(weakref.ref(instance)) |
||||
|
|
||||
|
|
||||
|
|
||||
|
tracked_classes = {} |
||||
|
|
||||
|
def string_to_classes(s): |
||||
|
if s == '*': |
||||
|
c = tracked_classes.keys() |
||||
|
c.sort() |
||||
|
return c |
||||
|
else: |
||||
|
return string.split(s) |
||||
|
|
||||
|
def fetchLoggedInstances(classes="*"): |
||||
|
classnames = string_to_classes(classes) |
||||
|
return map(lambda cn: (cn, len(tracked_classes[cn])), 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]: |
||||
|
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(): |
||||
|
mstr = open('/proc/self/stat').read() |
||||
|
mstr = string.split(mstr)[22] |
||||
|
return int(mstr) |
||||
|
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(*backlist): |
||||
|
import traceback |
||||
|
if not backlist: |
||||
|
backlist = [0] |
||||
|
result = [] |
||||
|
for back in backlist: |
||||
|
tb = traceback.extract_stack(limit=3+back) |
||||
|
key = tb[0][:3] |
||||
|
result.append('%s:%d(%s)' % func_shorten(key)) |
||||
|
return result |
||||
|
|
||||
|
caller_bases = {} |
||||
|
caller_dicts = {} |
||||
|
|
||||
|
# trace a caller's stack |
||||
|
def caller_trace(back=0): |
||||
|
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): |
||||
|
l = [] |
||||
|
for c,v in caller_dicts[key].items(): |
||||
|
l.append((-v,c)) |
||||
|
l.sort() |
||||
|
leader = ' '*level |
||||
|
for v,c in l: |
||||
|
file.write("%s %6d %s:%d(%s)\n" % ((leader,-v) + func_shorten(c[-3:]))) |
||||
|
if caller_dicts.has_key(c): |
||||
|
_dump_one_caller(c, file, level+1) |
||||
|
|
||||
|
# print each call tree |
||||
|
def dump_caller_counts(file=sys.stdout): |
||||
|
keys = caller_bases.keys() |
||||
|
keys.sort() |
||||
|
for k in 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 != '/': |
||||
|
def platformize(t): |
||||
|
return (string.replace(t[0], '/', os.sep), t[1]) |
||||
|
shorten_list = map(platformize, shorten_list) |
||||
|
del platformize |
||||
|
|
||||
|
def func_shorten(func_tuple): |
||||
|
f = func_tuple[0] |
||||
|
for t in shorten_list: |
||||
|
i = string.find(f, 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' |
||||
|
|
||||
|
def Trace(msg, file=None, mode='w'): |
||||
|
"""Write a trace message to a file. Whenever a file is specified, |
||||
|
it becomes the default for the next call to Trace().""" |
||||
|
global TraceDefault |
||||
|
if file is None: |
||||
|
file = TraceDefault |
||||
|
else: |
||||
|
TraceDefault = file |
||||
|
try: |
||||
|
fp = TraceFP[file] |
||||
|
except KeyError: |
||||
|
try: |
||||
|
fp = TraceFP[file] = open(file, mode) |
||||
|
except TypeError: |
||||
|
# Assume we were passed an open file pointer. |
||||
|
fp = file |
||||
|
fp.write(msg) |
||||
|
fp.flush() |
@ -0,0 +1,463 @@ |
|||||
|
"""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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Defaults.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
|
||||
|
|
||||
|
import os |
||||
|
import os.path |
||||
|
import shutil |
||||
|
import stat |
||||
|
import string |
||||
|
import time |
||||
|
import types |
||||
|
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 = apply(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") |
||||
|
|
||||
|
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 '[' + string.join(elem_strs, ', ') + ']' |
||||
|
else: |
||||
|
return '"' + str(dest) + '"' |
||||
|
|
||||
|
def chmod_func(dest, mode): |
||||
|
SCons.Node.FS.invalidate_node_memos(dest) |
||||
|
if not SCons.Util.is_List(dest): |
||||
|
dest = [dest] |
||||
|
for element in dest: |
||||
|
os.chmod(str(element), mode) |
||||
|
|
||||
|
def chmod_strfunc(dest, mode): |
||||
|
return 'Chmod(%s, 0%o)' % (get_paths_str(dest), mode) |
||||
|
|
||||
|
Chmod = ActionFactory(chmod_func, chmod_strfunc) |
||||
|
|
||||
|
def copy_func(dest, 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.isfile(src): |
||||
|
return shutil.copy2(src, dest) |
||||
|
else: |
||||
|
return shutil.copytree(src, dest, 1) |
||||
|
|
||||
|
Copy = ActionFactory(copy_func, |
||||
|
lambda dest, src: 'Copy("%s", "%s")' % (dest, src), |
||||
|
convert=str) |
||||
|
|
||||
|
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) |
||||
|
if not must_exist and not os.path.exists(entry): |
||||
|
continue |
||||
|
if not os.path.exists(entry) or os.path.isfile(entry): |
||||
|
os.unlink(entry) |
||||
|
continue |
||||
|
else: |
||||
|
shutil.rmtree(entry, 1) |
||||
|
continue |
||||
|
|
||||
|
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: |
||||
|
os.makedirs(str(entry)) |
||||
|
|
||||
|
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) |
||||
|
os.rename(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: |
||||
|
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 not l is 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, list, 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 elements 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 list: |
||||
|
return list |
||||
|
|
||||
|
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 = map(env.subst, SCons.Util.flatten(stripprefixes)) |
||||
|
stripsuffixes = map(env.subst, SCons.Util.flatten(stripsuffixes)) |
||||
|
|
||||
|
stripped = [] |
||||
|
for l in SCons.PathList.PathList(list).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 _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. |
||||
|
""" |
||||
|
if SCons.Util.is_List(defs): |
||||
|
l = [] |
||||
|
for d in defs: |
||||
|
if SCons.Util.is_List(d) or type(d) is types.TupleType: |
||||
|
l.append(str(d[0]) + '=' + str(d[1])) |
||||
|
else: |
||||
|
l.append(str(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 = [] |
||||
|
keys = defs.keys() |
||||
|
keys.sort() |
||||
|
for k in keys: |
||||
|
v = defs[k] |
||||
|
if v is None: |
||||
|
l.append(str(k)) |
||||
|
else: |
||||
|
l.append(str(k) + '=' + str(v)) |
||||
|
else: |
||||
|
l = [str(defs)] |
||||
|
return c(prefix, env.subst_path(l), 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 frame.f_locals.has_key(variable): |
||||
|
v = frame.f_locals[variable] |
||||
|
if v: |
||||
|
method = getattr(v, self.method) |
||||
|
return apply(method, args, kw) |
||||
|
frame = frame.f_back |
||||
|
return None |
||||
|
|
||||
|
ConstructionEnvironment = { |
||||
|
'BUILDERS' : {}, |
||||
|
'SCANNERS' : [], |
||||
|
'CONFIGUREDIR' : '#/.sconf_temp', |
||||
|
'CONFIGURELOG' : '#/config.log', |
||||
|
'CPPSUFFIXES' : SCons.Tool.CSuffixes, |
||||
|
'DSUFFIXES' : SCons.Tool.DSuffixes, |
||||
|
'ENV' : {}, |
||||
|
'IDLSUFFIXES' : SCons.Tool.IDLSuffixes, |
||||
|
'LATEXSUFFIXES' : SCons.Tool.LaTeXSuffixes, |
||||
|
'_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__)}', |
||||
|
'TEMPFILE' : NullCmdGenerator, |
||||
|
'Dir' : Variable_Method_Caller('TARGET', 'Dir'), |
||||
|
'Dirs' : Variable_Method_Caller('TARGET', 'Dirs'), |
||||
|
'File' : Variable_Method_Caller('TARGET', 'File'), |
||||
|
'RDirs' : Variable_Method_Caller('TARGET', 'RDirs'), |
||||
|
} |
File diff suppressed because it is too large
@ -0,0 +1,198 @@ |
|||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
"""SCons.Errors |
||||
|
|
||||
|
This file contains the exception classes used to handle internal |
||||
|
and user errors in SCons. |
||||
|
|
||||
|
""" |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Errors.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons.Util |
||||
|
|
||||
|
import exceptions |
||||
|
|
||||
|
class BuildError(Exception): |
||||
|
""" Errors occuring while building. |
||||
|
|
||||
|
BuildError have the following 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 cause of the location of the error: |
||||
|
--------------------------------------------------------- |
||||
|
|
||||
|
node : the error occured 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)): |
||||
|
|
||||
|
self.errstr = 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 EnvironmentError(Exception): |
||||
|
pass |
||||
|
|
||||
|
class ExplicitExit(Exception): |
||||
|
def __init__(self, node=None, status=None, *args): |
||||
|
self.node = node |
||||
|
self.status = status |
||||
|
self.exitstatus = status |
||||
|
apply(Exception.__init__, (self,) + args) |
||||
|
|
||||
|
def convert_to_BuildError(status, exc_info=None): |
||||
|
""" |
||||
|
Convert any return code a BuildError Exception. |
||||
|
|
||||
|
`status' can either be a return code or an Exception. |
||||
|
The buildError.status we set here will normally be |
||||
|
used as the exit status of the "scons" process. |
||||
|
""" |
||||
|
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) |
||||
|
# TODO(1.5): |
||||
|
#elif isinstance(status, (StopError, UserError)): |
||||
|
elif isinstance(status, StopError) or isinstance(status, UserError): |
||||
|
buildError = BuildError( |
||||
|
errstr=str(status), |
||||
|
status=2, |
||||
|
exitstatus=2, |
||||
|
exc_info=exc_info) |
||||
|
elif isinstance(status, exceptions.EnvironmentError): |
||||
|
# 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). |
||||
|
try: filename = status.filename |
||||
|
except AttributeError: filename = None |
||||
|
buildError = BuildError( |
||||
|
errstr=status.strerror, |
||||
|
status=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)"%(status,buildError.errstr, buildError.status)) |
||||
|
return buildError |
@ -0,0 +1,393 @@ |
|||||
|
"""SCons.Executor |
||||
|
|
||||
|
A module for executing actions with specific lists of target and source |
||||
|
Nodes. |
||||
|
|
||||
|
""" |
||||
|
|
||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Executor.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import string |
||||
|
|
||||
|
from SCons.Debug import logInstanceCreation |
||||
|
import SCons.Errors |
||||
|
import SCons.Memoize |
||||
|
|
||||
|
|
||||
|
class Executor: |
||||
|
"""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. |
||||
|
""" |
||||
|
|
||||
|
if SCons.Memoize.use_memoizer: |
||||
|
__metaclass__ = SCons.Memoize.Memoized_Metaclass |
||||
|
|
||||
|
memoizer_counters = [] |
||||
|
|
||||
|
def __init__(self, action, env=None, overridelist=[{}], |
||||
|
targets=[], sources=[], builder_kw={}): |
||||
|
if __debug__: logInstanceCreation(self, 'Executor.Executor') |
||||
|
self.set_action_list(action) |
||||
|
self.pre_actions = [] |
||||
|
self.post_actions = [] |
||||
|
self.env = env |
||||
|
self.overridelist = overridelist |
||||
|
self.targets = targets |
||||
|
self.sources = sources[:] |
||||
|
self.sources_need_sorting = False |
||||
|
self.builder_kw = builder_kw |
||||
|
self._memo = {} |
||||
|
|
||||
|
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): |
||||
|
return self.pre_actions + self.action_list + self.post_actions |
||||
|
|
||||
|
memoizer_counters.append(SCons.Memoize.CountValue('get_build_env')) |
||||
|
|
||||
|
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.targets[0].cwd |
||||
|
except (IndexError, AttributeError): |
||||
|
cwd = None |
||||
|
return scanner.path(env, cwd, self.targets, self.get_sources()) |
||||
|
|
||||
|
def get_kw(self, kw={}): |
||||
|
result = self.builder_kw.copy() |
||||
|
result.update(kw) |
||||
|
return result |
||||
|
|
||||
|
def do_nothing(self, target, kw): |
||||
|
return 0 |
||||
|
|
||||
|
def do_execute(self, target, kw): |
||||
|
"""Actually execute the action list.""" |
||||
|
env = self.get_build_env() |
||||
|
kw = self.get_kw(kw) |
||||
|
status = 0 |
||||
|
for act in self.get_action_list(): |
||||
|
status = apply(act, (self.targets, self.get_sources(), env), kw) |
||||
|
if isinstance(status, SCons.Errors.BuildError): |
||||
|
status.executor = self |
||||
|
raise status |
||||
|
elif status: |
||||
|
msg = "Error %s" % status |
||||
|
raise SCons.Errors.BuildError( |
||||
|
errstr=msg, |
||||
|
node=self.targets, |
||||
|
executor=self, |
||||
|
action=act) |
||||
|
return status |
||||
|
|
||||
|
# 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 self.do_execute(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.""" |
||||
|
self.sources.extend(sources) |
||||
|
self.sources_need_sorting = True |
||||
|
|
||||
|
def get_sources(self): |
||||
|
if self.sources_need_sorting: |
||||
|
self.sources = SCons.Util.uniquer_hashables(self.sources) |
||||
|
self.sources_need_sorting = False |
||||
|
return self.sources |
||||
|
|
||||
|
def prepare(self): |
||||
|
""" |
||||
|
Preparatory checks for whether this Executor can go ahead |
||||
|
and (try to) build its targets. |
||||
|
""" |
||||
|
for s in self.get_sources(): |
||||
|
if s.missing(): |
||||
|
msg = "Source `%s' not found, needed by target `%s'." |
||||
|
raise SCons.Errors.StopError, msg % (s, self.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 my_str(self): |
||||
|
env = self.get_build_env() |
||||
|
get = lambda action, t=self.targets, s=self.get_sources(), e=env: \ |
||||
|
action.genstring(t, s, e) |
||||
|
return string.join(map(get, self.get_action_list()), "\n") |
||||
|
|
||||
|
|
||||
|
def __str__(self): |
||||
|
return self.my_str() |
||||
|
|
||||
|
def nullify(self): |
||||
|
self.cleanup() |
||||
|
self.do_execute = self.do_nothing |
||||
|
self.my_str = lambda S=self: '' |
||||
|
|
||||
|
memoizer_counters.append(SCons.Memoize.CountValue('get_contents')) |
||||
|
|
||||
|
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. |
||||
|
""" |
||||
|
try: |
||||
|
return self._memo['get_contents'] |
||||
|
except KeyError: |
||||
|
pass |
||||
|
env = self.get_build_env() |
||||
|
get = lambda action, t=self.targets, s=self.get_sources(), e=env: \ |
||||
|
action.get_contents(t, s, e) |
||||
|
result = string.join(map(get, self.get_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): |
||||
|
self.scan(scanner, self.targets) |
||||
|
|
||||
|
def scan_sources(self, scanner): |
||||
|
if self.sources: |
||||
|
self.scan(scanner, self.get_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() |
||||
|
|
||||
|
deps = [] |
||||
|
if scanner: |
||||
|
for node in node_list: |
||||
|
node.disambiguate() |
||||
|
s = scanner.select(node) |
||||
|
if not s: |
||||
|
continue |
||||
|
path = self.get_build_scanner_path(s) |
||||
|
deps.extend(node.get_implicit_deps(env, s, path)) |
||||
|
else: |
||||
|
kw = self.get_kw() |
||||
|
for node in node_list: |
||||
|
node.disambiguate() |
||||
|
scanner = node.get_env_scanner(env, kw) |
||||
|
if not scanner: |
||||
|
continue |
||||
|
scanner = scanner.select(node) |
||||
|
if not scanner: |
||||
|
continue |
||||
|
path = self.get_build_scanner_path(scanner) |
||||
|
deps.extend(node.get_implicit_deps(env, scanner, path)) |
||||
|
|
||||
|
deps.extend(self.get_implicit_deps()) |
||||
|
|
||||
|
for tgt in self.targets: |
||||
|
tgt.add_to_implicit(deps) |
||||
|
|
||||
|
def _get_unignored_sources_key(self, ignore=()): |
||||
|
return tuple(ignore) |
||||
|
|
||||
|
memoizer_counters.append(SCons.Memoize.CountDict('get_unignored_sources', _get_unignored_sources_key)) |
||||
|
|
||||
|
def get_unignored_sources(self, ignore=()): |
||||
|
ignore = 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[ignore] |
||||
|
except KeyError: |
||||
|
pass |
||||
|
|
||||
|
sourcelist = self.get_sources() |
||||
|
if ignore: |
||||
|
idict = {} |
||||
|
for i in ignore: |
||||
|
idict[i] = 1 |
||||
|
sourcelist = filter(lambda s, i=idict: not i.has_key(s), sourcelist) |
||||
|
|
||||
|
memo_dict[ignore] = sourcelist |
||||
|
|
||||
|
return sourcelist |
||||
|
|
||||
|
def _process_sources_key(self, func, ignore=()): |
||||
|
return (func, tuple(ignore)) |
||||
|
|
||||
|
memoizer_counters.append(SCons.Memoize.CountDict('process_sources', _process_sources_key)) |
||||
|
|
||||
|
def process_sources(self, func, ignore=()): |
||||
|
memo_key = (func, tuple(ignore)) |
||||
|
try: |
||||
|
memo_dict = self._memo['process_sources'] |
||||
|
except KeyError: |
||||
|
memo_dict = {} |
||||
|
self._memo['process_sources'] = memo_dict |
||||
|
else: |
||||
|
try: |
||||
|
return memo_dict[memo_key] |
||||
|
except KeyError: |
||||
|
pass |
||||
|
|
||||
|
result = map(func, self.get_unignored_sources(ignore)) |
||||
|
|
||||
|
memo_dict[memo_key] = result |
||||
|
|
||||
|
return result |
||||
|
|
||||
|
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(): |
||||
|
result.extend(act.get_implicit_deps(self.targets, self.get_sources(), build_env)) |
||||
|
return result |
||||
|
|
||||
|
nullenv = None |
||||
|
|
||||
|
def get_NullEnvironment(): |
||||
|
"""Use singleton pattern for Null Environments.""" |
||||
|
global nullenv |
||||
|
|
||||
|
import SCons.Util |
||||
|
class NullEnvironment(SCons.Util.Null): |
||||
|
import SCons.CacheDir |
||||
|
_CacheDir_path = None |
||||
|
_CacheDir = SCons.CacheDir.CacheDir(None) |
||||
|
def get_CacheDir(self): |
||||
|
return self._CacheDir |
||||
|
|
||||
|
if not nullenv: |
||||
|
nullenv = NullEnvironment() |
||||
|
return nullenv |
||||
|
|
||||
|
class Null: |
||||
|
"""A null Executor, with a null build Environment, that does |
||||
|
nothing when the rest of the methods call it. |
||||
|
|
||||
|
This might be able to disapper 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. |
||||
|
""" |
||||
|
def __init__(self, *args, **kw): |
||||
|
if __debug__: logInstanceCreation(self, 'Executor.Null') |
||||
|
self.targets = 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_list(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.""" |
||||
|
self.__class__ = Executor |
||||
|
self.__init__([], targets=self.targets) |
||||
|
|
||||
|
# 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) |
||||
|
|
||||
|
|
@ -0,0 +1,429 @@ |
|||||
|
"""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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Job.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
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 very difficult to stop the build process |
||||
|
by throwing asynchronously an exception such as |
||||
|
KeyboardInterrupt. For example, the python Condition |
||||
|
variables (threading.Condition) and Queue's do not seem to |
||||
|
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 1: |
||||
|
task = self.taskmaster.next_task() |
||||
|
|
||||
|
if task is None: |
||||
|
break |
||||
|
|
||||
|
try: |
||||
|
task.prepare() |
||||
|
if task.needs_execute(): |
||||
|
task.execute() |
||||
|
except: |
||||
|
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 1: |
||||
|
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, e: |
||||
|
# Only print a warning if the stack size has been |
||||
|
# explicitly set. |
||||
|
if not explicit_stack_size is 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, 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) |
||||
|
|
||||
|
# Once we drop Python 1.5 we can change the following to: |
||||
|
#if 'prev_size' in locals(): |
||||
|
if 'prev_size' in locals().keys(): |
||||
|
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 1: |
||||
|
# 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 1: |
||||
|
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() |
@ -0,0 +1,286 @@ |
|||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Memoize.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
__doc__ = """Memoizer |
||||
|
|
||||
|
A metaclass 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. Here is an example of wrapping a method |
||||
|
that returns a computed value, with no input parameters: |
||||
|
|
||||
|
memoizer_counters = [] # Memoization |
||||
|
|
||||
|
memoizer_counters.append(SCons.Memoize.CountValue('foo')) # Memoization |
||||
|
|
||||
|
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 |
||||
|
|
||||
|
memoizer_counters.append(SCons.Memoize.CountDict('bar', _bar_key)) # Memoization |
||||
|
|
||||
|
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 |
||||
|
|
||||
|
At one point we avoided replicating this sort of logic in all the methods |
||||
|
by putting it right into this module, but we've moved away from that at |
||||
|
present (see the "Historical Note," below.). |
||||
|
|
||||
|
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. |
||||
|
|
||||
|
Historical Note: The initial Memoizer implementation actually handled |
||||
|
the caching of values for the wrapped methods, based on a set of generic |
||||
|
algorithms for computing hashable values based on the method's arguments. |
||||
|
This collected caching logic nicely, but had two drawbacks: |
||||
|
|
||||
|
Running arguments through a generic key-conversion mechanism is slower |
||||
|
(and less flexible) than just coding these things directly. Since the |
||||
|
methods that need memoized values are generally performance-critical, |
||||
|
slowing them down in order to collect the logic isn't the right |
||||
|
tradeoff. |
||||
|
|
||||
|
Use of the memoizer really obscured what was being called, because |
||||
|
all the memoized methods were wrapped with re-used generic methods. |
||||
|
This made it more difficult, for example, to use the Python profiler |
||||
|
to figure out how to optimize the underlying methods. |
||||
|
""" |
||||
|
|
||||
|
import new |
||||
|
|
||||
|
# A flag controlling whether or not we actually use memoization. |
||||
|
use_memoizer = None |
||||
|
|
||||
|
CounterList = [] |
||||
|
|
||||
|
class Counter: |
||||
|
""" |
||||
|
Base class for counting memoization hits and misses. |
||||
|
|
||||
|
We expect that the metaclass initialization will have filled in |
||||
|
the .name attribute that represents the name of the function |
||||
|
being counted. |
||||
|
""" |
||||
|
def __init__(self, method_name): |
||||
|
""" |
||||
|
""" |
||||
|
self.method_name = method_name |
||||
|
self.hit = 0 |
||||
|
self.miss = 0 |
||||
|
CounterList.append(self) |
||||
|
def display(self): |
||||
|
fmt = " %7d hits %7d misses %s()" |
||||
|
print fmt % (self.hit, self.miss, self.name) |
||||
|
def __cmp__(self, other): |
||||
|
try: |
||||
|
return cmp(self.name, other.name) |
||||
|
except AttributeError: |
||||
|
return 0 |
||||
|
|
||||
|
class CountValue(Counter): |
||||
|
""" |
||||
|
A counter class for simple, atomic memoized values. |
||||
|
|
||||
|
A CountValue object should be instantiated in a class for each of |
||||
|
the class's methods that memoizes its return value by simply storing |
||||
|
the return value in its _memo dictionary. |
||||
|
|
||||
|
We expect that the metaclass initialization will fill in the |
||||
|
.underlying_method attribute with the method that we're wrapping. |
||||
|
We then call the underlying_method method after counting whether |
||||
|
its memoized value has already been set (a hit) or not (a miss). |
||||
|
""" |
||||
|
def __call__(self, *args, **kw): |
||||
|
obj = args[0] |
||||
|
if obj._memo.has_key(self.method_name): |
||||
|
self.hit = self.hit + 1 |
||||
|
else: |
||||
|
self.miss = self.miss + 1 |
||||
|
return apply(self.underlying_method, args, kw) |
||||
|
|
||||
|
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 class 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. |
||||
|
|
||||
|
We expect that the metaclass initialization will fill in the |
||||
|
.underlying_method attribute with the method that we're wrapping. |
||||
|
We then call the underlying_method method after counting whether the |
||||
|
computed key value is already present in the memoization dictionary |
||||
|
(a hit) or not (a miss). |
||||
|
""" |
||||
|
def __init__(self, method_name, keymaker): |
||||
|
""" |
||||
|
""" |
||||
|
Counter.__init__(self, method_name) |
||||
|
self.keymaker = keymaker |
||||
|
def __call__(self, *args, **kw): |
||||
|
obj = args[0] |
||||
|
try: |
||||
|
memo_dict = obj._memo[self.method_name] |
||||
|
except KeyError: |
||||
|
self.miss = self.miss + 1 |
||||
|
else: |
||||
|
key = apply(self.keymaker, args, kw) |
||||
|
if memo_dict.has_key(key): |
||||
|
self.hit = self.hit + 1 |
||||
|
else: |
||||
|
self.miss = self.miss + 1 |
||||
|
return apply(self.underlying_method, args, kw) |
||||
|
|
||||
|
class Memoizer: |
||||
|
"""Object which performs caching of method calls for its 'primary' |
||||
|
instance.""" |
||||
|
|
||||
|
def __init__(self): |
||||
|
pass |
||||
|
|
||||
|
# Find out if we support metaclasses (Python 2.2 and later). |
||||
|
|
||||
|
class M: |
||||
|
def __init__(cls, name, bases, cls_dict): |
||||
|
cls.use_metaclass = 1 |
||||
|
def fake_method(self): |
||||
|
pass |
||||
|
new.instancemethod(fake_method, None, cls) |
||||
|
|
||||
|
try: |
||||
|
class A: |
||||
|
__metaclass__ = M |
||||
|
|
||||
|
use_metaclass = A.use_metaclass |
||||
|
except AttributeError: |
||||
|
use_metaclass = None |
||||
|
reason = 'no metaclasses' |
||||
|
except TypeError: |
||||
|
use_metaclass = None |
||||
|
reason = 'new.instancemethod() bug' |
||||
|
else: |
||||
|
del A |
||||
|
|
||||
|
del M |
||||
|
|
||||
|
if not use_metaclass: |
||||
|
|
||||
|
def Dump(title): |
||||
|
pass |
||||
|
|
||||
|
try: |
||||
|
class Memoized_Metaclass(type): |
||||
|
# Just a place-holder so pre-metaclass Python versions don't |
||||
|
# have to have special code for the Memoized classes. |
||||
|
pass |
||||
|
except TypeError: |
||||
|
class Memoized_Metaclass: |
||||
|
# A place-holder so pre-metaclass Python versions don't |
||||
|
# have to have special code for the Memoized classes. |
||||
|
pass |
||||
|
|
||||
|
def EnableMemoization(): |
||||
|
import SCons.Warnings |
||||
|
msg = 'memoization is not supported in this version of Python (%s)' |
||||
|
raise SCons.Warnings.NoMetaclassSupportWarning, msg % reason |
||||
|
|
||||
|
else: |
||||
|
|
||||
|
def Dump(title=None): |
||||
|
if title: |
||||
|
print title |
||||
|
CounterList.sort() |
||||
|
for counter in CounterList: |
||||
|
counter.display() |
||||
|
|
||||
|
class Memoized_Metaclass(type): |
||||
|
def __init__(cls, name, bases, cls_dict): |
||||
|
super(Memoized_Metaclass, cls).__init__(name, bases, cls_dict) |
||||
|
|
||||
|
for counter in cls_dict.get('memoizer_counters', []): |
||||
|
method_name = counter.method_name |
||||
|
|
||||
|
counter.name = cls.__name__ + '.' + method_name |
||||
|
counter.underlying_method = cls_dict[method_name] |
||||
|
|
||||
|
replacement_method = new.instancemethod(counter, None, cls) |
||||
|
setattr(cls, method_name, replacement_method) |
||||
|
|
||||
|
def EnableMemoization(): |
||||
|
global use_memoizer |
||||
|
use_memoizer = 1 |
@ -0,0 +1,147 @@ |
|||||
|
|
||||
|
"""scons.Node.Alias |
||||
|
|
||||
|
Alias nodes. |
||||
|
|
||||
|
This creates a hash of global Aliases (dummy targets). |
||||
|
|
||||
|
""" |
||||
|
|
||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Node/Alias.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import string |
||||
|
import UserDict |
||||
|
|
||||
|
import SCons.Errors |
||||
|
import SCons.Node |
||||
|
import SCons.Util |
||||
|
|
||||
|
class AliasNameSpace(UserDict.UserDict): |
||||
|
def Alias(self, name, **kw): |
||||
|
if isinstance(name, SCons.Node.Alias.Alias): |
||||
|
return name |
||||
|
try: |
||||
|
a = self[name] |
||||
|
except KeyError: |
||||
|
a = apply(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): |
||||
|
current_version_id = 1 |
||||
|
field_list = ['csig'] |
||||
|
def str_to_node(self, s): |
||||
|
return default_ans.Alias(s) |
||||
|
|
||||
|
class AliasBuildInfo(SCons.Node.BuildInfoBase): |
||||
|
current_version_id = 1 |
||||
|
|
||||
|
class Alias(SCons.Node.Node): |
||||
|
|
||||
|
NodeInfo = AliasNodeInfo |
||||
|
BuildInfo = AliasBuildInfo |
||||
|
|
||||
|
def __init__(self, name): |
||||
|
SCons.Node.Node.__init__(self) |
||||
|
self.name = name |
||||
|
|
||||
|
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 = map(lambda n: n.get_csig(), self.children()) |
||||
|
return string.join(childsigs, '') |
||||
|
|
||||
|
def sconsign(self): |
||||
|
"""An Alias is not recorded in .sconsign files""" |
||||
|
pass |
||||
|
|
||||
|
# |
||||
|
# |
||||
|
# |
||||
|
|
||||
|
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 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 = SCons.Util.MD5signature(contents) |
||||
|
self.get_ninfo().csig = csig |
||||
|
return csig |
||||
|
|
||||
|
default_ans = AliasNameSpace() |
||||
|
|
||||
|
SCons.Node.arg2nodes_lookups.append(default_ans.lookup) |
File diff suppressed because it is too large
@ -0,0 +1,119 @@ |
|||||
|
"""scons.Node.Python |
||||
|
|
||||
|
Python nodes. |
||||
|
|
||||
|
""" |
||||
|
|
||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Node/Python.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons.Node |
||||
|
|
||||
|
class ValueNodeInfo(SCons.Node.NodeInfoBase): |
||||
|
current_version_id = 1 |
||||
|
|
||||
|
field_list = ['csig'] |
||||
|
|
||||
|
def str_to_node(self, s): |
||||
|
return Value(s) |
||||
|
|
||||
|
class ValueBuildInfo(SCons.Node.BuildInfoBase): |
||||
|
current_version_id = 1 |
||||
|
|
||||
|
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): |
||||
|
SCons.Node.Node.__init__(self) |
||||
|
self.value = value |
||||
|
if not built_value is None: |
||||
|
self.built_value = built_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'): |
||||
|
apply (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_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.""" |
||||
|
contents = str(self.value) |
||||
|
for kid in self.children(None): |
||||
|
contents = contents + kid.get_contents() |
||||
|
return 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.""" |
||||
|
try: |
||||
|
return self.ninfo.csig |
||||
|
except AttributeError: |
||||
|
pass |
||||
|
contents = self.get_contents() |
||||
|
self.get_ninfo().csig = contents |
||||
|
return contents |
File diff suppressed because it is too large
@ -0,0 +1,44 @@ |
|||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Options/BoolOption.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
__doc__ = """Place-holder for the old SCons.Options module hierarchy |
||||
|
|
||||
|
This is for backwards compatibility. The new equivalent is the Variables/ |
||||
|
class hierarchy. These will have deprecation warnings added (some day), |
||||
|
and will then be removed entirely (some day). |
||||
|
""" |
||||
|
|
||||
|
import SCons.Variables |
||||
|
import SCons.Warnings |
||||
|
|
||||
|
warned = False |
||||
|
|
||||
|
def BoolOption(*args, **kw): |
||||
|
global warned |
||||
|
if not warned: |
||||
|
msg = "The BoolOption() function is deprecated; use the BoolVariable() function instead." |
||||
|
SCons.Warnings.warn(SCons.Warnings.DeprecatedOptionsWarning, msg) |
||||
|
warned = True |
||||
|
return apply(SCons.Variables.BoolVariable, args, kw) |
@ -0,0 +1,44 @@ |
|||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Options/EnumOption.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
__doc__ = """Place-holder for the old SCons.Options module hierarchy |
||||
|
|
||||
|
This is for backwards compatibility. The new equivalent is the Variables/ |
||||
|
class hierarchy. These will have deprecation warnings added (some day), |
||||
|
and will then be removed entirely (some day). |
||||
|
""" |
||||
|
|
||||
|
import SCons.Variables |
||||
|
import SCons.Warnings |
||||
|
|
||||
|
warned = False |
||||
|
|
||||
|
def EnumOption(*args, **kw): |
||||
|
global warned |
||||
|
if not warned: |
||||
|
msg = "The EnumOption() function is deprecated; use the EnumVariable() function instead." |
||||
|
SCons.Warnings.warn(SCons.Warnings.DeprecatedOptionsWarning, msg) |
||||
|
warned = True |
||||
|
return apply(SCons.Variables.EnumVariable, args, kw) |
@ -0,0 +1,44 @@ |
|||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Options/ListOption.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
__doc__ = """Place-holder for the old SCons.Options module hierarchy |
||||
|
|
||||
|
This is for backwards compatibility. The new equivalent is the Variables/ |
||||
|
class hierarchy. These will have deprecation warnings added (some day), |
||||
|
and will then be removed entirely (some day). |
||||
|
""" |
||||
|
|
||||
|
import SCons.Variables |
||||
|
import SCons.Warnings |
||||
|
|
||||
|
warned = False |
||||
|
|
||||
|
def ListOption(*args, **kw): |
||||
|
global warned |
||||
|
if not warned: |
||||
|
msg = "The ListOption() function is deprecated; use the ListVariable() function instead." |
||||
|
SCons.Warnings.warn(SCons.Warnings.DeprecatedOptionsWarning, msg) |
||||
|
warned = True |
||||
|
return apply(SCons.Variables.ListVariable, args, kw) |
@ -0,0 +1,44 @@ |
|||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Options/PackageOption.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
__doc__ = """Place-holder for the old SCons.Options module hierarchy |
||||
|
|
||||
|
This is for backwards compatibility. The new equivalent is the Variables/ |
||||
|
class hierarchy. These will have deprecation warnings added (some day), |
||||
|
and will then be removed entirely (some day). |
||||
|
""" |
||||
|
|
||||
|
import SCons.Variables |
||||
|
import SCons.Warnings |
||||
|
|
||||
|
warned = False |
||||
|
|
||||
|
def PackageOption(*args, **kw): |
||||
|
global warned |
||||
|
if not warned: |
||||
|
msg = "The PackageOption() function is deprecated; use the PackageVariable() function instead." |
||||
|
SCons.Warnings.warn(SCons.Warnings.DeprecatedOptionsWarning, msg) |
||||
|
warned = True |
||||
|
return apply(SCons.Variables.PackageVariable, args, kw) |
@ -0,0 +1,70 @@ |
|||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Options/PathOption.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
__doc__ = """Place-holder for the old SCons.Options module hierarchy |
||||
|
|
||||
|
This is for backwards compatibility. The new equivalent is the Variables/ |
||||
|
class hierarchy. These will have deprecation warnings added (some day), |
||||
|
and will then be removed entirely (some day). |
||||
|
""" |
||||
|
|
||||
|
import SCons.Variables |
||||
|
import SCons.Warnings |
||||
|
|
||||
|
warned = False |
||||
|
|
||||
|
class _PathOptionClass: |
||||
|
def warn(self): |
||||
|
global warned |
||||
|
if not warned: |
||||
|
msg = "The PathOption() function is deprecated; use the PathVariable() function instead." |
||||
|
SCons.Warnings.warn(SCons.Warnings.DeprecatedOptionsWarning, msg) |
||||
|
warned = True |
||||
|
|
||||
|
def __call__(self, *args, **kw): |
||||
|
self.warn() |
||||
|
return apply(SCons.Variables.PathVariable, args, kw) |
||||
|
|
||||
|
def PathAccept(self, *args, **kw): |
||||
|
self.warn() |
||||
|
return apply(SCons.Variables.PathVariable.PathAccept, args, kw) |
||||
|
|
||||
|
def PathIsDir(self, *args, **kw): |
||||
|
self.warn() |
||||
|
return apply(SCons.Variables.PathVariable.PathIsDir, args, kw) |
||||
|
|
||||
|
def PathIsDirCreate(self, *args, **kw): |
||||
|
self.warn() |
||||
|
return apply(SCons.Variables.PathVariable.PathIsDirCreate, args, kw) |
||||
|
|
||||
|
def PathIsFile(self, *args, **kw): |
||||
|
self.warn() |
||||
|
return apply(SCons.Variables.PathVariable.PathIsFile, args, kw) |
||||
|
|
||||
|
def PathExists(self, *args, **kw): |
||||
|
self.warn() |
||||
|
return apply(SCons.Variables.PathVariable.PathExists, args, kw) |
||||
|
|
||||
|
PathOption = _PathOptionClass() |
@ -0,0 +1,68 @@ |
|||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Options/__init__.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
__doc__ = """Place-holder for the old SCons.Options module hierarchy |
||||
|
|
||||
|
This is for backwards compatibility. The new equivalent is the Variables/ |
||||
|
class hierarchy. These will have deprecation warnings added (some day), |
||||
|
and will then be removed entirely (some day). |
||||
|
""" |
||||
|
|
||||
|
import SCons.Variables |
||||
|
import SCons.Warnings |
||||
|
|
||||
|
from BoolOption import BoolOption # okay |
||||
|
from EnumOption import EnumOption # okay |
||||
|
from ListOption import ListOption # naja |
||||
|
from PackageOption import PackageOption # naja |
||||
|
from PathOption import PathOption # okay |
||||
|
|
||||
|
warned = False |
||||
|
|
||||
|
class Options(SCons.Variables.Variables): |
||||
|
def __init__(self, *args, **kw): |
||||
|
global warned |
||||
|
if not warned: |
||||
|
msg = "The Options class is deprecated; use the Variables class instead." |
||||
|
SCons.Warnings.warn(SCons.Warnings.DeprecatedOptionsWarning, msg) |
||||
|
warned = True |
||||
|
apply(SCons.Variables.Variables.__init__, |
||||
|
(self,) + args, |
||||
|
kw) |
||||
|
|
||||
|
def AddOptions(self, *args, **kw): |
||||
|
return apply(SCons.Variables.Variables.AddVariables, |
||||
|
(self,) + args, |
||||
|
kw) |
||||
|
|
||||
|
def UnknownOptions(self, *args, **kw): |
||||
|
return apply(SCons.Variables.Variables.UnknownVariables, |
||||
|
(self,) + args, |
||||
|
kw) |
||||
|
|
||||
|
def FormatOptionHelpText(self, *args, **kw): |
||||
|
return apply(SCons.Variables.Variables.FormatVariableHelpText, |
||||
|
(self,) + args, |
||||
|
kw) |
@ -0,0 +1,226 @@ |
|||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/PathList.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
__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 string |
||||
|
|
||||
|
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 = string.split(pathlist, os.pathsep) |
||||
|
elif not SCons.Util.is_Sequence(pathlist): |
||||
|
pathlist = [pathlist] |
||||
|
|
||||
|
pl = [] |
||||
|
for p in pathlist: |
||||
|
try: |
||||
|
index = string.find(p, '$') |
||||
|
except (AttributeError, TypeError): |
||||
|
type = TYPE_OBJECT |
||||
|
else: |
||||
|
if index == -1: |
||||
|
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(value) |
||||
|
continue |
||||
|
|
||||
|
elif type == TYPE_OBJECT: |
||||
|
value = node_conv(value) |
||||
|
if 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. |
||||
|
""" |
||||
|
if SCons.Memoize.use_memoizer: |
||||
|
__metaclass__ = SCons.Memoize.Memoized_Metaclass |
||||
|
|
||||
|
memoizer_counters = [] |
||||
|
|
||||
|
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 |
||||
|
|
||||
|
memoizer_counters.append(SCons.Memoize.CountDict('PathList', _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 |
@ -0,0 +1,216 @@ |
|||||
|
"""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 subsysem 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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Platform/__init__.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import imp |
||||
|
import os |
||||
|
import string |
||||
|
import sys |
||||
|
import tempfile |
||||
|
|
||||
|
import SCons.Errors |
||||
|
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 we're 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 string.find(sys.platform, 'irix') != -1: |
||||
|
return 'irix' |
||||
|
elif string.find(sys.platform, 'sunos') != -1: |
||||
|
return 'sunos' |
||||
|
elif string.find(sys.platform, 'hp-ux') != -1: |
||||
|
return 'hpux' |
||||
|
elif string.find(sys.platform, 'aix') != -1: |
||||
|
return 'aix' |
||||
|
elif string.find(sys.platform, '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 not sys.modules.has_key(full_name): |
||||
|
if os.name == 'java': |
||||
|
eval(full_name) |
||||
|
else: |
||||
|
try: |
||||
|
file, path, desc = imp.find_module(name, |
||||
|
sys.modules['SCons.Platform'].__path__) |
||||
|
try: |
||||
|
mod = imp.load_module(full_name, file, path, desc) |
||||
|
finally: |
||||
|
if file: |
||||
|
file.close() |
||||
|
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): |
||||
|
self.name = name |
||||
|
|
||||
|
def __str__(self): |
||||
|
return self.name |
||||
|
|
||||
|
class TempFileMunge: |
||||
|
"""A callable class. You can set an Environment variable to this, |
||||
|
then call it with a string argument, then it will perform temporary |
||||
|
file substitution on it. This is used to circumvent the long command |
||||
|
line limitation. |
||||
|
|
||||
|
Example usage: |
||||
|
env["TEMPFILE"] = TempFileMunge |
||||
|
env["LINKCOM"] = "${TEMPFILE('$LINK $TARGET $SOURCES')}" |
||||
|
|
||||
|
By default, the name of the temporary file used begins with a |
||||
|
prefix of '@'. This may be configred for other tool chains by |
||||
|
setting '$TEMPFILEPREFIX'. |
||||
|
|
||||
|
env["TEMPFILEPREFIX"] = '-@' # diab compiler |
||||
|
env["TEMPFILEPREFIX"] = '-via' # arm tool chain |
||||
|
""" |
||||
|
def __init__(self, cmd): |
||||
|
self.cmd = cmd |
||||
|
|
||||
|
def __call__(self, target, source, env, for_signature): |
||||
|
if for_signature: |
||||
|
return self.cmd |
||||
|
cmd = env.subst_list(self.cmd, 0, target, source)[0] |
||||
|
try: |
||||
|
maxline = int(env.subst('$MAXLINELENGTH')) |
||||
|
except ValueError: |
||||
|
maxline = 2048 |
||||
|
|
||||
|
if (reduce(lambda x, y: x + len(y), cmd, 0) + len(cmd)) <= maxline: |
||||
|
return self.cmd |
||||
|
|
||||
|
# We do a normpath because mktemp() has what appears to be |
||||
|
# a bug in Windows that will use a forward slash as a path |
||||
|
# delimiter. Windows's link mistakes that for a command line |
||||
|
# switch and barfs. |
||||
|
# |
||||
|
# We use the .lnk suffix for the benefit of the Phar Lap |
||||
|
# linkloc linker, which likes to append an .lnk suffix if |
||||
|
# none is given. |
||||
|
tmp = os.path.normpath(tempfile.mktemp('.lnk')) |
||||
|
native_tmp = SCons.Util.get_native_path(tmp) |
||||
|
|
||||
|
if env['SHELL'] and env['SHELL'] == 'sh': |
||||
|
# The sh shell will try to escape the backslashes in the |
||||
|
# path, so unescape them. |
||||
|
native_tmp = string.replace(native_tmp, '\\', 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 = map(SCons.Subst.quote_spaces, cmd[1:]) |
||||
|
open(tmp, 'w').write(string.join(args, " ") + "\n") |
||||
|
# 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: |
||||
|
print("Using tempfile "+native_tmp+" for command line:\n"+ |
||||
|
str(cmd[0]) + " " + string.join(args," ")) |
||||
|
return [ cmd[0], prefix + native_tmp + '\n' + rm, native_tmp ] |
||||
|
|
||||
|
def Platform(name = platform_default()): |
||||
|
"""Select a canned Platform specification. |
||||
|
""" |
||||
|
module = platform_module(name) |
||||
|
spec = PlatformSpec(name) |
||||
|
spec.__call__ = module.generate |
||||
|
return spec |
@ -0,0 +1,65 @@ |
|||||
|
"""engine.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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Platform/aix.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import os |
||||
|
import string |
||||
|
|
||||
|
import posix |
||||
|
|
||||
|
def get_xlc(env, xlc=None, xlc_r=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 xlc_r is None: |
||||
|
xlc_r = xlc + '_r' |
||||
|
for package in packages: |
||||
|
cmd = "lslpp -fc " + package + " 2>/dev/null | egrep '" + xlc + "([^-_a-zA-Z0-9].*)?$'" |
||||
|
line = os.popen(cmd).readline() |
||||
|
if line: |
||||
|
v, p = string.split(line, ':')[1:3] |
||||
|
xlcVersion = string.split(v)[1] |
||||
|
xlcPath = string.split(p)[0] |
||||
|
xlcPath = xlcPath[:xlcPath.rindex('/')] |
||||
|
break |
||||
|
return (xlcPath, xlc, xlc_r, xlcVersion) |
||||
|
|
||||
|
def generate(env): |
||||
|
posix.generate(env) |
||||
|
#Based on AIX 5.2: ARG_MAX=24576 - 3000 for environment expansion |
||||
|
env['MAXLINELENGTH'] = 21576 |
||||
|
|
@ -0,0 +1,49 @@ |
|||||
|
"""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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Platform/cygwin.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import posix |
||||
|
from SCons.Platform import TempFileMunge |
||||
|
|
||||
|
def generate(env): |
||||
|
posix.generate(env) |
||||
|
|
||||
|
env['PROGPREFIX'] = '' |
||||
|
env['PROGSUFFIX'] = '.exe' |
||||
|
env['SHLIBPREFIX'] = '' |
||||
|
env['SHLIBSUFFIX'] = '.dll' |
||||
|
env['LIBPREFIXES'] = [ '$LIBPREFIX', '$SHLIBPREFIX' ] |
||||
|
env['LIBSUFFIXES'] = [ '$LIBSUFFIX', '$SHLIBSUFFIX' ] |
||||
|
env['TEMPFILE'] = TempFileMunge |
||||
|
env['TEMPFILEPREFIX'] = '@' |
||||
|
env['MAXLINELENGTH'] = 2048 |
@ -0,0 +1,40 @@ |
|||||
|
"""engine.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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Platform/darwin.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import posix |
||||
|
|
||||
|
def generate(env): |
||||
|
posix.generate(env) |
||||
|
env['SHLIBSUFFIX'] = '.dylib' |
||||
|
env['ENV']['PATH'] = env['ENV']['PATH'] + ':/sw/bin' |
@ -0,0 +1,40 @@ |
|||||
|
"""engine.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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Platform/hpux.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import posix |
||||
|
|
||||
|
def generate(env): |
||||
|
posix.generate(env) |
||||
|
#Based on HP-UX11i: ARG_MAX=2048000 - 3000 for environment expansion |
||||
|
env['MAXLINELENGTH'] = 2045000 |
@ -0,0 +1,38 @@ |
|||||
|
"""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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Platform/irix.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import posix |
||||
|
|
||||
|
def generate(env): |
||||
|
posix.generate(env) |
@ -0,0 +1,49 @@ |
|||||
|
"""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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Platform/os2.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
def generate(env): |
||||
|
if not env.has_key('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' ] |
@ -0,0 +1,258 @@ |
|||||
|
"""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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Platform/posix.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import errno |
||||
|
import os |
||||
|
import os.path |
||||
|
import string |
||||
|
import subprocess |
||||
|
import sys |
||||
|
import select |
||||
|
|
||||
|
import SCons.Util |
||||
|
from SCons.Platform import TempFileMunge |
||||
|
|
||||
|
exitvalmap = { |
||||
|
2 : 127, |
||||
|
13 : 126, |
||||
|
} |
||||
|
|
||||
|
def escape(arg): |
||||
|
"escape shell special characters" |
||||
|
slash = '\\' |
||||
|
special = '"$()' |
||||
|
|
||||
|
arg = string.replace(arg, slash, slash+slash) |
||||
|
for c in special: |
||||
|
arg = string.replace(arg, c, slash+c) |
||||
|
|
||||
|
return '"' + arg + '"' |
||||
|
|
||||
|
def exec_system(l, env): |
||||
|
stat = os.system(string.join(l)) |
||||
|
if stat & 0xff: |
||||
|
return stat | 0x80 |
||||
|
return stat >> 8 |
||||
|
|
||||
|
def exec_spawnvpe(l, env): |
||||
|
stat = os.spawnvpe(os.P_WAIT, l[0], l, env) |
||||
|
# os.spawnvpe() returns the actual exit code, not the encoding |
||||
|
# returned by os.waitpid() or os.system(). |
||||
|
return stat |
||||
|
|
||||
|
def exec_fork(l, env): |
||||
|
pid = os.fork() |
||||
|
if not pid: |
||||
|
# Child process. |
||||
|
exitval = 127 |
||||
|
try: |
||||
|
os.execvpe(l[0], l, env) |
||||
|
except OSError, e: |
||||
|
exitval = exitvalmap.get(e[0], e[0]) |
||||
|
sys.stderr.write("scons: %s: %s\n" % (l[0], e[1])) |
||||
|
os._exit(exitval) |
||||
|
else: |
||||
|
# Parent process. |
||||
|
pid, stat = os.waitpid(pid, 0) |
||||
|
if stat & 0xff: |
||||
|
return stat | 0x80 |
||||
|
return stat >> 8 |
||||
|
|
||||
|
def _get_env_command(sh, escape, cmd, args, env): |
||||
|
s = string.join(args) |
||||
|
if env: |
||||
|
l = ['env', '-'] + \ |
||||
|
map(lambda t, e=escape: e(t[0])+'='+e(t[1]), env.items()) + \ |
||||
|
[sh, '-c', escape(s)] |
||||
|
s = string.join(l) |
||||
|
return s |
||||
|
|
||||
|
def env_spawn(sh, escape, cmd, args, env): |
||||
|
return exec_system([_get_env_command( sh, escape, cmd, args, env)], env) |
||||
|
|
||||
|
def spawnvpe_spawn(sh, escape, cmd, args, env): |
||||
|
return exec_spawnvpe([sh, '-c', string.join(args)], env) |
||||
|
|
||||
|
def fork_spawn(sh, escape, cmd, args, env): |
||||
|
return exec_fork([sh, '-c', string.join(args)], env) |
||||
|
|
||||
|
def process_cmd_output(cmd_stdout, cmd_stderr, stdout, stderr): |
||||
|
stdout_eof = stderr_eof = 0 |
||||
|
while not (stdout_eof and stderr_eof): |
||||
|
try: |
||||
|
(i,o,e) = select.select([cmd_stdout, cmd_stderr], [], []) |
||||
|
if cmd_stdout in i: |
||||
|
str = cmd_stdout.read() |
||||
|
if len(str) == 0: |
||||
|
stdout_eof = 1 |
||||
|
elif stdout != None: |
||||
|
stdout.write(str) |
||||
|
if cmd_stderr in i: |
||||
|
str = cmd_stderr.read() |
||||
|
if len(str) == 0: |
||||
|
#sys.__stderr__.write( "stderr_eof=1\n" ) |
||||
|
stderr_eof = 1 |
||||
|
else: |
||||
|
#sys.__stderr__.write( "str(stderr) = %s\n" % str ) |
||||
|
stderr.write(str) |
||||
|
except select.error, (_errno, _strerror): |
||||
|
if _errno != errno.EINTR: |
||||
|
raise |
||||
|
|
||||
|
def exec_popen3(l, env, stdout, stderr): |
||||
|
proc = subprocess.Popen(string.join(l), |
||||
|
stdout=stdout, |
||||
|
stderr=stderr, |
||||
|
shell=True) |
||||
|
stat = proc.wait() |
||||
|
if stat & 0xff: |
||||
|
return stat | 0x80 |
||||
|
return stat >> 8 |
||||
|
|
||||
|
def exec_piped_fork(l, env, stdout, stderr): |
||||
|
# spawn using fork / exec and providing a pipe for the command's |
||||
|
# stdout / stderr stream |
||||
|
if stdout != stderr: |
||||
|
(rFdOut, wFdOut) = os.pipe() |
||||
|
(rFdErr, wFdErr) = os.pipe() |
||||
|
else: |
||||
|
(rFdOut, wFdOut) = os.pipe() |
||||
|
rFdErr = rFdOut |
||||
|
wFdErr = wFdOut |
||||
|
# do the fork |
||||
|
pid = os.fork() |
||||
|
if not pid: |
||||
|
# Child process |
||||
|
os.close( rFdOut ) |
||||
|
if rFdOut != rFdErr: |
||||
|
os.close( rFdErr ) |
||||
|
os.dup2( wFdOut, 1 ) # is there some symbolic way to do that ? |
||||
|
os.dup2( wFdErr, 2 ) |
||||
|
os.close( wFdOut ) |
||||
|
if stdout != stderr: |
||||
|
os.close( wFdErr ) |
||||
|
exitval = 127 |
||||
|
try: |
||||
|
os.execvpe(l[0], l, env) |
||||
|
except OSError, e: |
||||
|
exitval = exitvalmap.get(e[0], e[0]) |
||||
|
stderr.write("scons: %s: %s\n" % (l[0], e[1])) |
||||
|
os._exit(exitval) |
||||
|
else: |
||||
|
# Parent process |
||||
|
pid, stat = os.waitpid(pid, 0) |
||||
|
os.close( wFdOut ) |
||||
|
if stdout != stderr: |
||||
|
os.close( wFdErr ) |
||||
|
childOut = os.fdopen( rFdOut ) |
||||
|
if stdout != stderr: |
||||
|
childErr = os.fdopen( rFdErr ) |
||||
|
else: |
||||
|
childErr = childOut |
||||
|
process_cmd_output(childOut, childErr, stdout, stderr) |
||||
|
os.close( rFdOut ) |
||||
|
if stdout != stderr: |
||||
|
os.close( rFdErr ) |
||||
|
if stat & 0xff: |
||||
|
return stat | 0x80 |
||||
|
return stat >> 8 |
||||
|
|
||||
|
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([_get_env_command(sh, escape, cmd, args, env)], |
||||
|
env, stdout, stderr) |
||||
|
|
||||
|
def piped_fork_spawn(sh, escape, cmd, args, env, stdout, stderr): |
||||
|
# spawn using fork / exec and providing a pipe for the command's |
||||
|
# stdout / stderr stream |
||||
|
return exec_piped_fork([sh, '-c', string.join(args)], |
||||
|
env, stdout, stderr) |
||||
|
|
||||
|
|
||||
|
|
||||
|
def generate(env): |
||||
|
# If os.spawnvpe() exists, we use it to spawn commands. Otherwise |
||||
|
# if the env utility exists, we use os.system() to spawn commands, |
||||
|
# finally we fall back on os.fork()/os.exec(). |
||||
|
# |
||||
|
# os.spawnvpe() is prefered because it is the most efficient. But |
||||
|
# for Python versions without it, os.system() is prefered because it |
||||
|
# is claimed that it works better with threads (i.e. -j) and is more |
||||
|
# efficient than forking Python. |
||||
|
# |
||||
|
# NB: Other people on the scons-users mailing list have claimed that |
||||
|
# os.fork()/os.exec() works better than os.system(). There may just |
||||
|
# not be a default that works best for all users. |
||||
|
|
||||
|
if os.__dict__.has_key('spawnvpe'): |
||||
|
spawn = spawnvpe_spawn |
||||
|
elif env.Detect('env'): |
||||
|
spawn = env_spawn |
||||
|
else: |
||||
|
spawn = fork_spawn |
||||
|
|
||||
|
if env.Detect('env'): |
||||
|
pspawn = piped_env_spawn |
||||
|
else: |
||||
|
pspawn = piped_fork_spawn |
||||
|
|
||||
|
if not env.has_key('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' |
@ -0,0 +1,44 @@ |
|||||
|
"""engine.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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Platform/sunos.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
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' |
@ -0,0 +1,324 @@ |
|||||
|
"""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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Platform/win32.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import os |
||||
|
import os.path |
||||
|
import string |
||||
|
import sys |
||||
|
import tempfile |
||||
|
|
||||
|
from SCons.Platform.posix import exitvalmap |
||||
|
from SCons.Platform import TempFileMunge |
||||
|
import SCons.Util |
||||
|
|
||||
|
|
||||
|
|
||||
|
try: |
||||
|
import msvcrt |
||||
|
import win32api |
||||
|
import win32con |
||||
|
|
||||
|
msvcrt.get_osfhandle |
||||
|
win32api.SetHandleInformation |
||||
|
win32con.HANDLE_FLAG_INHERIT |
||||
|
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 |
||||
|
|
||||
|
import __builtin__ |
||||
|
|
||||
|
_builtin_file = __builtin__.file |
||||
|
_builtin_open = __builtin__.open |
||||
|
|
||||
|
def _scons_file(*args, **kw): |
||||
|
fp = apply(_builtin_file, args, kw) |
||||
|
win32api.SetHandleInformation(msvcrt.get_osfhandle(fp.fileno()), |
||||
|
win32con.HANDLE_FLAG_INHERIT, |
||||
|
0) |
||||
|
return fp |
||||
|
|
||||
|
def _scons_open(*args, **kw): |
||||
|
fp = apply(_builtin_open, args, kw) |
||||
|
win32api.SetHandleInformation(msvcrt.get_osfhandle(fp.fileno()), |
||||
|
win32con.HANDLE_FLAG_INHERIT, |
||||
|
0) |
||||
|
return fp |
||||
|
|
||||
|
__builtin__.file = _scons_file |
||||
|
__builtin__.open = _scons_open |
||||
|
|
||||
|
|
||||
|
|
||||
|
# 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 |
||||
|
if not sh: |
||||
|
sys.stderr.write("scons: Could not find command interpreter, is it in your PATH?\n") |
||||
|
return 127 |
||||
|
else: |
||||
|
# one temporary file for stdout and stderr |
||||
|
tmpFileStdout = os.path.normpath(tempfile.mktemp()) |
||||
|
tmpFileStderr = os.path.normpath(tempfile.mktemp()) |
||||
|
|
||||
|
# check if output is redirected |
||||
|
stdoutRedirected = 0 |
||||
|
stderrRedirected = 0 |
||||
|
for arg in args: |
||||
|
# are there more possibilities to redirect stdout ? |
||||
|
if (string.find( arg, ">", 0, 1 ) != -1 or |
||||
|
string.find( arg, "1>", 0, 2 ) != -1): |
||||
|
stdoutRedirected = 1 |
||||
|
# are there more possibilities to redirect stderr ? |
||||
|
if string.find( arg, "2>", 0, 2 ) != -1: |
||||
|
stderrRedirected = 1 |
||||
|
|
||||
|
# redirect output of non-redirected streams to our tempfiles |
||||
|
if stdoutRedirected == 0: |
||||
|
args.append(">" + str(tmpFileStdout)) |
||||
|
if stderrRedirected == 0: |
||||
|
args.append("2>" + str(tmpFileStderr)) |
||||
|
|
||||
|
# actually do the spawn |
||||
|
try: |
||||
|
args = [sh, '/C', escape(string.join(args)) ] |
||||
|
ret = os.spawnve(os.P_WAIT, sh, args, env) |
||||
|
except OSError, e: |
||||
|
# catch any error |
||||
|
try: |
||||
|
ret = exitvalmap[e[0]] |
||||
|
except KeyError: |
||||
|
sys.stderr.write("scons: unknown OSError exception code %d - %s: %s\n" % (e[0], cmd, e[1])) |
||||
|
if stderr != None: |
||||
|
stderr.write("scons: %s: %s\n" % (cmd, e[1])) |
||||
|
# copy child output from tempfiles to our streams |
||||
|
# and do clean up stuff |
||||
|
if stdout != None and stdoutRedirected == 0: |
||||
|
try: |
||||
|
stdout.write(open( tmpFileStdout, "r" ).read()) |
||||
|
os.remove( tmpFileStdout ) |
||||
|
except (IOError, OSError): |
||||
|
pass |
||||
|
|
||||
|
if stderr != None and stderrRedirected == 0: |
||||
|
try: |
||||
|
stderr.write(open( tmpFileStderr, "r" ).read()) |
||||
|
os.remove( tmpFileStderr ) |
||||
|
except (IOError, OSError): |
||||
|
pass |
||||
|
return ret |
||||
|
|
||||
|
def exec_spawn(l, env): |
||||
|
try: |
||||
|
result = os.spawnve(os.P_WAIT, l[0], l, env) |
||||
|
except OSError, e: |
||||
|
try: |
||||
|
result = exitvalmap[e[0]] |
||||
|
sys.stderr.write("scons: %s: %s\n" % (l[0], e[1])) |
||||
|
except KeyError: |
||||
|
result = 127 |
||||
|
if len(l) > 2: |
||||
|
if len(l[2]) < 1000: |
||||
|
command = string.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[0], command, e[1])) |
||||
|
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(string.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 |
||||
|
def get_system_root(): |
||||
|
# A resonable default if we can't read the registry |
||||
|
try: |
||||
|
val = os.environ['SYSTEMROOT'] |
||||
|
except KeyError: |
||||
|
val = "C:/WINDOWS" |
||||
|
pass |
||||
|
|
||||
|
# 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') |
||||
|
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 |
||||
|
return val |
||||
|
|
||||
|
# Get the location of the program files directory |
||||
|
def get_program_files_dir(): |
||||
|
# 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 |
||||
|
|
||||
|
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 = r'C:\Windows' |
||||
|
if os.environ.has_key('SYSTEMROOT'): |
||||
|
systemroot = os.environ['SYSTEMROOT'] |
||||
|
tmp_path = systemroot + os.pathsep + \ |
||||
|
os.path.join(systemroot,'System32') |
||||
|
tmp_pathext = '.com;.exe;.bat;.cmd' |
||||
|
if os.environ.has_key('PATHEXT'): |
||||
|
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 not env.has_key('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 |
||||
|
|
||||
|
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 |
File diff suppressed because it is too large
@ -0,0 +1,375 @@ |
|||||
|
"""SCons.SConsign |
||||
|
|
||||
|
Writing and reading information to the .sconsign file or files. |
||||
|
|
||||
|
""" |
||||
|
|
||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/SConsign.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import cPickle |
||||
|
import os |
||||
|
import os.path |
||||
|
|
||||
|
import SCons.dblite |
||||
|
import SCons.Warnings |
||||
|
|
||||
|
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 anydbm modules have sync() methods. |
||||
|
else: |
||||
|
syncmethod() |
||||
|
|
||||
|
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. |
||||
|
""" |
||||
|
current_version_id = 1 |
||||
|
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 |
||||
|
def convert_to_sconsign(self): |
||||
|
self.binfo.convert_to_sconsign() |
||||
|
def convert_from_sconsign(self, dir, name): |
||||
|
self.binfo.convert_from_sconsign(dir, name) |
||||
|
|
||||
|
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.tpath) |
||||
|
try: |
||||
|
rawentries = db[path] |
||||
|
except KeyError: |
||||
|
pass |
||||
|
else: |
||||
|
try: |
||||
|
self.entries = cPickle.loads(rawentries) |
||||
|
if type(self.entries) is not type({}): |
||||
|
self.entries = {} |
||||
|
raise TypeError |
||||
|
except KeyboardInterrupt: |
||||
|
raise |
||||
|
except Exception, e: |
||||
|
SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning, |
||||
|
"Ignoring corrupt sconsign entry : %s (%s)\n"%(self.dir.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.path) |
||||
|
for key, entry in self.entries.items(): |
||||
|
entry.convert_to_sconsign() |
||||
|
db[path] = cPickle.dumps(self.entries, 1) |
||||
|
|
||||
|
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 = cPickle.load(fp) |
||||
|
if type(self.entries) is not type({}): |
||||
|
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.path, '.sconsign') |
||||
|
|
||||
|
try: |
||||
|
fp = open(self.sconsign, 'rb') |
||||
|
except IOError: |
||||
|
fp = None |
||||
|
|
||||
|
try: |
||||
|
Dir.__init__(self, fp, dir) |
||||
|
except KeyboardInterrupt: |
||||
|
raise |
||||
|
except: |
||||
|
SCons.Warnings.warn(SCons.Warnings.CorruptSConsignWarning, |
||||
|
"Ignoring corrupt .sconsign file: %s"%self.sconsign) |
||||
|
|
||||
|
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.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() |
||||
|
cPickle.dump(self.entries, file, 1) |
||||
|
file.close() |
||||
|
if fname != self.sconsign: |
||||
|
try: |
||||
|
mode = os.stat(self.sconsign)[0] |
||||
|
os.chmod(self.sconsign, 0666) |
||||
|
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. |
||||
|
open(self.sconsign, 'wb').write(open(fname, 'rb').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 not dbm_module is None: |
||||
|
DB_Module = dbm_module |
@ -0,0 +1,126 @@ |
|||||
|
"""SCons.Scanner.C |
||||
|
|
||||
|
This module implements the depenency scanner for C/C++ code. |
||||
|
|
||||
|
""" |
||||
|
|
||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Scanner/C.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
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): |
||||
|
apply(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: |
||||
|
fp = open(str(file.rfile())) |
||||
|
except EnvironmentError, e: |
||||
|
self.missing.append((file, self.current_file)) |
||||
|
return '' |
||||
|
else: |
||||
|
return fp.read() |
||||
|
|
||||
|
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 |
@ -0,0 +1,68 @@ |
|||||
|
"""SCons.Scanner.D |
||||
|
|
||||
|
Scanner for the Digital Mars "D" programming language. |
||||
|
|
||||
|
Coded by Andy Friesen |
||||
|
17 Nov 2003 |
||||
|
|
||||
|
""" |
||||
|
|
||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Scanner/D.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import re |
||||
|
import string |
||||
|
|
||||
|
import SCons.Scanner |
||||
|
|
||||
|
def DScanner(): |
||||
|
"""Return a prototype Scanner instance for scanning D source files""" |
||||
|
ds = D() |
||||
|
return ds |
||||
|
|
||||
|
class D(SCons.Scanner.Classic): |
||||
|
def __init__ (self): |
||||
|
SCons.Scanner.Classic.__init__ (self, |
||||
|
name = "DScanner", |
||||
|
suffixes = '$DSUFFIXES', |
||||
|
path_variable = 'DPATH', |
||||
|
regex = 'import\s+(?:[a-zA-Z0-9_.]+)\s*(?:,\s*(?:[a-zA-Z0-9_.]+)\s*)*;') |
||||
|
|
||||
|
self.cre2 = re.compile ('(?:import\s)?\s*([a-zA-Z0-9_.]+)\s*(?:,|;)', re.M) |
||||
|
|
||||
|
def find_include(self, include, source_dir, path): |
||||
|
# translate dots (package separators) to slashes |
||||
|
inc = string.replace(include, '.', '/') |
||||
|
|
||||
|
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 i in self.cre.findall(node.get_contents()): |
||||
|
includes = includes + self.cre2.findall(i) |
||||
|
return includes |
@ -0,0 +1,105 @@ |
|||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Scanner/Dir.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons.Node.FS |
||||
|
import SCons.Scanner |
||||
|
|
||||
|
def only_dirs(nodes): |
||||
|
is_Dir = lambda n: isinstance(n.disambiguate(), SCons.Node.FS.Dir) |
||||
|
return filter(is_Dir, nodes) |
||||
|
|
||||
|
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 apply(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 apply(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: not skip_entry.has_key(k) |
||||
|
|
||||
|
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.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 = filter(do_not_scan, entries.keys()) |
||||
|
entry_list.sort() |
||||
|
return map(lambda n, e=entries: e[n], entry_list) |
@ -0,0 +1,314 @@ |
|||||
|
"""SCons.Scanner.Fortran |
||||
|
|
||||
|
This module implements the dependency scanner for Fortran code. |
||||
|
|
||||
|
""" |
||||
|
|
||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Scanner/Fortran.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import re |
||||
|
import string |
||||
|
|
||||
|
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 |
||||
|
|
||||
|
apply(SCons.Scanner.Current.__init__, (self,) + args, kw) |
||||
|
|
||||
|
def scan(self, node, env, path=()): |
||||
|
|
||||
|
# cache the includes list in node so we only scan it once: |
||||
|
if node.includes != None: |
||||
|
mods_and_includes = node.includes |
||||
|
else: |
||||
|
# retrieve all included filenames |
||||
|
includes = self.cre_incl.findall(node.get_contents()) |
||||
|
# retrieve all USE'd module names |
||||
|
modules = self.cre_use.findall(node.get_contents()) |
||||
|
# retrieve all defined module names |
||||
|
defmodules = self.cre_def.findall(node.get_contents()) |
||||
|
|
||||
|
# Remove all USE'd module names that are defined in the same file |
||||
|
d = {} |
||||
|
for m in defmodules: |
||||
|
d[m] = 1 |
||||
|
modules = filter(lambda m, d=d: not d.has_key(m), modules) |
||||
|
#modules = self.undefinedModules(modules, defmodules) |
||||
|
|
||||
|
# Convert module name to a .mod filename |
||||
|
suffix = env.subst('$FORTRANMODSUFFIX') |
||||
|
modules = map(lambda x, s=suffix: string.lower(x) + s, 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)) |
||||
|
|
||||
|
nodes.sort() |
||||
|
nodes = map(lambda pair: pair[1], nodes) |
||||
|
return nodes |
||||
|
|
||||
|
def FortranScan(path_variable="FORTRANPATH"): |
||||
|
"""Return a prototype Scanner instance for scanning source files |
||||
|
for Fortran USE & INCLUDE statements""" |
||||
|
|
||||
|
# The USE statement regex matches the following: |
||||
|
# |
||||
|
# USE module_name |
||||
|
# USE :: module_name |
||||
|
# USE, INTRINSIC :: module_name |
||||
|
# USE, NON_INTRINSIC :: module_name |
||||
|
# |
||||
|
# Limitations |
||||
|
# |
||||
|
# -- While the regex can handle multiple USE statements on one line, |
||||
|
# it cannot properly handle them if they are commented out. |
||||
|
# In either of the following cases: |
||||
|
# |
||||
|
# ! USE mod_a ; USE mod_b [entire line is commented out] |
||||
|
# USE mod_a ! ; USE mod_b [in-line comment of second USE statement] |
||||
|
# |
||||
|
# the second module name (mod_b) will be picked up as a dependency |
||||
|
# even though it should be ignored. The only way I can see |
||||
|
# to rectify this would be to modify the scanner to eliminate |
||||
|
# the call to re.findall, read in the contents of the file, |
||||
|
# treating the comment character as an end-of-line character |
||||
|
# in addition to the normal linefeed, loop over each line, |
||||
|
# weeding out the comments, and looking for the USE statements. |
||||
|
# One advantage to this is that the regex passed to the scanner |
||||
|
# would no longer need to match a semicolon. |
||||
|
# |
||||
|
# -- I question whether or not we need to detect dependencies to |
||||
|
# INTRINSIC modules because these are built-in to the compiler. |
||||
|
# If we consider them a dependency, will SCons look for them, not |
||||
|
# find them, and kill the build? Or will we there be standard |
||||
|
# compiler-specific directories we will need to point to so the |
||||
|
# compiler and SCons can locate the proper object and mod files? |
||||
|
|
||||
|
# Here is a breakdown of the regex: |
||||
|
# |
||||
|
# (?i) : regex is case insensitive |
||||
|
# ^ : start of line |
||||
|
# (?: : group a collection of regex symbols without saving the match as a "group" |
||||
|
# ^|; : matches either the start of the line or a semicolon - semicolon |
||||
|
# ) : end the unsaved grouping |
||||
|
# \s* : any amount of white space |
||||
|
# USE : match the string USE, case insensitive |
||||
|
# (?: : group a collection of regex symbols without saving the match as a "group" |
||||
|
# \s+| : match one or more whitespace OR .... (the next entire grouped set of regex symbols) |
||||
|
# (?: : group a collection of regex symbols without saving the match as a "group" |
||||
|
# (?: : establish another unsaved grouping of regex symbols |
||||
|
# \s* : any amount of white space |
||||
|
# , : match a comma |
||||
|
# \s* : any amount of white space |
||||
|
# (?:NON_)? : optionally match the prefix NON_, case insensitive |
||||
|
# INTRINSIC : match the string INTRINSIC, case insensitive |
||||
|
# )? : optionally match the ", INTRINSIC/NON_INTRINSIC" grouped expression |
||||
|
# \s* : any amount of white space |
||||
|
# :: : match a double colon that must appear after the INTRINSIC/NON_INTRINSIC attribute |
||||
|
# ) : end the unsaved grouping |
||||
|
# ) : end the unsaved grouping |
||||
|
# \s* : match any amount of white space |
||||
|
# (\w+) : match the module name that is being USE'd |
||||
|
# |
||||
|
# |
||||
|
use_regex = "(?i)(?:^|;)\s*USE(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(\w+)" |
||||
|
|
||||
|
|
||||
|
# The INCLUDE statement regex matches the following: |
||||
|
# |
||||
|
# INCLUDE 'some_Text' |
||||
|
# INCLUDE "some_Text" |
||||
|
# INCLUDE "some_Text" ; INCLUDE "some_Text" |
||||
|
# INCLUDE kind_"some_Text" |
||||
|
# INCLUDE kind_'some_Text" |
||||
|
# |
||||
|
# where some_Text can include any alphanumeric and/or special character |
||||
|
# as defined by the Fortran 2003 standard. |
||||
|
# |
||||
|
# Limitations: |
||||
|
# |
||||
|
# -- The Fortran standard dictates that a " or ' in the INCLUDE'd |
||||
|
# string must be represented as a "" or '', if the quotes that wrap |
||||
|
# the entire string are either a ' or ", respectively. While the |
||||
|
# regular expression below can detect the ' or " characters just fine, |
||||
|
# the scanning logic, presently is unable to detect them and reduce |
||||
|
# them to a single instance. This probably isn't an issue since, |
||||
|
# in practice, ' or " are not generally used in filenames. |
||||
|
# |
||||
|
# -- This regex will not properly deal with multiple INCLUDE statements |
||||
|
# when the entire line has been commented out, ala |
||||
|
# |
||||
|
# ! INCLUDE 'some_file' ; INCLUDE 'some_file' |
||||
|
# |
||||
|
# In such cases, it will properly ignore the first INCLUDE file, |
||||
|
# but will actually still pick up the second. Interestingly enough, |
||||
|
# the regex will properly deal with these cases: |
||||
|
# |
||||
|
# INCLUDE 'some_file' |
||||
|
# INCLUDE 'some_file' !; INCLUDE 'some_file' |
||||
|
# |
||||
|
# To get around the above limitation, the FORTRAN programmer could |
||||
|
# simply comment each INCLUDE statement separately, like this |
||||
|
# |
||||
|
# ! INCLUDE 'some_file' !; INCLUDE 'some_file' |
||||
|
# |
||||
|
# The way I see it, the only way to get around this limitation would |
||||
|
# be to modify the scanning logic to replace the calls to re.findall |
||||
|
# with a custom loop that processes each line separately, throwing |
||||
|
# away fully commented out lines before attempting to match against |
||||
|
# the INCLUDE syntax. |
||||
|
# |
||||
|
# Here is a breakdown of the regex: |
||||
|
# |
||||
|
# (?i) : regex is case insensitive |
||||
|
# (?: : begin a non-saving group that matches the following: |
||||
|
# ^ : either the start of the line |
||||
|
# | : or |
||||
|
# ['">]\s*; : a semicolon that follows a single quote, |
||||
|
# double quote or greater than symbol (with any |
||||
|
# amount of whitespace in between). This will |
||||
|
# allow the regex to match multiple INCLUDE |
||||
|
# statements per line (although it also requires |
||||
|
# the positive lookahead assertion that is |
||||
|
# used below). It will even properly deal with |
||||
|
# (i.e. ignore) cases in which the additional |
||||
|
# INCLUDES are part of an in-line comment, ala |
||||
|
# " INCLUDE 'someFile' ! ; INCLUDE 'someFile2' " |
||||
|
# ) : end of non-saving group |
||||
|
# \s* : any amount of white space |
||||
|
# INCLUDE : match the string INCLUDE, case insensitive |
||||
|
# \s+ : match one or more white space characters |
||||
|
# (?\w+_)? : match the optional "kind-param _" prefix allowed by the standard |
||||
|
# [<"'] : match the include delimiter - an apostrophe, double quote, or less than symbol |
||||
|
# (.+?) : match one or more characters that make up |
||||
|
# the included path and file name and save it |
||||
|
# in a group. The Fortran standard allows for |
||||
|
# any non-control character to be used. The dot |
||||
|
# operator will pick up any character, including |
||||
|
# control codes, but I can't conceive of anyone |
||||
|
# putting control codes in their file names. |
||||
|
# The question mark indicates it is non-greedy so |
||||
|
# that regex will match only up to the next quote, |
||||
|
# double quote, or greater than symbol |
||||
|
# (?=["'>]) : positive lookahead assertion to match the include |
||||
|
# delimiter - an apostrophe, double quote, or |
||||
|
# greater than symbol. This level of complexity |
||||
|
# is required so that the include delimiter is |
||||
|
# not consumed by the match, thus allowing the |
||||
|
# sub-regex discussed above to uniquely match a |
||||
|
# set of semicolon-separated INCLUDE statements |
||||
|
# (as allowed by the F2003 standard) |
||||
|
|
||||
|
include_regex = """(?i)(?:^|['">]\s*;)\s*INCLUDE\s+(?:\w+_)?[<"'](.+?)(?=["'>])""" |
||||
|
|
||||
|
# The MODULE statement regex finds module definitions by matching |
||||
|
# the following: |
||||
|
# |
||||
|
# MODULE module_name |
||||
|
# |
||||
|
# but *not* the following: |
||||
|
# |
||||
|
# MODULE PROCEDURE procedure_name |
||||
|
# |
||||
|
# Here is a breakdown of the regex: |
||||
|
# |
||||
|
# (?i) : regex is case insensitive |
||||
|
# ^\s* : any amount of white space |
||||
|
# MODULE : match the string MODULE, case insensitive |
||||
|
# \s+ : match one or more white space characters |
||||
|
# (?!PROCEDURE) : but *don't* match if the next word matches |
||||
|
# PROCEDURE (negative lookahead assertion), |
||||
|
# case insensitive |
||||
|
# (\w+) : match one or more alphanumeric characters |
||||
|
# that make up the defined module name and |
||||
|
# save it in a group |
||||
|
|
||||
|
def_regex = """(?i)^\s*MODULE\s+(?!PROCEDURE)(\w+)""" |
||||
|
|
||||
|
scanner = F90Scanner("FortranScan", |
||||
|
"$FORTRANSUFFIXES", |
||||
|
path_variable, |
||||
|
use_regex, |
||||
|
include_regex, |
||||
|
def_regex) |
||||
|
return scanner |
@ -0,0 +1,42 @@ |
|||||
|
"""SCons.Scanner.IDL |
||||
|
|
||||
|
This module implements the depenency scanner for IDL (Interface |
||||
|
Definition Language) files. |
||||
|
|
||||
|
""" |
||||
|
|
||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Scanner/IDL.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
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 |
@ -0,0 +1,334 @@ |
|||||
|
"""SCons.Scanner.LaTeX |
||||
|
|
||||
|
This module implements the dependency scanner for LaTeX code. |
||||
|
|
||||
|
""" |
||||
|
|
||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Scanner/LaTeX.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import os.path |
||||
|
import string |
||||
|
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'] |
||||
|
|
||||
|
# 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]): |
||||
|
#TODO(1.5) |
||||
|
#env.PrependENVPath(var, [os.path.abspath(str(p)) for p in env[var]]) |
||||
|
env.PrependENVPath(var, map(lambda p: os.path.abspath(str(p)), env[var])) |
||||
|
else: |
||||
|
# Split at os.pathsep to convert into absolute path |
||||
|
#TODO(1.5) env.PrependENVPath(var, [os.path.abspath(p) for p in str(env[var]).split(os.pathsep)]) |
||||
|
env.PrependENVPath(var, map(lambda p: os.path.abspath(p), string.split(str(env[var]), 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]): |
||||
|
# TODO(1.5) |
||||
|
#env['ENV'][var] = os.pathsep.join(env['ENV'][var]) |
||||
|
env['ENV'][var] = string.join(env['ENV'][var], os.pathsep) |
||||
|
# 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 *PATH variable name to a function that |
||||
|
will return all of the *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['BIBINPUTS'] for "bibliography" keyword |
||||
|
env['BSTINPUTS'] for "bibliographystyle" keyword |
||||
|
|
||||
|
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', |
||||
|
'usepackage': 'TEXINPUTS'} |
||||
|
env_variables = SCons.Util.unique(keyword_paths.values()) |
||||
|
|
||||
|
def __init__(self, name, suffixes, graphics_extensions, *args, **kw): |
||||
|
|
||||
|
# We have to include \n with the % we exclude from the first part |
||||
|
# part of the regex because the expression is compiled with re.M. |
||||
|
# Without the \n, the ^ could match the beginning of a *previous* |
||||
|
# line followed by one or more newline characters (i.e. blank |
||||
|
# lines), interfering with a match on the next line. |
||||
|
regex = r'^[^%\n]*\\(include|includegraphics(?:\[[^\]]+\])?|input|bibliography|usepackage){([^}]*)}' |
||||
|
self.cre = re.compile(regex, 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(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'] = 1 |
||||
|
kw['skeys'] = suffixes |
||||
|
kw['scan_check'] = LaTeXScanCheck(suffixes) |
||||
|
kw['name'] = name |
||||
|
|
||||
|
apply(SCons.Scanner.Base.__init__, (self,) + args, kw) |
||||
|
|
||||
|
def _latex_names(self, include): |
||||
|
filename = include[1] |
||||
|
if include[0] == 'input': |
||||
|
base, ext = os.path.splitext( filename ) |
||||
|
if ext == "": |
||||
|
return [filename + '.tex'] |
||||
|
if (include[0] == 'include'): |
||||
|
return [filename + '.tex'] |
||||
|
if include[0] == 'bibliography': |
||||
|
base, ext = os.path.splitext( filename ) |
||||
|
if ext == "": |
||||
|
return [filename + '.bib'] |
||||
|
if include[0] == 'usepackage': |
||||
|
base, ext = os.path.splitext( filename ) |
||||
|
if ext == "": |
||||
|
return [filename + '.sty'] |
||||
|
if include[0] == 'includegraphics': |
||||
|
base, ext = os.path.splitext( filename ) |
||||
|
if ext == "": |
||||
|
#TODO(1.5) return [filename + e for e in self.graphics_extensions] |
||||
|
return map(lambda e, f=filename: f+e, 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): |
||||
|
try: |
||||
|
sub_path = path[include[0]] |
||||
|
except (IndexError, KeyError): |
||||
|
sub_path = () |
||||
|
try_names = self._latex_names(include) |
||||
|
for n in try_names: |
||||
|
# see if we find it using the path in env[var] |
||||
|
i = SCons.Node.FS.find_file(n, (source_dir,) + sub_path[0]) |
||||
|
if i: |
||||
|
return i, include |
||||
|
# see if we find it using the path in env['ENV'][var] |
||||
|
i = SCons.Node.FS.find_file(n, (source_dir,) + sub_path[1]) |
||||
|
if i: |
||||
|
return i, include |
||||
|
return i, include |
||||
|
|
||||
|
def scan(self, node, path=()): |
||||
|
# 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)) |
||||
|
noopt_cre = re.compile('\[.*$') |
||||
|
if node.includes != None: |
||||
|
includes = node.includes |
||||
|
else: |
||||
|
includes = self.cre.findall(node.get_contents()) |
||||
|
# 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_list = string.split(include[1],',') |
||||
|
for j in range(len(inc_list)): |
||||
|
split_includes.append( (inc_type, inc_list[j]) ) |
||||
|
# |
||||
|
includes = split_includes |
||||
|
node.includes = 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, \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: |
||||
|
# |
||||
|
# 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 include[0] != '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)) |
||||
|
# |
||||
|
nodes.sort() |
||||
|
nodes = map(lambda pair: pair[1], nodes) |
||||
|
return nodes |
@ -0,0 +1,97 @@ |
|||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Scanner/Prog.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import string |
||||
|
|
||||
|
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 = apply(SCons.Scanner.Base, [scan, "ProgramScanner"], kw) |
||||
|
return ps |
||||
|
|
||||
|
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 [] |
||||
|
if SCons.Util.is_String(libs): |
||||
|
libs = string.split(libs) |
||||
|
else: |
||||
|
libs = SCons.Util.flatten(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): |
||||
|
lib = env.subst(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 |
@ -0,0 +1,49 @@ |
|||||
|
"""SCons.Scanner.RC |
||||
|
|
||||
|
This module implements the depenency scanner for RC (Interface |
||||
|
Definition Language) files. |
||||
|
|
||||
|
""" |
||||
|
|
||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Scanner/RC.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons.Node.FS |
||||
|
import SCons.Scanner |
||||
|
import re |
||||
|
|
||||
|
def RCScan(): |
||||
|
"""Return a prototype Scanner instance for scanning RC source files""" |
||||
|
|
||||
|
res_re= r'^(?:\s*#\s*(?:include)|' \ |
||||
|
'.*?\s+(?:ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)' \ |
||||
|
'\s*.*?)' \ |
||||
|
'\s*(<|"| )([^>"\s]+)(?:[>" ])*$' |
||||
|
resScanner = SCons.Scanner.ClassicCPP( "ResourceScanner", |
||||
|
"$RCSUFFIXES", |
||||
|
"CPPPATH", |
||||
|
res_re ) |
||||
|
|
||||
|
return resScanner |
@ -0,0 +1,406 @@ |
|||||
|
"""SCons.Scanner |
||||
|
|
||||
|
The Scanner package for the SCons software construction utility. |
||||
|
|
||||
|
""" |
||||
|
|
||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Scanner/__init__.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import re |
||||
|
import string |
||||
|
|
||||
|
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 apply(Selector, (function,) + args, kw) |
||||
|
else: |
||||
|
return apply(Base, (function,) + args, kw) |
||||
|
|
||||
|
|
||||
|
|
||||
|
class FindPathDirs: |
||||
|
"""A class to bind a specific *PATH variable name to a function that |
||||
|
will return all of the *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_class = SCons.Node.FS.Entry, |
||||
|
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 = 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 not self.argument is _null: |
||||
|
return self.path_function(env, dir, target, source, self.argument) |
||||
|
else: |
||||
|
return self.path_function(env, dir, target, source) |
||||
|
|
||||
|
def __call__(self, node, env, path = ()): |
||||
|
""" |
||||
|
This method scans a single object. 'node' is the node |
||||
|
that will be passed to the scanner function, and 'env' is the |
||||
|
environment that will be passed to the scanner function. A list of |
||||
|
direct dependency nodes for the specified node will be returned. |
||||
|
""" |
||||
|
if self.scan_check and not self.scan_check(node, env): |
||||
|
return [] |
||||
|
|
||||
|
self = self.select(node) |
||||
|
|
||||
|
if not self.argument is _null: |
||||
|
list = self.function(node, env, path, self.argument) |
||||
|
else: |
||||
|
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 list: |
||||
|
if self.node_class and not isinstance(l, self.node_class): |
||||
|
l = apply(node_factory, (l,), kw) |
||||
|
nodes.append(l) |
||||
|
return nodes |
||||
|
|
||||
|
def __cmp__(self, other): |
||||
|
try: |
||||
|
return cmp(self.__dict__, other.__dict__) |
||||
|
except AttributeError: |
||||
|
# other probably doesn't have a __dict__ |
||||
|
return cmp(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): |
||||
|
apply(Base.__init__, (self, None,)+args, kw) |
||||
|
self.dict = dict |
||||
|
self.skeys = 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 |
||||
|
apply(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, env, 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) |
||||
|
kw['recursive'] = 1 |
||||
|
kw['skeys'] = suffixes |
||||
|
kw['name'] = name |
||||
|
|
||||
|
apply(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_contents()) |
||||
|
|
||||
|
def scan(self, node, path=()): |
||||
|
|
||||
|
# cache the includes list in node so we only scan it once: |
||||
|
if node.includes != None: |
||||
|
includes = node.includes |
||||
|
else: |
||||
|
includes = self.find_include_names (node) |
||||
|
node.includes = 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: |
||||
|
sortkey = self.sort_key(include) |
||||
|
nodes.append((sortkey, n)) |
||||
|
|
||||
|
nodes.sort() |
||||
|
nodes = map(lambda pair: pair[1], nodes) |
||||
|
return 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): |
||||
|
if include[0] == '"': |
||||
|
paths = (source_dir,) + tuple(path) |
||||
|
else: |
||||
|
paths = tuple(path) + (source_dir,) |
||||
|
|
||||
|
n = SCons.Node.FS.find_file(include[1], paths) |
||||
|
|
||||
|
return n, include[1] |
||||
|
|
||||
|
def sort_key(self, include): |
||||
|
return SCons.Node.FS._my_normcase(string.join(include)) |
@ -0,0 +1,376 @@ |
|||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Script/Interactive.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
__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 string |
||||
|
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 = string.strip(line) |
||||
|
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 = string.replace(line, '\\', '\\\\') |
||||
|
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 not seen_nodes.has_key(node) |
||||
|
return filter(is_unseen, node.children(scan=1)) |
||||
|
|
||||
|
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.next() |
||||
|
while n: |
||||
|
n = walker.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') |
||||
|
lines = string.split(s, '\n') |
||||
|
spaces = re.match(' *', lines[0]).group(0) |
||||
|
#def strip_spaces(l): |
||||
|
# if l.startswith(spaces): |
||||
|
# l = l[len(spaces):] |
||||
|
# return l |
||||
|
#return '\n'.join([ strip_spaces(l) for l in lines ]) |
||||
|
def strip_spaces(l, spaces=spaces): |
||||
|
if l[:len(spaces)] == spaces: |
||||
|
l = l[len(spaces):] |
||||
|
return l |
||||
|
lines = map(strip_spaces, lines) |
||||
|
return string.join(lines, '\n') |
||||
|
|
||||
|
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: |
||||
|
p = subprocess.Popen(argv) |
||||
|
except EnvironmentError, 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() |
File diff suppressed because it is too large
@ -0,0 +1,940 @@ |
|||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Script/SConsOptions.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import optparse |
||||
|
import re |
||||
|
import string |
||||
|
import sys |
||||
|
import textwrap |
||||
|
|
||||
|
try: |
||||
|
no_hyphen_re = re.compile(r'(\s+|(?<=[\w\!\"\'\&\.\,\?])-{2,}(?=\w))') |
||||
|
except re.error: |
||||
|
# Pre-2.0 Python versions don't have the (?<= negative |
||||
|
# look-behind assertion. |
||||
|
no_hyphen_re = re.compile(r'(\s+|-*\w{2,}-(?=\w{2,}))') |
||||
|
|
||||
|
try: |
||||
|
from gettext import gettext |
||||
|
except ImportError: |
||||
|
def gettext(message): |
||||
|
return message |
||||
|
_ = gettext |
||||
|
|
||||
|
import SCons.Node.FS |
||||
|
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 = string.split(value, ',') |
||||
|
result = [] |
||||
|
for v in map(string.lower, value): |
||||
|
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: |
||||
|
return getattr(self.__dict__['__defaults__'], attr) |
||||
|
|
||||
|
settable = [ |
||||
|
'clean', |
||||
|
'diskcheck', |
||||
|
'duplicate', |
||||
|
'help', |
||||
|
'implicit_cache', |
||||
|
'max_drift', |
||||
|
'md5_chunksize', |
||||
|
'no_exec', |
||||
|
'num_jobs', |
||||
|
'random', |
||||
|
'stack_size', |
||||
|
'warn', |
||||
|
] |
||||
|
|
||||
|
def set_option(self, name, value): |
||||
|
""" |
||||
|
Sets an option from an SConscript file. |
||||
|
""" |
||||
|
if not name 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 not value 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, v: |
||||
|
raise SCons.Errors.UserError, "Not a valid diskcheck value: %s"%v |
||||
|
if not self.__dict__.has_key('diskcheck'): |
||||
|
# 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) |
||||
|
|
||||
|
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(map(lambda v, o=opt, s=self: s.check_value(o, v), 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] |
||||
|
|
||||
|
try: |
||||
|
_orig_CONST_ACTIONS = optparse.Option.CONST_ACTIONS |
||||
|
|
||||
|
_orig_CHECK_METHODS = optparse.Option.CHECK_METHODS |
||||
|
|
||||
|
except AttributeError: |
||||
|
# optparse.Option had no CONST_ACTIONS before Python 2.5. |
||||
|
|
||||
|
_orig_CONST_ACTIONS = ("store_const",) |
||||
|
|
||||
|
def _check_const(self): |
||||
|
if self.action not in self.CONST_ACTIONS and self.const is not None: |
||||
|
raise OptionError( |
||||
|
"'const' must not be supplied for action %r" % self.action, |
||||
|
self) |
||||
|
|
||||
|
# optparse.Option collects its list of unbound check functions |
||||
|
# up front. This sucks because it means we can't just override |
||||
|
# the _check_const() function like a normal method, we have to |
||||
|
# actually replace it in the list. This seems to be the most |
||||
|
# straightforward way to do that. |
||||
|
|
||||
|
_orig_CHECK_METHODS = [optparse.Option._check_action, |
||||
|
optparse.Option._check_type, |
||||
|
optparse.Option._check_choice, |
||||
|
optparse.Option._check_dest, |
||||
|
_check_const, |
||||
|
optparse.Option._check_nargs, |
||||
|
optparse.Option._check_callback] |
||||
|
|
||||
|
CHECK_METHODS = _orig_CHECK_METHODS + [_check_nargs_optional] |
||||
|
|
||||
|
CONST_ACTIONS = _orig_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): |
||||
|
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) = string.split(arg, "=", 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: |
||||
|
self.error(_("%s option requires an argument") % opt) |
||||
|
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 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 = apply(group.add_option, args, kw) |
||||
|
|
||||
|
if result: |
||||
|
# The option was added succesfully. 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.parse_args(self.largs, self.values) |
||||
|
|
||||
|
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': |
||||
|
# The versions of optparse.py shipped with Pythons 2.3 and |
||||
|
# 2.4 pass this in uncapitalized; override that so we get |
||||
|
# consistent output on all versions. |
||||
|
heading = "Options" |
||||
|
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 = [] |
||||
|
|
||||
|
try: |
||||
|
opts = self.option_strings[option] |
||||
|
except AttributeError: |
||||
|
# The Python 2.3 version of optparse attaches this to |
||||
|
# to the option argument, not to this object. |
||||
|
opts = option.option_strings |
||||
|
|
||||
|
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: |
||||
|
|
||||
|
try: |
||||
|
expand_default = self.expand_default |
||||
|
except AttributeError: |
||||
|
# The HelpFormatter base class in the Python 2.3 version |
||||
|
# of optparse has no expand_default() method. |
||||
|
help_text = option.help |
||||
|
else: |
||||
|
help_text = 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 string.join(result, "") |
||||
|
|
||||
|
# For consistent help output across Python versions, we provide a |
||||
|
# subclass copy of format_option_strings() and these two variables. |
||||
|
# This is necessary (?) for Python2.3, which otherwise concatenates |
||||
|
# a short option with its metavar. |
||||
|
_short_opt_fmt = "%s %s" |
||||
|
_long_opt_fmt = "%s=%s" |
||||
|
|
||||
|
def format_option_strings(self, option): |
||||
|
"""Return a comma-separated list of option strings & metavariables.""" |
||||
|
if option.takes_value(): |
||||
|
metavar = option.metavar or string.upper(option.dest) |
||||
|
short_opts = [] |
||||
|
for sopt in option._short_opts: |
||||
|
short_opts.append(self._short_opt_fmt % (sopt, metavar)) |
||||
|
long_opts = [] |
||||
|
for lopt in option._long_opts: |
||||
|
long_opts.append(self._long_opt_fmt % (lopt, metavar)) |
||||
|
else: |
||||
|
short_opts = option._short_opts |
||||
|
long_opts = option._long_opts |
||||
|
|
||||
|
if self.short_first: |
||||
|
opts = short_opts + long_opts |
||||
|
else: |
||||
|
opts = long_opts + short_opts |
||||
|
|
||||
|
return string.join(opts, ", ") |
||||
|
|
||||
|
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-show', |
||||
|
dest='cache_show', default=False, |
||||
|
action="store_true", |
||||
|
help="Print build actions for files from CacheDir.") |
||||
|
|
||||
|
config_options = ["auto", "force" ,"cache"] |
||||
|
|
||||
|
def opt_config(option, opt, value, parser, c_options=config_options): |
||||
|
if not value in c_options: |
||||
|
raise OptionValueError("Warning: %s is not a valid config type" % value) |
||||
|
setattr(parser.values, option.dest, value) |
||||
|
opt_config_help = "Controls Configure subsystem: %s." \ |
||||
|
% string.join(config_options, ", ") |
||||
|
op.add_option('--config', |
||||
|
nargs=1, type="string", |
||||
|
dest="config", default="auto", |
||||
|
action="callback", callback=opt_config, |
||||
|
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 = { |
||||
|
"dtree" : '; please use --tree=derived instead', |
||||
|
"nomemoizer" : ' and has no effect', |
||||
|
"stree" : '; please use --tree=all,status instead', |
||||
|
"tree" : '; please use --tree=all instead', |
||||
|
} |
||||
|
|
||||
|
debug_options = ["count", "explain", "findlibs", |
||||
|
"includes", "memoizer", "memory", "objects", |
||||
|
"pdb", "presub", "stacktrace", |
||||
|
"time"] + deprecated_debug_options.keys() |
||||
|
|
||||
|
def opt_debug(option, opt, value, parser, |
||||
|
debug_options=debug_options, |
||||
|
deprecated_debug_options=deprecated_debug_options): |
||||
|
if value in debug_options: |
||||
|
parser.values.debug.append(value) |
||||
|
if value in deprecated_debug_options.keys(): |
||||
|
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.DeprecatedWarning, w) |
||||
|
parser.values.delayed_warnings.append(t) |
||||
|
else: |
||||
|
raise OptionValueError("Warning: %s is not a valid debug type" % value) |
||||
|
opt_debug_help = "Print various types of debugging information: %s." \ |
||||
|
% string.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, e: |
||||
|
raise OptionValueError("Warning: `%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 not value in SCons.Node.FS.Valid_Duplicates: |
||||
|
raise OptionValueError("`%s' is not a valid duplication style." % value) |
||||
|
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 " \ |
||||
|
+ string.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) |
||||
|
|
||||
|
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('--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"] |
||||
|
|
||||
|
def opt_tree(option, opt, value, parser, tree_options=tree_options): |
||||
|
import Main |
||||
|
tp = Main.TreePrinter() |
||||
|
for o in string.split(value, ','): |
||||
|
if o == 'all': |
||||
|
tp.derived = False |
||||
|
elif o == 'derived': |
||||
|
tp.derived = True |
||||
|
elif o == 'prune': |
||||
|
tp.prune = True |
||||
|
elif o == 'status': |
||||
|
tp.status = True |
||||
|
else: |
||||
|
raise OptionValueError("Warning: %s is not a valid --tree option" % o) |
||||
|
parser.values.tree_printers.append(tp) |
||||
|
|
||||
|
opt_tree_help = "Print a dependency tree in various formats: %s." \ |
||||
|
% string.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 = string.split(value, ',') |
||||
|
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) |
||||
|
sys.exit(0) |
||||
|
|
||||
|
|
||||
|
op.add_option('-l', '--load-average', '--max-load', |
||||
|
nargs=1, type="int", |
||||
|
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 |
@ -0,0 +1,632 @@ |
|||||
|
"""SCons.Script.SConscript |
||||
|
|
||||
|
This module defines the Python API provided to SConscript and SConstruct |
||||
|
files. |
||||
|
|
||||
|
""" |
||||
|
|
||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Script/SConscript.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
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 |
||||
|
import SCons.Util |
||||
|
|
||||
|
import os |
||||
|
import os.path |
||||
|
import re |
||||
|
import string |
||||
|
import sys |
||||
|
import traceback |
||||
|
import types |
||||
|
import UserList |
||||
|
|
||||
|
# The following variables used to live in this module. Some |
||||
|
# SConscript files out there may have referred to them directly as |
||||
|
# SCons.Script.SConscript.*. This is now supported by some special |
||||
|
# handling towards the bottom of the SConscript.__init__.py module. |
||||
|
#Arguments = {} |
||||
|
#ArgList = [] |
||||
|
#BuildTargets = TargetList() |
||||
|
#CommandLineTargets = [] |
||||
|
#DefaultTargets = [] |
||||
|
|
||||
|
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 SCons.Util.is_Dict(export): |
||||
|
retval.update(export) |
||||
|
else: |
||||
|
try: |
||||
|
retval[export] = loc[export] |
||||
|
except KeyError: |
||||
|
retval[export] = glob[export] |
||||
|
except KeyError, 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 = SCons.Util.flatten(vars) |
||||
|
for var in fvars: |
||||
|
for v in string.split(var): |
||||
|
retval.append(call_stack[-1].globals[v]) |
||||
|
except KeyError, 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 _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 in call_stack[-1].globals |
||||
|
else: |
||||
|
if isinstance(fn, SCons.Node.Node): |
||||
|
f = fn |
||||
|
else: |
||||
|
f = fs.File(str(fn)) |
||||
|
_file_ = None |
||||
|
|
||||
|
# 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(): |
||||
|
_file_ = open(f.rfile().get_abspath(), "r") |
||||
|
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(), "r") |
||||
|
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) |
||||
|
# TODO Not sure how to handle src_dir here |
||||
|
os.chdir(f.rfile().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: |
||||
|
exec _file_ in call_stack[-1].globals |
||||
|
except SConscriptReturn: |
||||
|
pass |
||||
|
finally: |
||||
|
if old_file is not None: |
||||
|
call_stack[-1].globals.update({__file__:old_file}) |
||||
|
else: |
||||
|
SCons.Warnings.warn(SCons.Warnings.MissingSConscriptWarning, |
||||
|
"Ignoring missing SConscript '%s'" % f.path) |
||||
|
|
||||
|
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, 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 not tb.tb_frame.f_locals.has_key(stack_bottom): |
||||
|
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 not tb.tb_frame.f_locals.has_key(stack_bottom): |
||||
|
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 = string.split(string.split(version_string, ' ')[0], '.') |
||||
|
v_major = int(version[0]) |
||||
|
v_minor = int(re.match('\d+', version[1]).group()) |
||||
|
if len(version) >= 3: |
||||
|
v_revision = int(re.match('\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 SCons.Util.is_List(dirs): |
||||
|
dirs = [ dirs ] |
||||
|
dirs = map(str, dirs) |
||||
|
|
||||
|
name = kw.get('name', 'SConscript') |
||||
|
|
||||
|
files = map(lambda n, name = name: os.path.join(n, name), 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 SCons.Util.is_List(files): |
||||
|
files = [ files ] |
||||
|
|
||||
|
if kw.get('exports'): |
||||
|
exports.extend(self.Split(kw['exports'])) |
||||
|
|
||||
|
variant_dir = kw.get('variant_dir') or kw.get('build_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.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 name space 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 apply(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.""" |
||||
|
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.""" |
||||
|
try: |
||||
|
v_major, v_minor, v_micro, release, serial = sys.version_info |
||||
|
python_ver = (v_major, v_minor) |
||||
|
except AttributeError: |
||||
|
python_ver = self._get_major_minor_revision(sys.version)[:2] |
||||
|
if python_ver < (major, minor): |
||||
|
v = string.split(sys.version, " ", 1)[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): |
||||
|
for var in vars: |
||||
|
global_exports.update(compute_exports(self.Split(var))) |
||||
|
|
||||
|
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): |
||||
|
text = self.subst(text, raw=1) |
||||
|
SCons.Script.HelpFunction(text) |
||||
|
|
||||
|
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 exports.has_key(v): |
||||
|
globals[v] = exports[v] |
||||
|
else: |
||||
|
globals[v] = global_exports[v] |
||||
|
except KeyError,x: |
||||
|
raise SCons.Errors.UserError, "Import of non-existent variable '%s'"%x |
||||
|
|
||||
|
def SConscript(self, *ls, **kw): |
||||
|
def subst_element(x, subst=self.subst): |
||||
|
if SCons.Util.is_List(x): |
||||
|
x = map(subst, x) |
||||
|
else: |
||||
|
x = subst(x) |
||||
|
return x |
||||
|
ls = map(subst_element, ls) |
||||
|
subst_kw = {} |
||||
|
for key, val in kw.items(): |
||||
|
if SCons.Util.is_String(val): |
||||
|
val = self.subst(val) |
||||
|
elif SCons.Util.is_List(val): |
||||
|
result = [] |
||||
|
for v in val: |
||||
|
if SCons.Util.is_String(v): |
||||
|
v = self.subst(v) |
||||
|
result.append(v) |
||||
|
val = result |
||||
|
subst_kw[key] = val |
||||
|
|
||||
|
files, exports = self._get_SConscript_filenames(ls, subst_kw) |
||||
|
subst_kw['exports'] = exports |
||||
|
return apply(_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 apply(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 apply(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 type(d[m]) != mtype |
||||
|
for m in filter(not_a_module, dir(SCons.Script)): |
||||
|
GlobalDict[m] = d[m] |
||||
|
|
||||
|
return GlobalDict.copy() |
@ -0,0 +1,408 @@ |
|||||
|
"""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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Script/__init__.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import time |
||||
|
start_time = time.time() |
||||
|
|
||||
|
import os |
||||
|
import string |
||||
|
import sys |
||||
|
import UserList |
||||
|
|
||||
|
# 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 + string.split(os.environ.get('SCONSFLAGS', '')) |
||||
|
if "--debug=memoizer" in _args: |
||||
|
import SCons.Memoize |
||||
|
import SCons.Warnings |
||||
|
try: |
||||
|
SCons.Memoize.EnableMemoization() |
||||
|
except SCons.Warnings.Warning: |
||||
|
# Some warning was thrown (inability to --debug=memoizer on |
||||
|
# Python 1.5.2 because it doesn't have metaclasses). Arrange |
||||
|
# for it to be displayed or not after warnings are configured. |
||||
|
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.Options |
||||
|
import SCons.Platform |
||||
|
import SCons.Scanner |
||||
|
import SCons.SConf |
||||
|
import SCons.Subst |
||||
|
import SCons.Tool |
||||
|
import SCons.Util |
||||
|
import SCons.Variables |
||||
|
import SCons.Defaults |
||||
|
|
||||
|
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 |
||||
|
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 |
||||
|
|
||||
|
# |
||||
|
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 |
||||
|
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 |
||||
|
|
||||
|
# Deprecated names that will go away some day. |
||||
|
BoolOption = SCons.Options.BoolOption |
||||
|
EnumOption = SCons.Options.EnumOption |
||||
|
ListOption = SCons.Options.ListOption |
||||
|
PackageOption = SCons.Options.PackageOption |
||||
|
PathOption = SCons.Options.PathOption |
||||
|
|
||||
|
# 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(UserList.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 = string.split(arg, '=', 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): |
||||
|
global help_text |
||||
|
if SCons.Script.help_text is None: |
||||
|
SCons.Script.help_text = text |
||||
|
else: |
||||
|
help_text = help_text + text |
||||
|
|
||||
|
# |
||||
|
# Will be non-zero if we are reading an SConscript file. |
||||
|
sconscript_reading = 0 |
||||
|
|
||||
|
# |
||||
|
def Variables(files=[], args=ARGUMENTS): |
||||
|
return SCons.Variables.Variables(files, args) |
||||
|
|
||||
|
def Options(files=[], args=ARGUMENTS): |
||||
|
return SCons.Options.Options(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', |
||||
|
'BuildDir', |
||||
|
'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', |
||||
|
'Literal', |
||||
|
'Local', |
||||
|
'ParseDepends', |
||||
|
'Precious', |
||||
|
'Repository', |
||||
|
'Requires', |
||||
|
'SConsignFile', |
||||
|
'SideEffect', |
||||
|
'SourceCode', |
||||
|
'SourceSignatures', |
||||
|
'Split', |
||||
|
'Tag', |
||||
|
'TargetSignatures', |
||||
|
'Value', |
||||
|
'VariantDir', |
||||
|
] |
||||
|
|
||||
|
GlobalDefaultBuilders = [ |
||||
|
# Supported builders. |
||||
|
'CFile', |
||||
|
'CXXFile', |
||||
|
'DVI', |
||||
|
'Jar', |
||||
|
'Java', |
||||
|
'JavaH', |
||||
|
'Library', |
||||
|
'M4', |
||||
|
'MSVSProject', |
||||
|
'Object', |
||||
|
'PCH', |
||||
|
'PDF', |
||||
|
'PostScript', |
||||
|
'Program', |
||||
|
'RES', |
||||
|
'RMIC', |
||||
|
'SharedLibrary', |
||||
|
'SharedObject', |
||||
|
'StaticLibrary', |
||||
|
'StaticObject', |
||||
|
'Tar', |
||||
|
'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) |
@ -0,0 +1,57 @@ |
|||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Sig.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
__doc__ = """Place-holder for the old SCons.Sig module hierarchy |
||||
|
|
||||
|
This is no longer used, but code out there (such as the NSIS module on |
||||
|
the SCons wiki) may try to import SCons.Sig. If so, we generate a warning |
||||
|
that points them to the line that caused the import, and don't die. |
||||
|
|
||||
|
If someone actually tried to use the sub-modules or functions within |
||||
|
the package (for example, SCons.Sig.MD5.signature()), then they'll still |
||||
|
get an AttributeError, but at least they'll know where to start looking. |
||||
|
""" |
||||
|
|
||||
|
import SCons.Util |
||||
|
import SCons.Warnings |
||||
|
|
||||
|
msg = 'The SCons.Sig module no longer exists.\n' \ |
||||
|
' Remove the following "import SCons.Sig" line to eliminate this warning:' |
||||
|
|
||||
|
SCons.Warnings.warn(SCons.Warnings.DeprecatedWarning, msg) |
||||
|
|
||||
|
default_calc = None |
||||
|
default_module = None |
||||
|
|
||||
|
class MD5Null(SCons.Util.Null): |
||||
|
def __repr__(self): |
||||
|
return "MD5Null()" |
||||
|
|
||||
|
class TimeStampNull(SCons.Util.Null): |
||||
|
def __repr__(self): |
||||
|
return "TimeStampNull()" |
||||
|
|
||||
|
MD5 = MD5Null() |
||||
|
TimeStamp = TimeStampNull() |
@ -0,0 +1,884 @@ |
|||||
|
"""SCons.Subst |
||||
|
|
||||
|
SCons string substitution. |
||||
|
|
||||
|
""" |
||||
|
|
||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Subst.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import re |
||||
|
import string |
||||
|
import types |
||||
|
import UserList |
||||
|
import UserString |
||||
|
|
||||
|
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 = filter(None, excepts) |
||||
|
|
||||
|
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 |
||||
|
|
||||
|
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(UserString.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): |
||||
|
UserString.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(list, 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 map(escape, list) |
||||
|
|
||||
|
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): |
||||
|
list = self.list |
||||
|
if list is None: |
||||
|
list = [] |
||||
|
elif not is_Sequence(list): |
||||
|
list = [list] |
||||
|
# The map(self.func) call is what actually turns |
||||
|
# a list into appropriate proxies. |
||||
|
self.nodelist = SCons.Util.NodeList(map(self.func, list)) |
||||
|
self._create_nodelist = self._return_nodelist |
||||
|
return self.nodelist |
||||
|
_create_nodelist = _gen_nodelist |
||||
|
|
||||
|
|
||||
|
class Targets_or_Sources(UserList.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 UserList.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 |
||||
|
UserList.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 '' |
||||
|
|
||||
|
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) |
||||
|
else: |
||||
|
dict['TARGETS'] = None |
||||
|
dict['TARGET'] = None |
||||
|
|
||||
|
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) |
||||
|
else: |
||||
|
dict['SOURCES'] = None |
||||
|
dict['SOURCE'] = None |
||||
|
|
||||
|
return dict |
||||
|
|
||||
|
# 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'\$[()]') |
||||
|
_remove = re.compile(r'\$\([^\$]*(\$[^\)][^\$]*)*\$\)') |
||||
|
|
||||
|
# Indexed by the SUBST_* constants above. |
||||
|
_regex_remove = [ _rm, None, _remove ] |
||||
|
|
||||
|
def _rm_list(list): |
||||
|
#return [ l for l in list if not l in ('$(', '$)') ] |
||||
|
return filter(lambda l: not l in ('$(', '$)'), list) |
||||
|
|
||||
|
def _remove_list(list): |
||||
|
result = [] |
||||
|
do_append = result.append |
||||
|
for l in list: |
||||
|
if l == '$(': |
||||
|
do_append = lambda x: None |
||||
|
elif l == '$)': |
||||
|
do_append = result.append |
||||
|
else: |
||||
|
do_append(l) |
||||
|
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 type(strSubst) == types.StringType and string.find(strSubst, '$') < 0: |
||||
|
return strSubst |
||||
|
|
||||
|
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, target, source, conv, gvars): |
||||
|
self.env = env |
||||
|
self.mode = mode |
||||
|
self.target = target |
||||
|
self.source = source |
||||
|
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 == '$': |
||||
|
return '$' |
||||
|
elif s1 in '()': |
||||
|
return s |
||||
|
else: |
||||
|
key = s[1:] |
||||
|
if key[0] == '{' or string.find(key, '.') >= 0: |
||||
|
if key[0] == '{': |
||||
|
key = key[1:-1] |
||||
|
try: |
||||
|
s = eval(key, self.gvars, lvars) |
||||
|
except KeyboardInterrupt: |
||||
|
raise |
||||
|
except Exception, e: |
||||
|
if e.__class__ in AllowableExceptions: |
||||
|
return '' |
||||
|
raise_exception(e, self.target, s) |
||||
|
else: |
||||
|
if lvars.has_key(key): |
||||
|
s = lvars[key] |
||||
|
elif self.gvars.has_key(key): |
||||
|
s = self.gvars[key] |
||||
|
elif not NameError in AllowableExceptions: |
||||
|
raise_exception(NameError(key), self.target, s) |
||||
|
else: |
||||
|
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 = string.split(key, '.')[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 map(func, s) |
||||
|
elif callable(s): |
||||
|
try: |
||||
|
s = s(target=self.target, |
||||
|
source=self.source, |
||||
|
env=self.env, |
||||
|
for_signature=(self.mode != SUBST_CMD)) |
||||
|
except TypeError: |
||||
|
# 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, conv=self.conv, expand=self.expand, lvars=lvars): |
||||
|
return conv(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 = string.join(map(str, result), '') |
||||
|
return result |
||||
|
else: |
||||
|
return self.expand(args, lvars) |
||||
|
|
||||
|
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. |
||||
|
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, target, source, conv, gvars) |
||||
|
result = ss.substitute(strSubst, lvars) |
||||
|
|
||||
|
try: |
||||
|
del gvars['__builtins__'] |
||||
|
except KeyError: |
||||
|
pass |
||||
|
|
||||
|
if is_String(result): |
||||
|
# Remove $(-$) pairs and any stuff in between, |
||||
|
# if that's appropriate. |
||||
|
remove = _regex_remove[mode] |
||||
|
if remove: |
||||
|
result = remove.sub('', result) |
||||
|
if mode != SUBST_RAW: |
||||
|
# Compress strings of white space characters into |
||||
|
# a single space. |
||||
|
result = string.strip(_space_sep.sub(' ', result)) |
||||
|
elif is_Sequence(result): |
||||
|
remove = _list_remove[mode] |
||||
|
if remove: |
||||
|
result = remove(result) |
||||
|
|
||||
|
return result |
||||
|
|
||||
|
#Subst_List_Strings = {} |
||||
|
|
||||
|
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. |
||||
|
""" |
||||
|
# try: |
||||
|
# Subst_List_Strings[strSubst] = Subst_List_Strings[strSubst] + 1 |
||||
|
# except KeyError: |
||||
|
# Subst_List_Strings[strSubst] = 1 |
||||
|
# import SCons.Debug |
||||
|
# SCons.Debug.caller_trace(1) |
||||
|
class ListSubber(UserList.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, target, source, conv, gvars): |
||||
|
UserList.UserList.__init__(self, []) |
||||
|
self.env = env |
||||
|
self.mode = mode |
||||
|
self.target = target |
||||
|
self.source = source |
||||
|
self.conv = conv |
||||
|
self.gvars = gvars |
||||
|
|
||||
|
if self.mode == SUBST_RAW: |
||||
|
self.add_strip = lambda x, s=self: s.append(x) |
||||
|
else: |
||||
|
self.add_strip = lambda x, s=self: None |
||||
|
self.in_strip = None |
||||
|
self.next_line() |
||||
|
|
||||
|
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 string.find(key, '.') >= 0: |
||||
|
if key[0] == '{': |
||||
|
key = key[1:-1] |
||||
|
try: |
||||
|
s = eval(key, self.gvars, lvars) |
||||
|
except KeyboardInterrupt: |
||||
|
raise |
||||
|
except Exception, e: |
||||
|
if e.__class__ in AllowableExceptions: |
||||
|
return |
||||
|
raise_exception(e, self.target, s) |
||||
|
else: |
||||
|
if lvars.has_key(key): |
||||
|
s = lvars[key] |
||||
|
elif self.gvars.has_key(key): |
||||
|
s = self.gvars[key] |
||||
|
elif not NameError in AllowableExceptions: |
||||
|
raise_exception(NameError(), self.target, s) |
||||
|
else: |
||||
|
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 = string.split(key, '.')[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): |
||||
|
try: |
||||
|
s = s(target=self.target, |
||||
|
source=self.source, |
||||
|
env=self.env, |
||||
|
for_signature=(self.mode != SUBST_CMD)) |
||||
|
except TypeError: |
||||
|
# 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.""" |
||||
|
UserList.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 |
||||
|
|
||||
|
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. |
||||
|
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, target, source, 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 type(strSubst) == types.StringType and string.find(strSubst, '$') < 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 string.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 |
@ -0,0 +1,985 @@ |
|||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__doc__ = """ |
||||
|
Generic Taskmaster module for the SCons build engine. |
||||
|
|
||||
|
This module contains the primary interface(s) between a wrapping user |
||||
|
interface and the SCons build engine. There are two key classes here: |
||||
|
|
||||
|
Taskmaster |
||||
|
This is the main engine for walking the dependency graph and |
||||
|
calling things to decide what does or doesn't need to be built. |
||||
|
|
||||
|
Task |
||||
|
This is the base class for allowing a wrapping interface to |
||||
|
decide what does or doesn't actually need to be done. The |
||||
|
intention is for a wrapping interface to subclass this as |
||||
|
appropriate for different types of behavior it may need. |
||||
|
|
||||
|
The canonical example is the SCons native Python interface, |
||||
|
which has Task subclasses that handle its specific behavior, |
||||
|
like printing "`foo' is up to date" when a top-level target |
||||
|
doesn't need to be built, and handling the -c option by removing |
||||
|
targets as its "build" action. There is also a separate subclass |
||||
|
for suppressing this output when the -q option is used. |
||||
|
|
||||
|
The Taskmaster instantiates a Task object for each (set of) |
||||
|
target(s) that it decides need to be evaluated and/or built. |
||||
|
""" |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Taskmaster.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
from itertools import chain |
||||
|
import operator |
||||
|
import string |
||||
|
import sys |
||||
|
import traceback |
||||
|
|
||||
|
import SCons.Errors |
||||
|
import SCons.Node |
||||
|
|
||||
|
StateString = SCons.Node.StateString |
||||
|
NODE_NO_STATE = SCons.Node.no_state |
||||
|
NODE_PENDING = SCons.Node.pending |
||||
|
NODE_EXECUTING = SCons.Node.executing |
||||
|
NODE_UP_TO_DATE = SCons.Node.up_to_date |
||||
|
NODE_EXECUTED = SCons.Node.executed |
||||
|
NODE_FAILED = SCons.Node.failed |
||||
|
|
||||
|
|
||||
|
# A subsystem for recording stats about how different Nodes are handled by |
||||
|
# the main Taskmaster loop. There's no external control here (no need for |
||||
|
# a --debug= option); enable it by changing the value of CollectStats. |
||||
|
|
||||
|
CollectStats = None |
||||
|
|
||||
|
class Stats: |
||||
|
""" |
||||
|
A simple class for holding statistics about the disposition of a |
||||
|
Node by the Taskmaster. If we're collecting statistics, each Node |
||||
|
processed by the Taskmaster gets one of these attached, in which case |
||||
|
the Taskmaster records its decision each time it processes the Node. |
||||
|
(Ideally, that's just once per Node.) |
||||
|
""" |
||||
|
def __init__(self): |
||||
|
""" |
||||
|
Instantiates a Taskmaster.Stats object, initializing all |
||||
|
appropriate counters to zero. |
||||
|
""" |
||||
|
self.considered = 0 |
||||
|
self.already_handled = 0 |
||||
|
self.problem = 0 |
||||
|
self.child_failed = 0 |
||||
|
self.not_built = 0 |
||||
|
self.side_effects = 0 |
||||
|
self.build = 0 |
||||
|
|
||||
|
StatsNodes = [] |
||||
|
|
||||
|
fmt = "%(considered)3d "\ |
||||
|
"%(already_handled)3d " \ |
||||
|
"%(problem)3d " \ |
||||
|
"%(child_failed)3d " \ |
||||
|
"%(not_built)3d " \ |
||||
|
"%(side_effects)3d " \ |
||||
|
"%(build)3d " |
||||
|
|
||||
|
def dump_stats(): |
||||
|
StatsNodes.sort(lambda a, b: cmp(str(a), str(b))) |
||||
|
for n in StatsNodes: |
||||
|
print (fmt % n.stats.__dict__) + str(n) |
||||
|
|
||||
|
|
||||
|
|
||||
|
class Task: |
||||
|
""" |
||||
|
Default SCons build engine task. |
||||
|
|
||||
|
This controls the interaction of the actual building of node |
||||
|
and the rest of the engine. |
||||
|
|
||||
|
This is expected to handle all of the normally-customizable |
||||
|
aspects of controlling a build, so any given application |
||||
|
*should* be able to do what it wants by sub-classing this |
||||
|
class and overriding methods as appropriate. If an application |
||||
|
needs to customze something by sub-classing Taskmaster (or |
||||
|
some other build engine class), we should first try to migrate |
||||
|
that functionality into this class. |
||||
|
|
||||
|
Note that it's generally a good idea for sub-classes to call |
||||
|
these methods explicitly to update state, etc., rather than |
||||
|
roll their own interaction with Taskmaster from scratch. |
||||
|
""" |
||||
|
def __init__(self, tm, targets, top, node): |
||||
|
self.tm = tm |
||||
|
self.targets = targets |
||||
|
self.top = top |
||||
|
self.node = node |
||||
|
self.exc_clear() |
||||
|
|
||||
|
def trace_message(self, method, node, description='node'): |
||||
|
fmt = '%-20s %s %s\n' |
||||
|
return fmt % (method + ':', description, self.tm.trace_node(node)) |
||||
|
|
||||
|
def display(self, message): |
||||
|
""" |
||||
|
Hook to allow the calling interface to display a message. |
||||
|
|
||||
|
This hook gets called as part of preparing a task for execution |
||||
|
(that is, a Node to be built). As part of figuring out what Node |
||||
|
should be built next, the actually target list may be altered, |
||||
|
along with a message describing the alteration. The calling |
||||
|
interface can subclass Task and provide a concrete implementation |
||||
|
of this method to see those messages. |
||||
|
""" |
||||
|
pass |
||||
|
|
||||
|
def prepare(self): |
||||
|
""" |
||||
|
Called just before the task is executed. |
||||
|
|
||||
|
This is mainly intended to give the target Nodes a chance to |
||||
|
unlink underlying files and make all necessary directories before |
||||
|
the Action is actually called to build the targets. |
||||
|
""" |
||||
|
T = self.tm.trace |
||||
|
if T: T.write(self.trace_message('Task.prepare()', self.node)) |
||||
|
|
||||
|
# Now that it's the appropriate time, give the TaskMaster a |
||||
|
# chance to raise any exceptions it encountered while preparing |
||||
|
# this task. |
||||
|
self.exception_raise() |
||||
|
|
||||
|
if self.tm.message: |
||||
|
self.display(self.tm.message) |
||||
|
self.tm.message = None |
||||
|
|
||||
|
# Let the targets take care of any necessary preparations. |
||||
|
# This includes verifying that all of the necessary sources |
||||
|
# and dependencies exist, removing the target file(s), etc. |
||||
|
# |
||||
|
# As of April 2008, the get_executor().prepare() method makes |
||||
|
# sure that all of the aggregate sources necessary to build this |
||||
|
# Task's target(s) exist in one up-front check. The individual |
||||
|
# target t.prepare() methods check that each target's explicit |
||||
|
# or implicit dependencies exists, and also initialize the |
||||
|
# .sconsign info. |
||||
|
self.targets[0].get_executor().prepare() |
||||
|
for t in self.targets: |
||||
|
t.prepare() |
||||
|
for s in t.side_effects: |
||||
|
s.prepare() |
||||
|
|
||||
|
def get_target(self): |
||||
|
"""Fetch the target being built or updated by this task. |
||||
|
""" |
||||
|
return self.node |
||||
|
|
||||
|
def needs_execute(self): |
||||
|
""" |
||||
|
Called to determine whether the task's execute() method should |
||||
|
be run. |
||||
|
|
||||
|
This method allows one to skip the somethat costly execution |
||||
|
of the execute() method in a seperate thread. For example, |
||||
|
that would be unnecessary for up-to-date targets. |
||||
|
""" |
||||
|
return True |
||||
|
|
||||
|
def execute(self): |
||||
|
""" |
||||
|
Called to execute the task. |
||||
|
|
||||
|
This method is called from multiple threads in a parallel build, |
||||
|
so only do thread safe stuff here. Do thread unsafe stuff in |
||||
|
prepare(), executed() or failed(). |
||||
|
""" |
||||
|
T = self.tm.trace |
||||
|
if T: T.write(self.trace_message('Task.execute()', self.node)) |
||||
|
|
||||
|
try: |
||||
|
everything_was_cached = 1 |
||||
|
for t in self.targets: |
||||
|
if not t.retrieve_from_cache(): |
||||
|
everything_was_cached = 0 |
||||
|
break |
||||
|
if not everything_was_cached: |
||||
|
self.targets[0].build() |
||||
|
except SystemExit: |
||||
|
exc_value = sys.exc_info()[1] |
||||
|
raise SCons.Errors.ExplicitExit(self.targets[0], exc_value.code) |
||||
|
except SCons.Errors.UserError: |
||||
|
raise |
||||
|
except SCons.Errors.BuildError: |
||||
|
raise |
||||
|
except Exception, e: |
||||
|
buildError = SCons.Errors.convert_to_BuildError(e) |
||||
|
buildError.node = self.targets[0] |
||||
|
buildError.exc_info = sys.exc_info() |
||||
|
raise buildError |
||||
|
|
||||
|
def executed_without_callbacks(self): |
||||
|
""" |
||||
|
Called when the task has been successfully executed |
||||
|
and the Taskmaster instance doesn't want to call |
||||
|
the Node's callback methods. |
||||
|
""" |
||||
|
T = self.tm.trace |
||||
|
if T: T.write(self.trace_message('Task.executed_without_callbacks()', |
||||
|
self.node)) |
||||
|
|
||||
|
for t in self.targets: |
||||
|
if t.get_state() == NODE_EXECUTING: |
||||
|
for side_effect in t.side_effects: |
||||
|
side_effect.set_state(NODE_NO_STATE) |
||||
|
t.set_state(NODE_EXECUTED) |
||||
|
|
||||
|
def executed_with_callbacks(self): |
||||
|
""" |
||||
|
Called when the task has been successfully executed and |
||||
|
the Taskmaster instance wants to call the Node's callback |
||||
|
methods. |
||||
|
|
||||
|
This may have been a do-nothing operation (to preserve build |
||||
|
order), so we must check the node's state before deciding whether |
||||
|
it was "built", in which case we call the appropriate Node method. |
||||
|
In any event, we always call "visited()", which will handle any |
||||
|
post-visit actions that must take place regardless of whether |
||||
|
or not the target was an actual built target or a source Node. |
||||
|
""" |
||||
|
T = self.tm.trace |
||||
|
if T: T.write(self.trace_message('Task.executed_with_callbacks()', |
||||
|
self.node)) |
||||
|
|
||||
|
for t in self.targets: |
||||
|
if t.get_state() == NODE_EXECUTING: |
||||
|
for side_effect in t.side_effects: |
||||
|
side_effect.set_state(NODE_NO_STATE) |
||||
|
t.set_state(NODE_EXECUTED) |
||||
|
t.built() |
||||
|
t.visited() |
||||
|
|
||||
|
executed = executed_with_callbacks |
||||
|
|
||||
|
def failed(self): |
||||
|
""" |
||||
|
Default action when a task fails: stop the build. |
||||
|
|
||||
|
Note: Although this function is normally invoked on nodes in |
||||
|
the executing state, it might also be invoked on up-to-date |
||||
|
nodes when using Configure(). |
||||
|
""" |
||||
|
self.fail_stop() |
||||
|
|
||||
|
def fail_stop(self): |
||||
|
""" |
||||
|
Explicit stop-the-build failure. |
||||
|
|
||||
|
This sets failure status on the target nodes and all of |
||||
|
their dependent parent nodes. |
||||
|
|
||||
|
Note: Although this function is normally invoked on nodes in |
||||
|
the executing state, it might also be invoked on up-to-date |
||||
|
nodes when using Configure(). |
||||
|
""" |
||||
|
T = self.tm.trace |
||||
|
if T: T.write(self.trace_message('Task.failed_stop()', self.node)) |
||||
|
|
||||
|
# Invoke will_not_build() to clean-up the pending children |
||||
|
# list. |
||||
|
self.tm.will_not_build(self.targets, lambda n: n.set_state(NODE_FAILED)) |
||||
|
|
||||
|
# Tell the taskmaster to not start any new tasks |
||||
|
self.tm.stop() |
||||
|
|
||||
|
# We're stopping because of a build failure, but give the |
||||
|
# calling Task class a chance to postprocess() the top-level |
||||
|
# target under which the build failure occurred. |
||||
|
self.targets = [self.tm.current_top] |
||||
|
self.top = 1 |
||||
|
|
||||
|
def fail_continue(self): |
||||
|
""" |
||||
|
Explicit continue-the-build failure. |
||||
|
|
||||
|
This sets failure status on the target nodes and all of |
||||
|
their dependent parent nodes. |
||||
|
|
||||
|
Note: Although this function is normally invoked on nodes in |
||||
|
the executing state, it might also be invoked on up-to-date |
||||
|
nodes when using Configure(). |
||||
|
""" |
||||
|
T = self.tm.trace |
||||
|
if T: T.write(self.trace_message('Task.failed_continue()', self.node)) |
||||
|
|
||||
|
self.tm.will_not_build(self.targets, lambda n: n.set_state(NODE_FAILED)) |
||||
|
|
||||
|
def make_ready_all(self): |
||||
|
""" |
||||
|
Marks all targets in a task ready for execution. |
||||
|
|
||||
|
This is used when the interface needs every target Node to be |
||||
|
visited--the canonical example being the "scons -c" option. |
||||
|
""" |
||||
|
T = self.tm.trace |
||||
|
if T: T.write(self.trace_message('Task.make_ready_all()', self.node)) |
||||
|
|
||||
|
self.out_of_date = self.targets[:] |
||||
|
for t in self.targets: |
||||
|
t.disambiguate().set_state(NODE_EXECUTING) |
||||
|
for s in t.side_effects: |
||||
|
s.set_state(NODE_EXECUTING) |
||||
|
|
||||
|
def make_ready_current(self): |
||||
|
""" |
||||
|
Marks all targets in a task ready for execution if any target |
||||
|
is not current. |
||||
|
|
||||
|
This is the default behavior for building only what's necessary. |
||||
|
""" |
||||
|
T = self.tm.trace |
||||
|
if T: T.write(self.trace_message('Task.make_ready_current()', |
||||
|
self.node)) |
||||
|
|
||||
|
self.out_of_date = [] |
||||
|
needs_executing = False |
||||
|
for t in self.targets: |
||||
|
try: |
||||
|
t.disambiguate().make_ready() |
||||
|
is_up_to_date = not t.has_builder() or \ |
||||
|
(not t.always_build and t.is_up_to_date()) |
||||
|
except EnvironmentError, e: |
||||
|
raise SCons.Errors.BuildError(node=t, errstr=e.strerror, filename=e.filename) |
||||
|
|
||||
|
if not is_up_to_date: |
||||
|
self.out_of_date.append(t) |
||||
|
needs_executing = True |
||||
|
|
||||
|
if needs_executing: |
||||
|
for t in self.targets: |
||||
|
t.set_state(NODE_EXECUTING) |
||||
|
for s in t.side_effects: |
||||
|
s.set_state(NODE_EXECUTING) |
||||
|
else: |
||||
|
for t in self.targets: |
||||
|
# We must invoke visited() to ensure that the node |
||||
|
# information has been computed before allowing the |
||||
|
# parent nodes to execute. (That could occur in a |
||||
|
# parallel build...) |
||||
|
t.visited() |
||||
|
t.set_state(NODE_UP_TO_DATE) |
||||
|
|
||||
|
make_ready = make_ready_current |
||||
|
|
||||
|
def postprocess(self): |
||||
|
""" |
||||
|
Post-processes a task after it's been executed. |
||||
|
|
||||
|
This examines all the targets just built (or not, we don't care |
||||
|
if the build was successful, or even if there was no build |
||||
|
because everything was up-to-date) to see if they have any |
||||
|
waiting parent Nodes, or Nodes waiting on a common side effect, |
||||
|
that can be put back on the candidates list. |
||||
|
""" |
||||
|
T = self.tm.trace |
||||
|
if T: T.write(self.trace_message('Task.postprocess()', self.node)) |
||||
|
|
||||
|
# We may have built multiple targets, some of which may have |
||||
|
# common parents waiting for this build. Count up how many |
||||
|
# targets each parent was waiting for so we can subtract the |
||||
|
# values later, and so we *don't* put waiting side-effect Nodes |
||||
|
# back on the candidates list if the Node is also a waiting |
||||
|
# parent. |
||||
|
|
||||
|
targets = set(self.targets) |
||||
|
|
||||
|
pending_children = self.tm.pending_children |
||||
|
parents = {} |
||||
|
for t in targets: |
||||
|
# A node can only be in the pending_children set if it has |
||||
|
# some waiting_parents. |
||||
|
if t.waiting_parents: |
||||
|
if T: T.write(self.trace_message('Task.postprocess()', |
||||
|
t, |
||||
|
'removing')) |
||||
|
pending_children.discard(t) |
||||
|
for p in t.waiting_parents: |
||||
|
parents[p] = parents.get(p, 0) + 1 |
||||
|
|
||||
|
for t in targets: |
||||
|
for s in t.side_effects: |
||||
|
if s.get_state() == NODE_EXECUTING: |
||||
|
s.set_state(NODE_NO_STATE) |
||||
|
for p in s.waiting_parents: |
||||
|
parents[p] = parents.get(p, 0) + 1 |
||||
|
for p in s.waiting_s_e: |
||||
|
if p.ref_count == 0: |
||||
|
self.tm.candidates.append(p) |
||||
|
|
||||
|
for p, subtract in parents.items(): |
||||
|
p.ref_count = p.ref_count - subtract |
||||
|
if T: T.write(self.trace_message('Task.postprocess()', |
||||
|
p, |
||||
|
'adjusted parent ref count')) |
||||
|
if p.ref_count == 0: |
||||
|
self.tm.candidates.append(p) |
||||
|
|
||||
|
for t in targets: |
||||
|
t.postprocess() |
||||
|
|
||||
|
# Exception handling subsystem. |
||||
|
# |
||||
|
# Exceptions that occur while walking the DAG or examining Nodes |
||||
|
# must be raised, but must be raised at an appropriate time and in |
||||
|
# a controlled manner so we can, if necessary, recover gracefully, |
||||
|
# possibly write out signature information for Nodes we've updated, |
||||
|
# etc. This is done by having the Taskmaster tell us about the |
||||
|
# exception, and letting |
||||
|
|
||||
|
def exc_info(self): |
||||
|
""" |
||||
|
Returns info about a recorded exception. |
||||
|
""" |
||||
|
return self.exception |
||||
|
|
||||
|
def exc_clear(self): |
||||
|
""" |
||||
|
Clears any recorded exception. |
||||
|
|
||||
|
This also changes the "exception_raise" attribute to point |
||||
|
to the appropriate do-nothing method. |
||||
|
""" |
||||
|
self.exception = (None, None, None) |
||||
|
self.exception_raise = self._no_exception_to_raise |
||||
|
|
||||
|
def exception_set(self, exception=None): |
||||
|
""" |
||||
|
Records an exception to be raised at the appropriate time. |
||||
|
|
||||
|
This also changes the "exception_raise" attribute to point |
||||
|
to the method that will, in fact |
||||
|
""" |
||||
|
if not exception: |
||||
|
exception = sys.exc_info() |
||||
|
self.exception = exception |
||||
|
self.exception_raise = self._exception_raise |
||||
|
|
||||
|
def _no_exception_to_raise(self): |
||||
|
pass |
||||
|
|
||||
|
def _exception_raise(self): |
||||
|
""" |
||||
|
Raises a pending exception that was recorded while getting a |
||||
|
Task ready for execution. |
||||
|
""" |
||||
|
exc = self.exc_info()[:] |
||||
|
try: |
||||
|
exc_type, exc_value, exc_traceback = exc |
||||
|
except ValueError: |
||||
|
exc_type, exc_value = exc |
||||
|
exc_traceback = None |
||||
|
raise exc_type, exc_value, exc_traceback |
||||
|
|
||||
|
|
||||
|
def find_cycle(stack, visited): |
||||
|
if stack[-1] in visited: |
||||
|
return None |
||||
|
visited.add(stack[-1]) |
||||
|
for n in stack[-1].waiting_parents: |
||||
|
stack.append(n) |
||||
|
if stack[0] == stack[-1]: |
||||
|
return stack |
||||
|
if find_cycle(stack, visited): |
||||
|
return stack |
||||
|
stack.pop() |
||||
|
return None |
||||
|
|
||||
|
|
||||
|
class Taskmaster: |
||||
|
""" |
||||
|
The Taskmaster for walking the dependency DAG. |
||||
|
""" |
||||
|
|
||||
|
def __init__(self, targets=[], tasker=Task, order=None, trace=None): |
||||
|
self.original_top = targets |
||||
|
self.top_targets_left = targets[:] |
||||
|
self.top_targets_left.reverse() |
||||
|
self.candidates = [] |
||||
|
self.tasker = tasker |
||||
|
if not order: |
||||
|
order = lambda l: l |
||||
|
self.order = order |
||||
|
self.message = None |
||||
|
self.trace = trace |
||||
|
self.next_candidate = self.find_next_candidate |
||||
|
self.pending_children = set() |
||||
|
|
||||
|
def find_next_candidate(self): |
||||
|
""" |
||||
|
Returns the next candidate Node for (potential) evaluation. |
||||
|
|
||||
|
The candidate list (really a stack) initially consists of all of |
||||
|
the top-level (command line) targets provided when the Taskmaster |
||||
|
was initialized. While we walk the DAG, visiting Nodes, all the |
||||
|
children that haven't finished processing get pushed on to the |
||||
|
candidate list. Each child can then be popped and examined in |
||||
|
turn for whether *their* children are all up-to-date, in which |
||||
|
case a Task will be created for their actual evaluation and |
||||
|
potential building. |
||||
|
|
||||
|
Here is where we also allow candidate Nodes to alter the list of |
||||
|
Nodes that should be examined. This is used, for example, when |
||||
|
invoking SCons in a source directory. A source directory Node can |
||||
|
return its corresponding build directory Node, essentially saying, |
||||
|
"Hey, you really need to build this thing over here instead." |
||||
|
""" |
||||
|
try: |
||||
|
return self.candidates.pop() |
||||
|
except IndexError: |
||||
|
pass |
||||
|
try: |
||||
|
node = self.top_targets_left.pop() |
||||
|
except IndexError: |
||||
|
return None |
||||
|
self.current_top = node |
||||
|
alt, message = node.alter_targets() |
||||
|
if alt: |
||||
|
self.message = message |
||||
|
self.candidates.append(node) |
||||
|
self.candidates.extend(self.order(alt)) |
||||
|
node = self.candidates.pop() |
||||
|
return node |
||||
|
|
||||
|
def no_next_candidate(self): |
||||
|
""" |
||||
|
Stops Taskmaster processing by not returning a next candidate. |
||||
|
|
||||
|
Note that we have to clean-up the Taskmaster candidate list |
||||
|
because the cycle detection depends on the fact all nodes have |
||||
|
been processed somehow. |
||||
|
""" |
||||
|
while self.candidates: |
||||
|
candidates = self.candidates |
||||
|
self.candidates = [] |
||||
|
self.will_not_build(candidates) |
||||
|
return None |
||||
|
|
||||
|
def _validate_pending_children(self): |
||||
|
""" |
||||
|
Validate the content of the pending_children set. Assert if an |
||||
|
internal error is found. |
||||
|
|
||||
|
This function is used strictly for debugging the taskmaster by |
||||
|
checking that no invariants are violated. It is not used in |
||||
|
normal operation. |
||||
|
|
||||
|
The pending_children set is used to detect cycles in the |
||||
|
dependency graph. We call a "pending child" a child that is |
||||
|
found in the "pending" state when checking the dependencies of |
||||
|
its parent node. |
||||
|
|
||||
|
A pending child can occur when the Taskmaster completes a loop |
||||
|
through a cycle. For example, lets imagine a graph made of |
||||
|
three node (A, B and C) making a cycle. The evaluation starts |
||||
|
at node A. The taskmaster first consider whether node A's |
||||
|
child B is up-to-date. Then, recursively, node B needs to |
||||
|
check whether node C is up-to-date. This leaves us with a |
||||
|
dependency graph looking like: |
||||
|
|
||||
|
Next candidate \ |
||||
|
\ |
||||
|
Node A (Pending) --> Node B(Pending) --> Node C (NoState) |
||||
|
^ | |
||||
|
| | |
||||
|
+-------------------------------------+ |
||||
|
|
||||
|
Now, when the Taskmaster examines the Node C's child Node A, |
||||
|
it finds that Node A is in the "pending" state. Therefore, |
||||
|
Node A is a pending child of node C. |
||||
|
|
||||
|
Pending children indicate that the Taskmaster has potentially |
||||
|
loop back through a cycle. We say potentially because it could |
||||
|
also occur when a DAG is evaluated in parallel. For example, |
||||
|
consider the following graph: |
||||
|
|
||||
|
|
||||
|
Node A (Pending) --> Node B(Pending) --> Node C (Pending) --> ... |
||||
|
| ^ |
||||
|
| | |
||||
|
+----------> Node D (NoState) --------+ |
||||
|
/ |
||||
|
Next candidate / |
||||
|
|
||||
|
The Taskmaster first evaluates the nodes A, B, and C and |
||||
|
starts building some children of node C. Assuming, that the |
||||
|
maximum parallel level has not been reached, the Taskmaster |
||||
|
will examine Node D. It will find that Node C is a pending |
||||
|
child of Node D. |
||||
|
|
||||
|
In summary, evaluating a graph with a cycle will always |
||||
|
involve a pending child at one point. A pending child might |
||||
|
indicate either a cycle or a diamond-shaped DAG. Only a |
||||
|
fraction of the nodes ends-up being a "pending child" of |
||||
|
another node. This keeps the pending_children set small in |
||||
|
practice. |
||||
|
|
||||
|
We can differentiate between the two cases if we wait until |
||||
|
the end of the build. At this point, all the pending children |
||||
|
nodes due to a diamond-shaped DAG will have been properly |
||||
|
built (or will have failed to build). But, the pending |
||||
|
children involved in a cycle will still be in the pending |
||||
|
state. |
||||
|
|
||||
|
The taskmaster removes nodes from the pending_children set as |
||||
|
soon as a pending_children node moves out of the pending |
||||
|
state. This also helps to keep the pending_children set small. |
||||
|
""" |
||||
|
|
||||
|
for n in self.pending_children: |
||||
|
assert n.state in (NODE_PENDING, NODE_EXECUTING), \ |
||||
|
(str(n), StateString[n.state]) |
||||
|
assert len(n.waiting_parents) != 0, (str(n), len(n.waiting_parents)) |
||||
|
for p in n.waiting_parents: |
||||
|
assert p.ref_count > 0, (str(n), str(p), p.ref_count) |
||||
|
|
||||
|
|
||||
|
def trace_message(self, message): |
||||
|
return 'Taskmaster: %s\n' % message |
||||
|
|
||||
|
def trace_node(self, node): |
||||
|
return '<%-10s %-3s %s>' % (StateString[node.get_state()], |
||||
|
node.ref_count, |
||||
|
repr(str(node))) |
||||
|
|
||||
|
def _find_next_ready_node(self): |
||||
|
""" |
||||
|
Finds the next node that is ready to be built. |
||||
|
|
||||
|
This is *the* main guts of the DAG walk. We loop through the |
||||
|
list of candidates, looking for something that has no un-built |
||||
|
children (i.e., that is a leaf Node or has dependencies that are |
||||
|
all leaf Nodes or up-to-date). Candidate Nodes are re-scanned |
||||
|
(both the target Node itself and its sources, which are always |
||||
|
scanned in the context of a given target) to discover implicit |
||||
|
dependencies. A Node that must wait for some children to be |
||||
|
built will be put back on the candidates list after the children |
||||
|
have finished building. A Node that has been put back on the |
||||
|
candidates list in this way may have itself (or its sources) |
||||
|
re-scanned, in order to handle generated header files (e.g.) and |
||||
|
the implicit dependencies therein. |
||||
|
|
||||
|
Note that this method does not do any signature calculation or |
||||
|
up-to-date check itself. All of that is handled by the Task |
||||
|
class. This is purely concerned with the dependency graph walk. |
||||
|
""" |
||||
|
|
||||
|
self.ready_exc = None |
||||
|
|
||||
|
T = self.trace |
||||
|
if T: T.write('\n' + self.trace_message('Looking for a node to evaluate')) |
||||
|
|
||||
|
while 1: |
||||
|
node = self.next_candidate() |
||||
|
if node is None: |
||||
|
if T: T.write(self.trace_message('No candidate anymore.') + '\n') |
||||
|
return None |
||||
|
|
||||
|
node = node.disambiguate() |
||||
|
state = node.get_state() |
||||
|
|
||||
|
# For debugging only: |
||||
|
# |
||||
|
# try: |
||||
|
# self._validate_pending_children() |
||||
|
# except: |
||||
|
# self.ready_exc = sys.exc_info() |
||||
|
# return node |
||||
|
|
||||
|
if CollectStats: |
||||
|
if not hasattr(node, 'stats'): |
||||
|
node.stats = Stats() |
||||
|
StatsNodes.append(node) |
||||
|
S = node.stats |
||||
|
S.considered = S.considered + 1 |
||||
|
else: |
||||
|
S = None |
||||
|
|
||||
|
if T: T.write(self.trace_message(' Considering node %s and its children:' % self.trace_node(node))) |
||||
|
|
||||
|
if state == NODE_NO_STATE: |
||||
|
# Mark this node as being on the execution stack: |
||||
|
node.set_state(NODE_PENDING) |
||||
|
elif state > NODE_PENDING: |
||||
|
# Skip this node if it has already been evaluated: |
||||
|
if S: S.already_handled = S.already_handled + 1 |
||||
|
if T: T.write(self.trace_message(' already handled (executed)')) |
||||
|
continue |
||||
|
|
||||
|
try: |
||||
|
children = node.children() |
||||
|
except SystemExit: |
||||
|
exc_value = sys.exc_info()[1] |
||||
|
e = SCons.Errors.ExplicitExit(node, exc_value.code) |
||||
|
self.ready_exc = (SCons.Errors.ExplicitExit, e) |
||||
|
if T: T.write(self.trace_message(' SystemExit')) |
||||
|
return node |
||||
|
except Exception, e: |
||||
|
# We had a problem just trying to figure out the |
||||
|
# children (like a child couldn't be linked in to a |
||||
|
# VariantDir, or a Scanner threw something). Arrange to |
||||
|
# raise the exception when the Task is "executed." |
||||
|
self.ready_exc = sys.exc_info() |
||||
|
if S: S.problem = S.problem + 1 |
||||
|
if T: T.write(self.trace_message(' exception %s while scanning children.\n' % e)) |
||||
|
return node |
||||
|
|
||||
|
children_not_visited = [] |
||||
|
children_pending = set() |
||||
|
children_not_ready = [] |
||||
|
children_failed = False |
||||
|
|
||||
|
for child in chain(children,node.prerequisites): |
||||
|
childstate = child.get_state() |
||||
|
|
||||
|
if T: T.write(self.trace_message(' ' + self.trace_node(child))) |
||||
|
|
||||
|
if childstate == NODE_NO_STATE: |
||||
|
children_not_visited.append(child) |
||||
|
elif childstate == NODE_PENDING: |
||||
|
children_pending.add(child) |
||||
|
elif childstate == NODE_FAILED: |
||||
|
children_failed = True |
||||
|
|
||||
|
if childstate <= NODE_EXECUTING: |
||||
|
children_not_ready.append(child) |
||||
|
|
||||
|
|
||||
|
# These nodes have not even been visited yet. Add |
||||
|
# them to the list so that on some next pass we can |
||||
|
# take a stab at evaluating them (or their children). |
||||
|
children_not_visited.reverse() |
||||
|
self.candidates.extend(self.order(children_not_visited)) |
||||
|
#if T and children_not_visited: |
||||
|
# T.write(self.trace_message(' adding to candidates: %s' % map(str, children_not_visited))) |
||||
|
# T.write(self.trace_message(' candidates now: %s\n' % map(str, self.candidates))) |
||||
|
|
||||
|
# Skip this node if any of its children have failed. |
||||
|
# |
||||
|
# This catches the case where we're descending a top-level |
||||
|
# target and one of our children failed while trying to be |
||||
|
# built by a *previous* descent of an earlier top-level |
||||
|
# target. |
||||
|
# |
||||
|
# It can also occur if a node is reused in multiple |
||||
|
# targets. One first descends though the one of the |
||||
|
# target, the next time occurs through the other target. |
||||
|
# |
||||
|
# Note that we can only have failed_children if the |
||||
|
# --keep-going flag was used, because without it the build |
||||
|
# will stop before diving in the other branch. |
||||
|
# |
||||
|
# Note that even if one of the children fails, we still |
||||
|
# added the other children to the list of candidate nodes |
||||
|
# to keep on building (--keep-going). |
||||
|
if children_failed: |
||||
|
node.set_state(NODE_FAILED) |
||||
|
|
||||
|
if S: S.child_failed = S.child_failed + 1 |
||||
|
if T: T.write(self.trace_message('****** %s\n' % self.trace_node(node))) |
||||
|
continue |
||||
|
|
||||
|
if children_not_ready: |
||||
|
for child in children_not_ready: |
||||
|
# We're waiting on one or more derived targets |
||||
|
# that have not yet finished building. |
||||
|
if S: S.not_built = S.not_built + 1 |
||||
|
|
||||
|
# Add this node to the waiting parents lists of |
||||
|
# anything we're waiting on, with a reference |
||||
|
# count so we can be put back on the list for |
||||
|
# re-evaluation when they've all finished. |
||||
|
node.ref_count = node.ref_count + child.add_to_waiting_parents(node) |
||||
|
if T: T.write(self.trace_message(' adjusted ref count: %s, child %s' % |
||||
|
(self.trace_node(node), repr(str(child))))) |
||||
|
|
||||
|
if T: |
||||
|
for pc in children_pending: |
||||
|
T.write(self.trace_message(' adding %s to the pending children set\n' % |
||||
|
self.trace_node(pc))) |
||||
|
self.pending_children = self.pending_children | children_pending |
||||
|
|
||||
|
continue |
||||
|
|
||||
|
# Skip this node if it has side-effects that are |
||||
|
# currently being built: |
||||
|
wait_side_effects = False |
||||
|
for se in node.side_effects: |
||||
|
if se.get_state() == NODE_EXECUTING: |
||||
|
se.add_to_waiting_s_e(node) |
||||
|
wait_side_effects = True |
||||
|
|
||||
|
if wait_side_effects: |
||||
|
if S: S.side_effects = S.side_effects + 1 |
||||
|
continue |
||||
|
|
||||
|
# The default when we've gotten through all of the checks above: |
||||
|
# this node is ready to be built. |
||||
|
if S: S.build = S.build + 1 |
||||
|
if T: T.write(self.trace_message('Evaluating %s\n' % |
||||
|
self.trace_node(node))) |
||||
|
|
||||
|
# For debugging only: |
||||
|
# |
||||
|
# try: |
||||
|
# self._validate_pending_children() |
||||
|
# except: |
||||
|
# self.ready_exc = sys.exc_info() |
||||
|
# return node |
||||
|
|
||||
|
return node |
||||
|
|
||||
|
return None |
||||
|
|
||||
|
def next_task(self): |
||||
|
""" |
||||
|
Returns the next task to be executed. |
||||
|
|
||||
|
This simply asks for the next Node to be evaluated, and then wraps |
||||
|
it in the specific Task subclass with which we were initialized. |
||||
|
""" |
||||
|
node = self._find_next_ready_node() |
||||
|
|
||||
|
if node is None: |
||||
|
return None |
||||
|
|
||||
|
tlist = node.get_executor().targets |
||||
|
|
||||
|
task = self.tasker(self, tlist, node in self.original_top, node) |
||||
|
try: |
||||
|
task.make_ready() |
||||
|
except: |
||||
|
# We had a problem just trying to get this task ready (like |
||||
|
# a child couldn't be linked in to a VariantDir when deciding |
||||
|
# whether this node is current). Arrange to raise the |
||||
|
# exception when the Task is "executed." |
||||
|
self.ready_exc = sys.exc_info() |
||||
|
|
||||
|
if self.ready_exc: |
||||
|
task.exception_set(self.ready_exc) |
||||
|
|
||||
|
self.ready_exc = None |
||||
|
|
||||
|
return task |
||||
|
|
||||
|
def will_not_build(self, nodes, node_func=lambda n: None): |
||||
|
""" |
||||
|
Perform clean-up about nodes that will never be built. Invokes |
||||
|
a user defined function on all of these nodes (including all |
||||
|
of their parents). |
||||
|
""" |
||||
|
|
||||
|
T = self.trace |
||||
|
|
||||
|
pending_children = self.pending_children |
||||
|
|
||||
|
to_visit = set(nodes) |
||||
|
pending_children = pending_children - to_visit |
||||
|
|
||||
|
if T: |
||||
|
for n in nodes: |
||||
|
T.write(self.trace_message(' removing node %s from the pending children set\n' % |
||||
|
self.trace_node(n))) |
||||
|
try: |
||||
|
while 1: |
||||
|
try: |
||||
|
node = to_visit.pop() |
||||
|
except AttributeError: |
||||
|
# Python 1.5.2 |
||||
|
if len(to_visit): |
||||
|
node = to_visit[0] |
||||
|
to_visit.remove(node) |
||||
|
else: |
||||
|
break |
||||
|
|
||||
|
node_func(node) |
||||
|
|
||||
|
# Prune recursion by flushing the waiting children |
||||
|
# list immediately. |
||||
|
parents = node.waiting_parents |
||||
|
node.waiting_parents = set() |
||||
|
|
||||
|
to_visit = to_visit | parents |
||||
|
pending_children = pending_children - parents |
||||
|
|
||||
|
for p in parents: |
||||
|
p.ref_count = p.ref_count - 1 |
||||
|
if T: T.write(self.trace_message(' removing parent %s from the pending children set\n' % |
||||
|
self.trace_node(p))) |
||||
|
except KeyError: |
||||
|
# The container to_visit has been emptied. |
||||
|
pass |
||||
|
|
||||
|
# We have the stick back the pending_children list into the |
||||
|
# task master because the python 1.5.2 compatibility does not |
||||
|
# allow us to use in-place updates |
||||
|
self.pending_children = pending_children |
||||
|
|
||||
|
def stop(self): |
||||
|
""" |
||||
|
Stops the current build completely. |
||||
|
""" |
||||
|
self.next_candidate = self.no_next_candidate |
||||
|
|
||||
|
def cleanup(self): |
||||
|
""" |
||||
|
Check for dependency cycles. |
||||
|
""" |
||||
|
if not self.pending_children: |
||||
|
return |
||||
|
|
||||
|
# TODO(1.5) |
||||
|
#nclist = [ (n, find_cycle([n], set())) for n in self.pending_children ] |
||||
|
nclist = map(lambda n: (n, find_cycle([n], set())), self.pending_children) |
||||
|
|
||||
|
# TODO(1.5) |
||||
|
#genuine_cycles = [ |
||||
|
# node for node, cycle in nclist |
||||
|
# if cycle or node.get_state() != NODE_EXECUTED |
||||
|
#] |
||||
|
genuine_cycles = filter(lambda t: t[1] or t[0].get_state() != NODE_EXECUTED, nclist) |
||||
|
if not genuine_cycles: |
||||
|
# All of the "cycles" found were single nodes in EXECUTED state, |
||||
|
# which is to say, they really weren't cycles. Just return. |
||||
|
return |
||||
|
|
||||
|
desc = 'Found dependency cycle(s):\n' |
||||
|
for node, cycle in nclist: |
||||
|
if cycle: |
||||
|
desc = desc + " " + string.join(map(str, cycle), " -> ") + "\n" |
||||
|
else: |
||||
|
desc = desc + \ |
||||
|
" Internal Error: no cycle found for node %s (%s) in state %s\n" % \ |
||||
|
(node, repr(node), StateString[node.get_state()]) |
||||
|
|
||||
|
raise SCons.Errors.UserError, desc |
@ -0,0 +1,55 @@ |
|||||
|
"""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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/386asm.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
from SCons.Tool.PharLapCommon import addPharLapPaths |
||||
|
import SCons.Util |
||||
|
|
||||
|
as_module = __import__('as', globals(), locals(), []) |
||||
|
|
||||
|
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') |
@ -0,0 +1,59 @@ |
|||||
|
"""SCons.Tool.BitKeeper.py |
||||
|
|
||||
|
Tool-specific initialization for the BitKeeper source code control |
||||
|
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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/BitKeeper.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons.Action |
||||
|
import SCons.Builder |
||||
|
import SCons.Util |
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add a Builder factory function and construction variables for |
||||
|
BitKeeper to an Environment.""" |
||||
|
|
||||
|
def BitKeeperFactory(env=env): |
||||
|
""" """ |
||||
|
act = SCons.Action.Action("$BITKEEPERCOM", "$BITKEEPERCOMSTR") |
||||
|
return SCons.Builder.Builder(action = act, env = env) |
||||
|
|
||||
|
#setattr(env, 'BitKeeper', BitKeeperFactory) |
||||
|
env.BitKeeper = BitKeeperFactory |
||||
|
|
||||
|
env['BITKEEPER'] = 'bk' |
||||
|
env['BITKEEPERGET'] = '$BITKEEPER get' |
||||
|
env['BITKEEPERGETFLAGS'] = SCons.Util.CLVar('') |
||||
|
env['BITKEEPERCOM'] = '$BITKEEPERGET $BITKEEPERGETFLAGS $TARGET' |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect('bk') |
@ -0,0 +1,67 @@ |
|||||
|
"""SCons.Tool.CVS.py |
||||
|
|
||||
|
Tool-specific initialization for CVS. |
||||
|
|
||||
|
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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/CVS.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons.Action |
||||
|
import SCons.Builder |
||||
|
import SCons.Util |
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add a Builder factory function and construction variables for |
||||
|
CVS to an Environment.""" |
||||
|
|
||||
|
def CVSFactory(repos, module='', env=env): |
||||
|
""" """ |
||||
|
# fail if repos is not an absolute path name? |
||||
|
if module != '': |
||||
|
# Don't use os.path.join() because the name we fetch might |
||||
|
# be across a network and must use POSIX slashes as separators. |
||||
|
module = module + '/' |
||||
|
env['CVSCOM'] = '$CVS $CVSFLAGS co $CVSCOFLAGS -d ${TARGET.dir} $CVSMODULE${TARGET.posix}' |
||||
|
act = SCons.Action.Action('$CVSCOM', '$CVSCOMSTR') |
||||
|
return SCons.Builder.Builder(action = act, |
||||
|
env = env, |
||||
|
CVSREPOSITORY = repos, |
||||
|
CVSMODULE = module) |
||||
|
|
||||
|
#setattr(env, 'CVS', CVSFactory) |
||||
|
env.CVS = CVSFactory |
||||
|
|
||||
|
env['CVS'] = 'cvs' |
||||
|
env['CVSFLAGS'] = SCons.Util.CLVar('-d $CVSREPOSITORY') |
||||
|
env['CVSCOFLAGS'] = SCons.Util.CLVar('') |
||||
|
env['CVSCOM'] = '$CVS $CVSFLAGS co $CVSCOFLAGS ${TARGET.posix}' |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect('cvs') |
@ -0,0 +1,241 @@ |
|||||
|
"""SCons.Tool.FortranCommon |
||||
|
|
||||
|
Stuff for processing Fortran, common to all fortran dialects. |
||||
|
|
||||
|
""" |
||||
|
|
||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/FortranCommon.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import re |
||||
|
import string |
||||
|
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 ([], []) |
||||
|
mod_regex = """(?i)^\s*MODULE\s+(?!PROCEDURE)(\w+)""" |
||||
|
cre = re.compile(mod_regex,re.M) |
||||
|
# Retrieve all USE'd module names |
||||
|
modules = cre.findall(node.get_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 = map(lambda x, s=suffix: string.lower(x) + s, 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 = string.upper(s) |
||||
|
upper_suffixes = map(string.upper, 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 not env.has_key('%sFLAGS' % dialect): |
||||
|
env['%sFLAGS' % dialect] = SCons.Util.CLVar('') |
||||
|
|
||||
|
if not env.has_key('SH%sFLAGS' % dialect): |
||||
|
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 not env.has_key('INC%sPREFIX' % dialect): |
||||
|
env['INC%sPREFIX' % dialect] = '$INCPREFIX' |
||||
|
|
||||
|
if not env.has_key('INC%sSUFFIX' % dialect): |
||||
|
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_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) |
@ -0,0 +1,317 @@ |
|||||
|
"""SCons.Tool.JavaCommon |
||||
|
|
||||
|
Stuff for processing Java. |
||||
|
|
||||
|
""" |
||||
|
|
||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/JavaCommon.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import os |
||||
|
import os.path |
||||
|
import re |
||||
|
import string |
||||
|
|
||||
|
java_parsing = 1 |
||||
|
|
||||
|
default_java_version = '1.4' |
||||
|
|
||||
|
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 not version in ('1.1', '1.2', '1.3','1.4', '1.5', '1.6'): |
||||
|
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(string.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]: |
||||
|
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'): |
||||
|
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(string.join(className, '$')) |
||||
|
|
||||
|
self.nextAnon = self.nextAnon + 1 |
||||
|
self.__getAnonStack().append(0) |
||||
|
|
||||
|
def setPackage(self, package): |
||||
|
self.package = package |
||||
|
|
||||
|
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() |
||||
|
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' (Tigris Issue 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): |
||||
|
return parse_java(open(fn, 'r').read(), 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 = string.replace(initial.package, '.', 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(file) |
@ -0,0 +1,98 @@ |
|||||
|
"""SCons.Tool.Perforce.py |
||||
|
|
||||
|
Tool-specific initialization for Perforce Source Code Management 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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/Perforce.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import os |
||||
|
|
||||
|
import SCons.Action |
||||
|
import SCons.Builder |
||||
|
import SCons.Node.FS |
||||
|
import SCons.Util |
||||
|
|
||||
|
# This function should maybe be moved to SCons.Util? |
||||
|
from SCons.Tool.PharLapCommon import addPathIfNotExists |
||||
|
|
||||
|
|
||||
|
|
||||
|
# Variables that we want to import from the base OS environment. |
||||
|
_import_env = [ 'P4PORT', 'P4CLIENT', 'P4USER', 'USER', 'USERNAME', 'P4PASSWD', |
||||
|
'P4CHARSET', 'P4LANGUAGE', 'SYSTEMROOT' ] |
||||
|
|
||||
|
PerforceAction = SCons.Action.Action('$P4COM', '$P4COMSTR') |
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add a Builder factory function and construction variables for |
||||
|
Perforce to an Environment.""" |
||||
|
|
||||
|
def PerforceFactory(env=env): |
||||
|
""" """ |
||||
|
return SCons.Builder.Builder(action = PerforceAction, env = env) |
||||
|
|
||||
|
#setattr(env, 'Perforce', PerforceFactory) |
||||
|
env.Perforce = PerforceFactory |
||||
|
|
||||
|
env['P4'] = 'p4' |
||||
|
env['P4FLAGS'] = SCons.Util.CLVar('') |
||||
|
env['P4COM'] = '$P4 $P4FLAGS sync $TARGET' |
||||
|
try: |
||||
|
environ = env['ENV'] |
||||
|
except KeyError: |
||||
|
environ = {} |
||||
|
env['ENV'] = environ |
||||
|
|
||||
|
# Perforce seems to use the PWD environment variable rather than |
||||
|
# calling getcwd() for itself, which is odd. If no PWD variable |
||||
|
# is present, p4 WILL call getcwd, but this seems to cause problems |
||||
|
# with good ol' Windows's tilde-mangling for long file names. |
||||
|
environ['PWD'] = env.Dir('#').get_abspath() |
||||
|
|
||||
|
for var in _import_env: |
||||
|
v = os.environ.get(var) |
||||
|
if v: |
||||
|
environ[var] = v |
||||
|
|
||||
|
if SCons.Util.can_read_reg: |
||||
|
# If we can read the registry, add the path to Perforce to our environment. |
||||
|
try: |
||||
|
k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE, |
||||
|
'Software\\Perforce\\environment') |
||||
|
val, tok = SCons.Util.RegQueryValueEx(k, 'P4INSTROOT') |
||||
|
addPathIfNotExists(environ, 'PATH', val) |
||||
|
except SCons.Util.RegError: |
||||
|
# Can't detect where Perforce is, hope the user has it set in the |
||||
|
# PATH. |
||||
|
pass |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect('p4') |
@ -0,0 +1,132 @@ |
|||||
|
"""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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/PharLapCommon.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import os |
||||
|
import os.path |
||||
|
import SCons.Errors |
||||
|
import SCons.Util |
||||
|
import re |
||||
|
import string |
||||
|
|
||||
|
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?" |
||||
|
mo = REGEX_ETS_VER.search(open(include_path, 'r').read()) |
||||
|
if mo: |
||||
|
return int(mo.group(1)) |
||||
|
# Default return for Phar Lap 9.1 |
||||
|
return 910 |
||||
|
|
||||
|
def addPathIfNotExists(env_dict, key, path, sep=os.pathsep): |
||||
|
"""This function will take 'key' out of the dictionary |
||||
|
'env_dict', then add the path 'path' to that key if it is not |
||||
|
already there. This treats the value of env_dict[key] as if it |
||||
|
has a similar format to the PATH variable...a list of paths |
||||
|
separated by tokens. The 'path' will get added to the list if it |
||||
|
is not already there.""" |
||||
|
try: |
||||
|
is_list = 1 |
||||
|
paths = env_dict[key] |
||||
|
if not SCons.Util.is_List(env_dict[key]): |
||||
|
paths = string.split(paths, sep) |
||||
|
is_list = 0 |
||||
|
if not os.path.normcase(path) in map(os.path.normcase, paths): |
||||
|
paths = [ path ] + paths |
||||
|
if is_list: |
||||
|
env_dict[key] = paths |
||||
|
else: |
||||
|
env_dict[key] = string.join(paths, sep) |
||||
|
except KeyError: |
||||
|
env_dict[key] = path |
||||
|
|
||||
|
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 |
||||
|
addPathIfNotExists(env_dict, 'PATH', |
||||
|
os.path.join(ph_path, 'bin')) |
||||
|
addPathIfNotExists(env_dict, 'INCLUDE', |
||||
|
os.path.join(ph_path, 'include')) |
||||
|
addPathIfNotExists(env_dict, 'LIB', |
||||
|
os.path.join(ph_path, 'lib')) |
||||
|
addPathIfNotExists(env_dict, 'LIB', |
||||
|
os.path.join(ph_path, os.path.normpath('lib/vclib'))) |
||||
|
|
||||
|
env['PHARLAP_PATH'] = getPharLapPath() |
||||
|
env['PHARLAP_VERSION'] = str(getPharLapVersion()) |
||||
|
|
@ -0,0 +1,58 @@ |
|||||
|
"""SCons.Tool.RCS.py |
||||
|
|
||||
|
Tool-specific initialization for RCS. |
||||
|
|
||||
|
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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/RCS.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons.Action |
||||
|
import SCons.Builder |
||||
|
import SCons.Util |
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add a Builder factory function and construction variables for |
||||
|
RCS to an Environment.""" |
||||
|
|
||||
|
def RCSFactory(env=env): |
||||
|
""" """ |
||||
|
act = SCons.Action.Action('$RCS_COCOM', '$RCS_COCOMSTR') |
||||
|
return SCons.Builder.Builder(action = act, env = env) |
||||
|
|
||||
|
#setattr(env, 'RCS', RCSFactory) |
||||
|
env.RCS = RCSFactory |
||||
|
|
||||
|
env['RCS'] = 'rcs' |
||||
|
env['RCS_CO'] = 'co' |
||||
|
env['RCS_COFLAGS'] = SCons.Util.CLVar('') |
||||
|
env['RCS_COCOM'] = '$RCS_CO $RCS_COFLAGS $TARGET' |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect('rcs') |
@ -0,0 +1,58 @@ |
|||||
|
"""SCons.Tool.SCCS.py |
||||
|
|
||||
|
Tool-specific initialization for SCCS. |
||||
|
|
||||
|
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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/SCCS.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons.Action |
||||
|
import SCons.Builder |
||||
|
import SCons.Util |
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add a Builder factory function and construction variables for |
||||
|
SCCS to an Environment.""" |
||||
|
|
||||
|
def SCCSFactory(env=env): |
||||
|
""" """ |
||||
|
act = SCons.Action.Action('$SCCSCOM', '$SCCSCOMSTR') |
||||
|
return SCons.Builder.Builder(action = act, env = env) |
||||
|
|
||||
|
#setattr(env, 'SCCS', SCCSFactory) |
||||
|
env.SCCS = SCCSFactory |
||||
|
|
||||
|
env['SCCS'] = 'sccs' |
||||
|
env['SCCSFLAGS'] = SCons.Util.CLVar('') |
||||
|
env['SCCSGETFLAGS'] = SCons.Util.CLVar('') |
||||
|
env['SCCSCOM'] = '$SCCS $SCCSFLAGS get $SCCSGETFLAGS $TARGET' |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect('sccs') |
@ -0,0 +1,65 @@ |
|||||
|
"""SCons.Tool.Subversion.py |
||||
|
|
||||
|
Tool-specific initialization for Subversion. |
||||
|
|
||||
|
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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/Subversion.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import os.path |
||||
|
|
||||
|
import SCons.Action |
||||
|
import SCons.Builder |
||||
|
import SCons.Util |
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add a Builder factory function and construction variables for |
||||
|
Subversion to an Environment.""" |
||||
|
|
||||
|
def SubversionFactory(repos, module='', env=env): |
||||
|
""" """ |
||||
|
# fail if repos is not an absolute path name? |
||||
|
if module != '': |
||||
|
module = os.path.join(module, '') |
||||
|
act = SCons.Action.Action('$SVNCOM', '$SVNCOMSTR') |
||||
|
return SCons.Builder.Builder(action = act, |
||||
|
env = env, |
||||
|
SVNREPOSITORY = repos, |
||||
|
SVNMODULE = module) |
||||
|
|
||||
|
#setattr(env, 'Subversion', SubversionFactory) |
||||
|
env.Subversion = SubversionFactory |
||||
|
|
||||
|
env['SVN'] = 'svn' |
||||
|
env['SVNFLAGS'] = SCons.Util.CLVar('') |
||||
|
env['SVNCOM'] = '$SVN $SVNFLAGS cat $SVNREPOSITORY/$SVNMODULE$TARGET > $TARGET' |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect('svn') |
@ -0,0 +1,667 @@ |
|||||
|
"""SCons.Tool |
||||
|
|
||||
|
SCons tool selection. |
||||
|
|
||||
|
This looks for modules that define a callable object that can modify |
||||
|
a construction environment as appropriate for a given tool (or tool |
||||
|
chain). |
||||
|
|
||||
|
Note that because this subsystem just *selects* a callable that can |
||||
|
modify a construction environment, it's possible for people to define |
||||
|
their own "tool specification" in an arbitrary callable function. No |
||||
|
one needs to use or tie in to this subsystem in order to roll their own |
||||
|
tool definition. |
||||
|
""" |
||||
|
|
||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/__init__.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import imp |
||||
|
import sys |
||||
|
|
||||
|
import SCons.Builder |
||||
|
import SCons.Errors |
||||
|
import SCons.Node.FS |
||||
|
import SCons.Scanner |
||||
|
import SCons.Scanner.C |
||||
|
import SCons.Scanner.D |
||||
|
import SCons.Scanner.LaTeX |
||||
|
import SCons.Scanner.Prog |
||||
|
|
||||
|
DefaultToolpath=[] |
||||
|
|
||||
|
CScanner = SCons.Scanner.C.CScanner() |
||||
|
DScanner = SCons.Scanner.D.DScanner() |
||||
|
LaTeXScanner = SCons.Scanner.LaTeX.LaTeXScanner() |
||||
|
PDFLaTeXScanner = SCons.Scanner.LaTeX.PDFLaTeXScanner() |
||||
|
ProgramScanner = SCons.Scanner.Prog.ProgramScanner() |
||||
|
SourceFileScanner = SCons.Scanner.Base({}, name='SourceFileScanner') |
||||
|
|
||||
|
CSuffixes = [".c", ".C", ".cxx", ".cpp", ".c++", ".cc", |
||||
|
".h", ".H", ".hxx", ".hpp", ".hh", |
||||
|
".F", ".fpp", ".FPP", |
||||
|
".m", ".mm", |
||||
|
".S", ".spp", ".SPP"] |
||||
|
|
||||
|
DSuffixes = ['.d'] |
||||
|
|
||||
|
IDLSuffixes = [".idl", ".IDL"] |
||||
|
|
||||
|
LaTeXSuffixes = [".tex", ".ltx", ".latex"] |
||||
|
|
||||
|
for suffix in CSuffixes: |
||||
|
SourceFileScanner.add_scanner(suffix, CScanner) |
||||
|
|
||||
|
for suffix in DSuffixes: |
||||
|
SourceFileScanner.add_scanner(suffix, DScanner) |
||||
|
|
||||
|
# FIXME: what should be done here? Two scanners scan the same extensions, |
||||
|
# but look for different files, e.g., "picture.eps" vs. "picture.pdf". |
||||
|
# The builders for DVI and PDF explicitly reference their scanners |
||||
|
# I think that means this is not needed??? |
||||
|
for suffix in LaTeXSuffixes: |
||||
|
SourceFileScanner.add_scanner(suffix, LaTeXScanner) |
||||
|
SourceFileScanner.add_scanner(suffix, PDFLaTeXScanner) |
||||
|
|
||||
|
class Tool: |
||||
|
def __init__(self, name, toolpath=[], **kw): |
||||
|
self.name = name |
||||
|
self.toolpath = toolpath + DefaultToolpath |
||||
|
# remember these so we can merge them into the call |
||||
|
self.init_kw = kw |
||||
|
|
||||
|
module = self._tool_module() |
||||
|
self.generate = module.generate |
||||
|
self.exists = module.exists |
||||
|
if hasattr(module, 'options'): |
||||
|
self.options = module.options |
||||
|
|
||||
|
def _tool_module(self): |
||||
|
# TODO: Interchange zipimport with normal initilization for better error reporting |
||||
|
oldpythonpath = sys.path |
||||
|
sys.path = self.toolpath + sys.path |
||||
|
|
||||
|
try: |
||||
|
try: |
||||
|
file, path, desc = imp.find_module(self.name, self.toolpath) |
||||
|
try: |
||||
|
return imp.load_module(self.name, file, path, desc) |
||||
|
finally: |
||||
|
if file: |
||||
|
file.close() |
||||
|
except ImportError, e: |
||||
|
if str(e)!="No module named %s"%self.name: |
||||
|
raise SCons.Errors.EnvironmentError, e |
||||
|
try: |
||||
|
import zipimport |
||||
|
except ImportError: |
||||
|
pass |
||||
|
else: |
||||
|
for aPath in self.toolpath: |
||||
|
try: |
||||
|
importer = zipimport.zipimporter(aPath) |
||||
|
return importer.load_module(self.name) |
||||
|
except ImportError, e: |
||||
|
pass |
||||
|
finally: |
||||
|
sys.path = oldpythonpath |
||||
|
|
||||
|
full_name = 'SCons.Tool.' + self.name |
||||
|
try: |
||||
|
return sys.modules[full_name] |
||||
|
except KeyError: |
||||
|
try: |
||||
|
smpath = sys.modules['SCons.Tool'].__path__ |
||||
|
try: |
||||
|
file, path, desc = imp.find_module(self.name, smpath) |
||||
|
module = imp.load_module(full_name, file, path, desc) |
||||
|
setattr(SCons.Tool, self.name, module) |
||||
|
if file: |
||||
|
file.close() |
||||
|
return module |
||||
|
except ImportError, e: |
||||
|
if str(e)!="No module named %s"%self.name: |
||||
|
raise SCons.Errors.EnvironmentError, e |
||||
|
try: |
||||
|
import zipimport |
||||
|
importer = zipimport.zipimporter( sys.modules['SCons.Tool'].__path__[0] ) |
||||
|
module = importer.load_module(full_name) |
||||
|
setattr(SCons.Tool, self.name, module) |
||||
|
return module |
||||
|
except ImportError, e: |
||||
|
m = "No tool named '%s': %s" % (self.name, e) |
||||
|
raise SCons.Errors.EnvironmentError, m |
||||
|
except ImportError, e: |
||||
|
m = "No tool named '%s': %s" % (self.name, e) |
||||
|
raise SCons.Errors.EnvironmentError, m |
||||
|
|
||||
|
def __call__(self, env, *args, **kw): |
||||
|
if self.init_kw is not None: |
||||
|
# Merge call kws into init kws; |
||||
|
# but don't bash self.init_kw. |
||||
|
if kw is not None: |
||||
|
call_kw = kw |
||||
|
kw = self.init_kw.copy() |
||||
|
kw.update(call_kw) |
||||
|
else: |
||||
|
kw = self.init_kw |
||||
|
env.Append(TOOLS = [ self.name ]) |
||||
|
if hasattr(self, 'options'): |
||||
|
import SCons.Variables |
||||
|
if not env.has_key('options'): |
||||
|
from SCons.Script import ARGUMENTS |
||||
|
env['options']=SCons.Variables.Variables(args=ARGUMENTS) |
||||
|
opts=env['options'] |
||||
|
|
||||
|
self.options(opts) |
||||
|
opts.Update(env) |
||||
|
|
||||
|
apply(self.generate, ( env, ) + args, kw) |
||||
|
|
||||
|
def __str__(self): |
||||
|
return self.name |
||||
|
|
||||
|
########################################################################## |
||||
|
# Create common executable program / library / object builders |
||||
|
|
||||
|
def createProgBuilder(env): |
||||
|
"""This is a utility function that creates the Program |
||||
|
Builder in an Environment if it is not there already. |
||||
|
|
||||
|
If it is already there, we return the existing one. |
||||
|
""" |
||||
|
|
||||
|
try: |
||||
|
program = env['BUILDERS']['Program'] |
||||
|
except KeyError: |
||||
|
import SCons.Defaults |
||||
|
program = SCons.Builder.Builder(action = SCons.Defaults.LinkAction, |
||||
|
emitter = '$PROGEMITTER', |
||||
|
prefix = '$PROGPREFIX', |
||||
|
suffix = '$PROGSUFFIX', |
||||
|
src_suffix = '$OBJSUFFIX', |
||||
|
src_builder = 'Object', |
||||
|
target_scanner = ProgramScanner) |
||||
|
env['BUILDERS']['Program'] = program |
||||
|
|
||||
|
return program |
||||
|
|
||||
|
def createStaticLibBuilder(env): |
||||
|
"""This is a utility function that creates the StaticLibrary |
||||
|
Builder in an Environment if it is not there already. |
||||
|
|
||||
|
If it is already there, we return the existing one. |
||||
|
""" |
||||
|
|
||||
|
try: |
||||
|
static_lib = env['BUILDERS']['StaticLibrary'] |
||||
|
except KeyError: |
||||
|
action_list = [ SCons.Action.Action("$ARCOM", "$ARCOMSTR") ] |
||||
|
if env.Detect('ranlib'): |
||||
|
ranlib_action = SCons.Action.Action("$RANLIBCOM", "$RANLIBCOMSTR") |
||||
|
action_list.append(ranlib_action) |
||||
|
|
||||
|
static_lib = SCons.Builder.Builder(action = action_list, |
||||
|
emitter = '$LIBEMITTER', |
||||
|
prefix = '$LIBPREFIX', |
||||
|
suffix = '$LIBSUFFIX', |
||||
|
src_suffix = '$OBJSUFFIX', |
||||
|
src_builder = 'StaticObject') |
||||
|
env['BUILDERS']['StaticLibrary'] = static_lib |
||||
|
env['BUILDERS']['Library'] = static_lib |
||||
|
|
||||
|
return static_lib |
||||
|
|
||||
|
def createSharedLibBuilder(env): |
||||
|
"""This is a utility function that creates the SharedLibrary |
||||
|
Builder in an Environment if it is not there already. |
||||
|
|
||||
|
If it is already there, we return the existing one. |
||||
|
""" |
||||
|
|
||||
|
try: |
||||
|
shared_lib = env['BUILDERS']['SharedLibrary'] |
||||
|
except KeyError: |
||||
|
import SCons.Defaults |
||||
|
action_list = [ SCons.Defaults.SharedCheck, |
||||
|
SCons.Defaults.ShLinkAction ] |
||||
|
shared_lib = SCons.Builder.Builder(action = action_list, |
||||
|
emitter = "$SHLIBEMITTER", |
||||
|
prefix = '$SHLIBPREFIX', |
||||
|
suffix = '$SHLIBSUFFIX', |
||||
|
target_scanner = ProgramScanner, |
||||
|
src_suffix = '$SHOBJSUFFIX', |
||||
|
src_builder = 'SharedObject') |
||||
|
env['BUILDERS']['SharedLibrary'] = shared_lib |
||||
|
|
||||
|
return shared_lib |
||||
|
|
||||
|
def createLoadableModuleBuilder(env): |
||||
|
"""This is a utility function that creates the LoadableModule |
||||
|
Builder in an Environment if it is not there already. |
||||
|
|
||||
|
If it is already there, we return the existing one. |
||||
|
""" |
||||
|
|
||||
|
try: |
||||
|
ld_module = env['BUILDERS']['LoadableModule'] |
||||
|
except KeyError: |
||||
|
import SCons.Defaults |
||||
|
action_list = [ SCons.Defaults.SharedCheck, |
||||
|
SCons.Defaults.LdModuleLinkAction ] |
||||
|
ld_module = SCons.Builder.Builder(action = action_list, |
||||
|
emitter = "$SHLIBEMITTER", |
||||
|
prefix = '$LDMODULEPREFIX', |
||||
|
suffix = '$LDMODULESUFFIX', |
||||
|
target_scanner = ProgramScanner, |
||||
|
src_suffix = '$SHOBJSUFFIX', |
||||
|
src_builder = 'SharedObject') |
||||
|
env['BUILDERS']['LoadableModule'] = ld_module |
||||
|
|
||||
|
return ld_module |
||||
|
|
||||
|
def createObjBuilders(env): |
||||
|
"""This is a utility function that creates the StaticObject |
||||
|
and SharedObject Builders in an Environment if they |
||||
|
are not there already. |
||||
|
|
||||
|
If they are there already, we return the existing ones. |
||||
|
|
||||
|
This is a separate function because soooo many Tools |
||||
|
use this functionality. |
||||
|
|
||||
|
The return is a 2-tuple of (StaticObject, SharedObject) |
||||
|
""" |
||||
|
|
||||
|
|
||||
|
try: |
||||
|
static_obj = env['BUILDERS']['StaticObject'] |
||||
|
except KeyError: |
||||
|
static_obj = SCons.Builder.Builder(action = {}, |
||||
|
emitter = {}, |
||||
|
prefix = '$OBJPREFIX', |
||||
|
suffix = '$OBJSUFFIX', |
||||
|
src_builder = ['CFile', 'CXXFile'], |
||||
|
source_scanner = SourceFileScanner, |
||||
|
single_source = 1) |
||||
|
env['BUILDERS']['StaticObject'] = static_obj |
||||
|
env['BUILDERS']['Object'] = static_obj |
||||
|
|
||||
|
try: |
||||
|
shared_obj = env['BUILDERS']['SharedObject'] |
||||
|
except KeyError: |
||||
|
shared_obj = SCons.Builder.Builder(action = {}, |
||||
|
emitter = {}, |
||||
|
prefix = '$SHOBJPREFIX', |
||||
|
suffix = '$SHOBJSUFFIX', |
||||
|
src_builder = ['CFile', 'CXXFile'], |
||||
|
source_scanner = SourceFileScanner, |
||||
|
single_source = 1) |
||||
|
env['BUILDERS']['SharedObject'] = shared_obj |
||||
|
|
||||
|
return (static_obj, shared_obj) |
||||
|
|
||||
|
def createCFileBuilders(env): |
||||
|
"""This is a utility function that creates the CFile/CXXFile |
||||
|
Builders in an Environment if they |
||||
|
are not there already. |
||||
|
|
||||
|
If they are there already, we return the existing ones. |
||||
|
|
||||
|
This is a separate function because soooo many Tools |
||||
|
use this functionality. |
||||
|
|
||||
|
The return is a 2-tuple of (CFile, CXXFile) |
||||
|
""" |
||||
|
|
||||
|
try: |
||||
|
c_file = env['BUILDERS']['CFile'] |
||||
|
except KeyError: |
||||
|
c_file = SCons.Builder.Builder(action = {}, |
||||
|
emitter = {}, |
||||
|
suffix = {None:'$CFILESUFFIX'}) |
||||
|
env['BUILDERS']['CFile'] = c_file |
||||
|
|
||||
|
env.SetDefault(CFILESUFFIX = '.c') |
||||
|
|
||||
|
try: |
||||
|
cxx_file = env['BUILDERS']['CXXFile'] |
||||
|
except KeyError: |
||||
|
cxx_file = SCons.Builder.Builder(action = {}, |
||||
|
emitter = {}, |
||||
|
suffix = {None:'$CXXFILESUFFIX'}) |
||||
|
env['BUILDERS']['CXXFile'] = cxx_file |
||||
|
env.SetDefault(CXXFILESUFFIX = '.cc') |
||||
|
|
||||
|
return (c_file, cxx_file) |
||||
|
|
||||
|
########################################################################## |
||||
|
# Create common Java builders |
||||
|
|
||||
|
def CreateJarBuilder(env): |
||||
|
try: |
||||
|
java_jar = env['BUILDERS']['Jar'] |
||||
|
except KeyError: |
||||
|
fs = SCons.Node.FS.get_default_fs() |
||||
|
jar_com = SCons.Action.Action('$JARCOM', '$JARCOMSTR') |
||||
|
java_jar = SCons.Builder.Builder(action = jar_com, |
||||
|
suffix = '$JARSUFFIX', |
||||
|
src_suffix = '$JAVACLASSSUFIX', |
||||
|
src_builder = 'JavaClassFile', |
||||
|
source_factory = fs.Entry) |
||||
|
env['BUILDERS']['Jar'] = java_jar |
||||
|
return java_jar |
||||
|
|
||||
|
def CreateJavaHBuilder(env): |
||||
|
try: |
||||
|
java_javah = env['BUILDERS']['JavaH'] |
||||
|
except KeyError: |
||||
|
fs = SCons.Node.FS.get_default_fs() |
||||
|
java_javah_com = SCons.Action.Action('$JAVAHCOM', '$JAVAHCOMSTR') |
||||
|
java_javah = SCons.Builder.Builder(action = java_javah_com, |
||||
|
src_suffix = '$JAVACLASSSUFFIX', |
||||
|
target_factory = fs.Entry, |
||||
|
source_factory = fs.File, |
||||
|
src_builder = 'JavaClassFile') |
||||
|
env['BUILDERS']['JavaH'] = java_javah |
||||
|
return java_javah |
||||
|
|
||||
|
def CreateJavaClassFileBuilder(env): |
||||
|
try: |
||||
|
java_class_file = env['BUILDERS']['JavaClassFile'] |
||||
|
except KeyError: |
||||
|
fs = SCons.Node.FS.get_default_fs() |
||||
|
javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR') |
||||
|
java_class_file = SCons.Builder.Builder(action = javac_com, |
||||
|
emitter = {}, |
||||
|
#suffix = '$JAVACLASSSUFFIX', |
||||
|
src_suffix = '$JAVASUFFIX', |
||||
|
src_builder = ['JavaFile'], |
||||
|
target_factory = fs.Entry, |
||||
|
source_factory = fs.File) |
||||
|
env['BUILDERS']['JavaClassFile'] = java_class_file |
||||
|
return java_class_file |
||||
|
|
||||
|
def CreateJavaClassDirBuilder(env): |
||||
|
try: |
||||
|
java_class_dir = env['BUILDERS']['JavaClassDir'] |
||||
|
except KeyError: |
||||
|
fs = SCons.Node.FS.get_default_fs() |
||||
|
javac_com = SCons.Action.Action('$JAVACCOM', '$JAVACCOMSTR') |
||||
|
java_class_dir = SCons.Builder.Builder(action = javac_com, |
||||
|
emitter = {}, |
||||
|
target_factory = fs.Dir, |
||||
|
source_factory = fs.Dir) |
||||
|
env['BUILDERS']['JavaClassDir'] = java_class_dir |
||||
|
return java_class_dir |
||||
|
|
||||
|
def CreateJavaFileBuilder(env): |
||||
|
try: |
||||
|
java_file = env['BUILDERS']['JavaFile'] |
||||
|
except KeyError: |
||||
|
java_file = SCons.Builder.Builder(action = {}, |
||||
|
emitter = {}, |
||||
|
suffix = {None:'$JAVASUFFIX'}) |
||||
|
env['BUILDERS']['JavaFile'] = java_file |
||||
|
env['JAVASUFFIX'] = '.java' |
||||
|
return java_file |
||||
|
|
||||
|
class ToolInitializerMethod: |
||||
|
""" |
||||
|
This is added to a construction environment in place of a |
||||
|
method(s) normally called for a Builder (env.Object, env.StaticObject, |
||||
|
etc.). When called, it has its associated ToolInitializer |
||||
|
object search the specified list of tools and apply the first |
||||
|
one that exists to the construction environment. It then calls |
||||
|
whatever builder was (presumably) added to the construction |
||||
|
environment in place of this particular instance. |
||||
|
""" |
||||
|
def __init__(self, name, initializer): |
||||
|
""" |
||||
|
Note: we store the tool name as __name__ so it can be used by |
||||
|
the class that attaches this to a construction environment. |
||||
|
""" |
||||
|
self.__name__ = name |
||||
|
self.initializer = initializer |
||||
|
|
||||
|
def get_builder(self, env): |
||||
|
""" |
||||
|
Returns the appropriate real Builder for this method name |
||||
|
after having the associated ToolInitializer object apply |
||||
|
the appropriate Tool module. |
||||
|
""" |
||||
|
builder = getattr(env, self.__name__) |
||||
|
|
||||
|
self.initializer.apply_tools(env) |
||||
|
|
||||
|
builder = getattr(env, self.__name__) |
||||
|
if builder is self: |
||||
|
# There was no Builder added, which means no valid Tool |
||||
|
# for this name was found (or possibly there's a mismatch |
||||
|
# between the name we were called by and the Builder name |
||||
|
# added by the Tool module). |
||||
|
return None |
||||
|
|
||||
|
self.initializer.remove_methods(env) |
||||
|
|
||||
|
return builder |
||||
|
|
||||
|
def __call__(self, env, *args, **kw): |
||||
|
""" |
||||
|
""" |
||||
|
builder = self.get_builder(env) |
||||
|
if builder is None: |
||||
|
return [], [] |
||||
|
return apply(builder, args, kw) |
||||
|
|
||||
|
class ToolInitializer: |
||||
|
""" |
||||
|
A class for delayed initialization of Tools modules. |
||||
|
|
||||
|
Instances of this class associate a list of Tool modules with |
||||
|
a list of Builder method names that will be added by those Tool |
||||
|
modules. As part of instantiating this object for a particular |
||||
|
construction environment, we also add the appropriate |
||||
|
ToolInitializerMethod objects for the various Builder methods |
||||
|
that we want to use to delay Tool searches until necessary. |
||||
|
""" |
||||
|
def __init__(self, env, tools, names): |
||||
|
if not SCons.Util.is_List(tools): |
||||
|
tools = [tools] |
||||
|
if not SCons.Util.is_List(names): |
||||
|
names = [names] |
||||
|
self.env = env |
||||
|
self.tools = tools |
||||
|
self.names = names |
||||
|
self.methods = {} |
||||
|
for name in names: |
||||
|
method = ToolInitializerMethod(name, self) |
||||
|
self.methods[name] = method |
||||
|
env.AddMethod(method) |
||||
|
|
||||
|
def remove_methods(self, env): |
||||
|
""" |
||||
|
Removes the methods that were added by the tool initialization |
||||
|
so we no longer copy and re-bind them when the construction |
||||
|
environment gets cloned. |
||||
|
""" |
||||
|
for method in self.methods.values(): |
||||
|
env.RemoveMethod(method) |
||||
|
|
||||
|
def apply_tools(self, env): |
||||
|
""" |
||||
|
Searches the list of associated Tool modules for one that |
||||
|
exists, and applies that to the construction environment. |
||||
|
""" |
||||
|
for t in self.tools: |
||||
|
tool = SCons.Tool.Tool(t) |
||||
|
if tool.exists(env): |
||||
|
env.Tool(tool) |
||||
|
return |
||||
|
|
||||
|
# If we fall through here, there was no tool module found. |
||||
|
# This is where we can put an informative error message |
||||
|
# about the inability to find the tool. We'll start doing |
||||
|
# this as we cut over more pre-defined Builder+Tools to use |
||||
|
# the ToolInitializer class. |
||||
|
|
||||
|
def Initializers(env): |
||||
|
ToolInitializer(env, ['install'], ['_InternalInstall', '_InternalInstallAs']) |
||||
|
def Install(self, *args, **kw): |
||||
|
return apply(self._InternalInstall, args, kw) |
||||
|
def InstallAs(self, *args, **kw): |
||||
|
return apply(self._InternalInstallAs, args, kw) |
||||
|
env.AddMethod(Install) |
||||
|
env.AddMethod(InstallAs) |
||||
|
|
||||
|
def FindTool(tools, env): |
||||
|
for tool in tools: |
||||
|
t = Tool(tool) |
||||
|
if t.exists(env): |
||||
|
return tool |
||||
|
return None |
||||
|
|
||||
|
def FindAllTools(tools, env): |
||||
|
def ToolExists(tool, env=env): |
||||
|
return Tool(tool).exists(env) |
||||
|
return filter (ToolExists, tools) |
||||
|
|
||||
|
def tool_list(platform, env): |
||||
|
|
||||
|
# XXX this logic about what tool to prefer on which platform |
||||
|
# should be moved into either the platform files or |
||||
|
# the tool files themselves. |
||||
|
# The search orders here are described in the man page. If you |
||||
|
# change these search orders, update the man page as well. |
||||
|
if str(platform) == 'win32': |
||||
|
"prefer Microsoft tools on Windows" |
||||
|
linkers = ['mslink', 'gnulink', 'ilink', 'linkloc', 'ilink32' ] |
||||
|
c_compilers = ['msvc', 'mingw', 'gcc', 'intelc', 'icl', 'icc', 'cc', 'bcc32' ] |
||||
|
cxx_compilers = ['msvc', 'intelc', 'icc', 'g++', 'c++', 'bcc32' ] |
||||
|
assemblers = ['masm', 'nasm', 'gas', '386asm' ] |
||||
|
fortran_compilers = ['gfortran', 'g77', 'ifl', 'cvf', 'f95', 'f90', 'fortran'] |
||||
|
ars = ['mslib', 'ar', 'tlib'] |
||||
|
elif str(platform) == 'os2': |
||||
|
"prefer IBM tools on OS/2" |
||||
|
linkers = ['ilink', 'gnulink', 'mslink'] |
||||
|
c_compilers = ['icc', 'gcc', 'msvc', 'cc'] |
||||
|
cxx_compilers = ['icc', 'g++', 'msvc', 'c++'] |
||||
|
assemblers = ['nasm', 'masm', 'gas'] |
||||
|
fortran_compilers = ['ifl', 'g77'] |
||||
|
ars = ['ar', 'mslib'] |
||||
|
elif str(platform) == 'irix': |
||||
|
"prefer MIPSPro on IRIX" |
||||
|
linkers = ['sgilink', 'gnulink'] |
||||
|
c_compilers = ['sgicc', 'gcc', 'cc'] |
||||
|
cxx_compilers = ['sgic++', 'g++', 'c++'] |
||||
|
assemblers = ['as', 'gas'] |
||||
|
fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran'] |
||||
|
ars = ['sgiar'] |
||||
|
elif str(platform) == 'sunos': |
||||
|
"prefer Forte tools on SunOS" |
||||
|
linkers = ['sunlink', 'gnulink'] |
||||
|
c_compilers = ['suncc', 'gcc', 'cc'] |
||||
|
cxx_compilers = ['sunc++', 'g++', 'c++'] |
||||
|
assemblers = ['as', 'gas'] |
||||
|
fortran_compilers = ['sunf95', 'sunf90', 'sunf77', 'f95', 'f90', 'f77', |
||||
|
'gfortran', 'g77', 'fortran'] |
||||
|
ars = ['sunar'] |
||||
|
elif str(platform) == 'hpux': |
||||
|
"prefer aCC tools on HP-UX" |
||||
|
linkers = ['hplink', 'gnulink'] |
||||
|
c_compilers = ['hpcc', 'gcc', 'cc'] |
||||
|
cxx_compilers = ['hpc++', 'g++', 'c++'] |
||||
|
assemblers = ['as', 'gas'] |
||||
|
fortran_compilers = ['f95', 'f90', 'f77', 'g77', 'fortran'] |
||||
|
ars = ['ar'] |
||||
|
elif str(platform) == 'aix': |
||||
|
"prefer AIX Visual Age tools on AIX" |
||||
|
linkers = ['aixlink', 'gnulink'] |
||||
|
c_compilers = ['aixcc', 'gcc', 'cc'] |
||||
|
cxx_compilers = ['aixc++', 'g++', 'c++'] |
||||
|
assemblers = ['as', 'gas'] |
||||
|
fortran_compilers = ['f95', 'f90', 'aixf77', 'g77', 'fortran'] |
||||
|
ars = ['ar'] |
||||
|
elif str(platform) == 'darwin': |
||||
|
"prefer GNU tools on Mac OS X, except for some linkers and IBM tools" |
||||
|
linkers = ['applelink', 'gnulink'] |
||||
|
c_compilers = ['gcc', 'cc'] |
||||
|
cxx_compilers = ['g++', 'c++'] |
||||
|
assemblers = ['as'] |
||||
|
fortran_compilers = ['gfortran', 'f95', 'f90', 'g77'] |
||||
|
ars = ['ar'] |
||||
|
else: |
||||
|
"prefer GNU tools on all other platforms" |
||||
|
linkers = ['gnulink', 'mslink', 'ilink'] |
||||
|
c_compilers = ['gcc', 'msvc', 'intelc', 'icc', 'cc'] |
||||
|
cxx_compilers = ['g++', 'msvc', 'intelc', 'icc', 'c++'] |
||||
|
assemblers = ['gas', 'nasm', 'masm'] |
||||
|
fortran_compilers = ['gfortran', 'g77', 'ifort', 'ifl', 'f95', 'f90', 'f77'] |
||||
|
ars = ['ar', 'mslib'] |
||||
|
|
||||
|
c_compiler = FindTool(c_compilers, env) or c_compilers[0] |
||||
|
|
||||
|
# XXX this logic about what tool provides what should somehow be |
||||
|
# moved into the tool files themselves. |
||||
|
if c_compiler and c_compiler == 'mingw': |
||||
|
# MinGW contains a linker, C compiler, C++ compiler, |
||||
|
# Fortran compiler, archiver and assembler: |
||||
|
cxx_compiler = None |
||||
|
linker = None |
||||
|
assembler = None |
||||
|
fortran_compiler = None |
||||
|
ar = None |
||||
|
else: |
||||
|
# Don't use g++ if the C compiler has built-in C++ support: |
||||
|
if c_compiler in ('msvc', 'intelc', 'icc'): |
||||
|
cxx_compiler = None |
||||
|
else: |
||||
|
cxx_compiler = FindTool(cxx_compilers, env) or cxx_compilers[0] |
||||
|
linker = FindTool(linkers, env) or linkers[0] |
||||
|
assembler = FindTool(assemblers, env) or assemblers[0] |
||||
|
fortran_compiler = FindTool(fortran_compilers, env) or fortran_compilers[0] |
||||
|
ar = FindTool(ars, env) or ars[0] |
||||
|
|
||||
|
other_tools = FindAllTools(['BitKeeper', 'CVS', |
||||
|
'dmd', |
||||
|
'filesystem', |
||||
|
'dvipdf', 'dvips', 'gs', |
||||
|
'jar', 'javac', 'javah', |
||||
|
'latex', 'lex', |
||||
|
'm4', 'midl', 'msvs', |
||||
|
'pdflatex', 'pdftex', 'Perforce', |
||||
|
'RCS', 'rmic', 'rpcgen', |
||||
|
'SCCS', |
||||
|
# 'Subversion', |
||||
|
'swig', |
||||
|
'tar', 'tex', |
||||
|
'yacc', 'zip', 'rpm', 'wix'], |
||||
|
env) |
||||
|
|
||||
|
tools = ([linker, c_compiler, cxx_compiler, |
||||
|
fortran_compiler, assembler, ar] |
||||
|
+ other_tools) |
||||
|
|
||||
|
return filter(lambda x: x, tools) |
@ -0,0 +1,76 @@ |
|||||
|
"""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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/aixc++.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import os.path |
||||
|
|
||||
|
import SCons.Platform.aix |
||||
|
|
||||
|
cplusplus = __import__('c++', globals(), locals(), []) |
||||
|
|
||||
|
packages = ['vacpp.cmp.core', 'vacpp.cmp.batch', 'vacpp.cmp.C', 'ibmcxx.cmp'] |
||||
|
|
||||
|
def get_xlc(env): |
||||
|
xlc = env.get('CXX', 'xlC') |
||||
|
xlc_r = env.get('SHCXX', 'xlC_r') |
||||
|
return SCons.Platform.aix.get_xlc(env, xlc, xlc_r, packages) |
||||
|
|
||||
|
def smart_cxxflags(source, target, env, for_signature): |
||||
|
build_dir = env.GetBuildPath() |
||||
|
if build_dir: |
||||
|
return '-qtempinc=' + os.path.join(build_dir, 'tempinc') |
||||
|
return '' |
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add Builders and construction variables for xlC / Visual Age |
||||
|
suite to an Environment.""" |
||||
|
path, _cxx, _shcxx, version = get_xlc(env) |
||||
|
if path: |
||||
|
_cxx = os.path.join(path, _cxx) |
||||
|
_shcxx = os.path.join(path, _shcxx) |
||||
|
|
||||
|
cplusplus.generate(env) |
||||
|
|
||||
|
env['CXX'] = _cxx |
||||
|
env['SHCXX'] = _shcxx |
||||
|
env['CXXVERSION'] = version |
||||
|
env['SHOBJSUFFIX'] = '.pic.o' |
||||
|
|
||||
|
def exists(env): |
||||
|
path, _cxx, _shcxx, version = get_xlc(env) |
||||
|
if path and _cxx: |
||||
|
xlc = os.path.join(path, _cxx) |
||||
|
if os.path.exists(xlc): |
||||
|
return xlc |
||||
|
return None |
@ -0,0 +1,68 @@ |
|||||
|
"""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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/aixcc.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import os.path |
||||
|
|
||||
|
import SCons.Platform.aix |
||||
|
|
||||
|
import cc |
||||
|
|
||||
|
packages = ['vac.C', 'ibmcxx.cmp'] |
||||
|
|
||||
|
def get_xlc(env): |
||||
|
xlc = env.get('CC', 'xlc') |
||||
|
xlc_r = env.get('SHCC', 'xlc_r') |
||||
|
return SCons.Platform.aix.get_xlc(env, xlc, xlc_r, packages) |
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add Builders and construction variables for xlc / Visual Age |
||||
|
suite to an Environment.""" |
||||
|
path, _cc, _shcc, version = get_xlc(env) |
||||
|
if path: |
||||
|
_cc = os.path.join(path, _cc) |
||||
|
_shcc = os.path.join(path, _shcc) |
||||
|
|
||||
|
cc.generate(env) |
||||
|
|
||||
|
env['CC'] = _cc |
||||
|
env['SHCC'] = _shcc |
||||
|
env['CCVERSION'] = version |
||||
|
|
||||
|
def exists(env): |
||||
|
path, _cc, _shcc, version = get_xlc(env) |
||||
|
if path and _cc: |
||||
|
xlc = os.path.join(path, _cc) |
||||
|
if os.path.exists(xlc): |
||||
|
return xlc |
||||
|
return None |
@ -0,0 +1,74 @@ |
|||||
|
"""engine.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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/aixf77.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import os.path |
||||
|
|
||||
|
#import SCons.Platform.aix |
||||
|
|
||||
|
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 the 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 |
@ -0,0 +1,70 @@ |
|||||
|
"""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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/aixlink.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import os |
||||
|
import os.path |
||||
|
|
||||
|
import SCons.Util |
||||
|
|
||||
|
import aixcc |
||||
|
import link |
||||
|
|
||||
|
cplusplus = __import__('c++', 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): |
||||
|
path, _cc, _shcc, version = aixcc.get_xlc(env) |
||||
|
if path and _cc: |
||||
|
xlc = os.path.join(path, _cc) |
||||
|
if os.path.exists(xlc): |
||||
|
return xlc |
||||
|
return None |
@ -0,0 +1,65 @@ |
|||||
|
"""SCons.Tool.applelink |
||||
|
|
||||
|
Tool-specific initialization for the Apple 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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/applelink.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
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". |
||||
|
import link |
||||
|
|
||||
|
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__)}' |
||||
|
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' |
||||
|
|
||||
|
# 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' |
||||
|
|
||||
|
|
||||
|
|
||||
|
def exists(env): |
||||
|
return env['PLATFORM'] == 'darwin' |
@ -0,0 +1,57 @@ |
|||||
|
"""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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/ar.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
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.Detect('ranlib'): |
||||
|
env['RANLIB'] = 'ranlib' |
||||
|
env['RANLIBFLAGS'] = SCons.Util.CLVar('') |
||||
|
env['RANLIBCOM'] = '$RANLIB $RANLIBFLAGS $TARGET' |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect('ar') |
@ -0,0 +1,72 @@ |
|||||
|
"""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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/as.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
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) |
@ -0,0 +1,76 @@ |
|||||
|
"""SCons.Tool.bcc32 |
||||
|
|
||||
|
XXX |
||||
|
|
||||
|
""" |
||||
|
|
||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/bcc32.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import os |
||||
|
import os.path |
||||
|
import string |
||||
|
|
||||
|
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) |
@ -0,0 +1,93 @@ |
|||||
|
"""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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/c++.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
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) |
||||
|
|
||||
|
env['CXX'] = 'c++' |
||||
|
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(compilers) |
@ -0,0 +1,108 @@ |
|||||
|
"""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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/cc.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
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 not env.has_key('_CCCOMCOM'): |
||||
|
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 not env.has_key('CCFLAGS'): |
||||
|
env['CCFLAGS'] = SCons.Util.CLVar('') |
||||
|
|
||||
|
if not env.has_key('SHCCFLAGS'): |
||||
|
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS') |
||||
|
|
||||
|
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) |
||||
|
#<<<<<<< .working |
||||
|
# |
||||
|
# 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' |
||||
|
#======= |
||||
|
#>>>>>>> .merge-right.r1907 |
||||
|
|
||||
|
add_common_cc_variables(env) |
||||
|
|
||||
|
env['CC'] = 'cc' |
||||
|
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('cc') |
@ -0,0 +1,52 @@ |
|||||
|
"""engine.SCons.Tool.cvf |
||||
|
|
||||
|
Tool-specific initialization for the Compaq Visual Fortran compiler. |
||||
|
|
||||
|
""" |
||||
|
|
||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/cvf.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
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) |
@ -0,0 +1,44 @@ |
|||||
|
"""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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/default.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
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 |
@ -0,0 +1,218 @@ |
|||||
|
"""SCons.Tool.dmd |
||||
|
|
||||
|
Tool-specific initialization for the Digital Mars D compiler. |
||||
|
(http://digitalmars.com/d) |
||||
|
|
||||
|
Coded by Andy Friesen (andy@ikagames.com) |
||||
|
15 November 2003 |
||||
|
|
||||
|
There are a number of problems with this script at this point in time. |
||||
|
The one that irritates me the most is the Windows linker setup. The D |
||||
|
linker doesn't have a way to add lib paths on the commandline, as far |
||||
|
as I can see. You have to specify paths relative to the SConscript or |
||||
|
use absolute paths. To hack around it, add '#/blah'. This will link |
||||
|
blah.lib from the directory where SConstruct resides. |
||||
|
|
||||
|
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. |
||||
|
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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/dmd.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import os |
||||
|
import string |
||||
|
|
||||
|
import SCons.Action |
||||
|
import SCons.Builder |
||||
|
import SCons.Defaults |
||||
|
import SCons.Scanner.D |
||||
|
import SCons.Tool |
||||
|
|
||||
|
# Adapted from c++.py |
||||
|
def isD(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 |
||||
|
|
||||
|
smart_link = {} |
||||
|
|
||||
|
smart_lib = {} |
||||
|
|
||||
|
def generate(env): |
||||
|
global smart_link |
||||
|
global smart_lib |
||||
|
|
||||
|
static_obj, shared_obj = SCons.Tool.createObjBuilders(env) |
||||
|
|
||||
|
DAction = SCons.Action.Action('$DCOM', '$DCOMSTR') |
||||
|
|
||||
|
static_obj.add_action('.d', DAction) |
||||
|
shared_obj.add_action('.d', DAction) |
||||
|
static_obj.add_emitter('.d', SCons.Defaults.StaticObjectEmitter) |
||||
|
shared_obj.add_emitter('.d', SCons.Defaults.SharedObjectEmitter) |
||||
|
|
||||
|
dc = env.Detect(['dmd', 'gdmd']) |
||||
|
env['DC'] = dc |
||||
|
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['DPATH'] = ['#/'] |
||||
|
env['DFLAGS'] = [] |
||||
|
env['DVERSIONS'] = [] |
||||
|
env['DDEBUG'] = [] |
||||
|
|
||||
|
if dc: |
||||
|
# Add the path to the standard library. |
||||
|
# This is merely for the convenience of the dependency scanner. |
||||
|
dmd_path = env.WhereIs(dc) |
||||
|
if dmd_path: |
||||
|
x = string.rindex(dmd_path, dc) |
||||
|
phobosDir = dmd_path[:x] + '/../src/phobos' |
||||
|
if os.path.isdir(phobosDir): |
||||
|
env.Append(DPATH = [phobosDir]) |
||||
|
|
||||
|
env['DINCPREFIX'] = '-I' |
||||
|
env['DINCSUFFIX'] = '' |
||||
|
env['DVERPREFIX'] = '-version=' |
||||
|
env['DVERSUFFIX'] = '' |
||||
|
env['DDEBUGPREFIX'] = '-debug=' |
||||
|
env['DDEBUGSUFFIX'] = '' |
||||
|
env['DFLAGPREFIX'] = '-' |
||||
|
env['DFLAGSUFFIX'] = '' |
||||
|
env['DFILESUFFIX'] = '.d' |
||||
|
|
||||
|
# Need to use the Digital Mars linker/lib on windows. |
||||
|
# *nix can just use GNU link. |
||||
|
if env['PLATFORM'] == 'win32': |
||||
|
env['DLINK'] = '$DC' |
||||
|
env['DLINKCOM'] = '$DLINK -of$TARGET $SOURCES $DFLAGS $DLINKFLAGS $_DLINKLIBFLAGS' |
||||
|
env['DLIB'] = 'lib' |
||||
|
env['DLIBCOM'] = '$DLIB $_DLIBFLAGS -c $TARGET $SOURCES $_DLINKLIBFLAGS' |
||||
|
|
||||
|
env['_DLINKLIBFLAGS'] = '$( ${_concat(DLIBLINKPREFIX, LIBS, DLIBLINKSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)' |
||||
|
env['_DLIBFLAGS'] = '$( ${_concat(DLIBFLAGPREFIX, DLIBFLAGS, DLIBFLAGSUFFIX, __env__)} $)' |
||||
|
env['DLINKFLAGS'] = [] |
||||
|
env['DLIBLINKPREFIX'] = '' |
||||
|
env['DLIBLINKSUFFIX'] = '.lib' |
||||
|
env['DLIBFLAGPREFIX'] = '-' |
||||
|
env['DLIBFLAGSUFFIX'] = '' |
||||
|
env['DLINKFLAGPREFIX'] = '-' |
||||
|
env['DLINKFLAGSUFFIX'] = '' |
||||
|
|
||||
|
SCons.Tool.createStaticLibBuilder(env) |
||||
|
|
||||
|
# Basically, we hijack the link and ar builders with our own. |
||||
|
# these builders check for the presence of D source, and swap out |
||||
|
# the system's defaults for the Digital Mars tools. If there's no D |
||||
|
# source, then we silently return the previous settings. |
||||
|
linkcom = env.get('LINKCOM') |
||||
|
try: |
||||
|
env['SMART_LINKCOM'] = smart_link[linkcom] |
||||
|
except KeyError: |
||||
|
def _smartLink(source, target, env, for_signature, |
||||
|
defaultLinker=linkcom): |
||||
|
if isD(source): |
||||
|
# XXX I'm not sure how to add a $DLINKCOMSTR variable |
||||
|
# so that it works with this _smartLink() logic, |
||||
|
# and I don't have a D compiler/linker to try it out, |
||||
|
# so we'll leave it alone for now. |
||||
|
return '$DLINKCOM' |
||||
|
else: |
||||
|
return defaultLinker |
||||
|
env['SMART_LINKCOM'] = smart_link[linkcom] = _smartLink |
||||
|
|
||||
|
arcom = env.get('ARCOM') |
||||
|
try: |
||||
|
env['SMART_ARCOM'] = smart_lib[arcom] |
||||
|
except KeyError: |
||||
|
def _smartLib(source, target, env, for_signature, |
||||
|
defaultLib=arcom): |
||||
|
if isD(source): |
||||
|
# XXX I'm not sure how to add a $DLIBCOMSTR variable |
||||
|
# so that it works with this _smartLib() logic, and |
||||
|
# I don't have a D compiler/archiver to try it out, |
||||
|
# so we'll leave it alone for now. |
||||
|
return '$DLIBCOM' |
||||
|
else: |
||||
|
return defaultLib |
||||
|
env['SMART_ARCOM'] = smart_lib[arcom] = _smartLib |
||||
|
|
||||
|
# It is worth noting that the final space in these strings is |
||||
|
# absolutely pivotal. SCons sees these as actions and not generators |
||||
|
# if it is not there. (very bad) |
||||
|
env['ARCOM'] = '$SMART_ARCOM ' |
||||
|
env['LINKCOM'] = '$SMART_LINKCOM ' |
||||
|
else: # assuming linux |
||||
|
linkcom = env.get('LINKCOM') |
||||
|
try: |
||||
|
env['SMART_LINKCOM'] = smart_link[linkcom] |
||||
|
except KeyError: |
||||
|
def _smartLink(source, target, env, for_signature, |
||||
|
defaultLinker=linkcom, dc=dc): |
||||
|
if isD(source): |
||||
|
try: |
||||
|
libs = env['LIBS'] |
||||
|
except KeyError: |
||||
|
libs = [] |
||||
|
if 'phobos' not in libs: |
||||
|
if dc is 'dmd': |
||||
|
env.Append(LIBS = ['phobos']) |
||||
|
elif dc is 'gdmd': |
||||
|
env.Append(LIBS = ['gphobos']) |
||||
|
if 'pthread' not in libs: |
||||
|
env.Append(LIBS = ['pthread']) |
||||
|
if 'm' not in libs: |
||||
|
env.Append(LIBS = ['m']) |
||||
|
return defaultLinker |
||||
|
env['SMART_LINKCOM'] = smart_link[linkcom] = _smartLink |
||||
|
|
||||
|
env['LINKCOM'] = '$SMART_LINKCOM ' |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect(['dmd', 'gdmd']) |
@ -0,0 +1,58 @@ |
|||||
|
"""SCons.Tool.dvi |
||||
|
|
||||
|
Common DVI Builder definition for various other Tool modules that use it. |
||||
|
|
||||
|
""" |
||||
|
|
||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/dvi.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons.Builder |
||||
|
import SCons.Tool |
||||
|
|
||||
|
DVIBuilder = None |
||||
|
|
||||
|
def generate(env): |
||||
|
try: |
||||
|
env['BUILDERS']['DVI'] |
||||
|
except KeyError: |
||||
|
global DVIBuilder |
||||
|
|
||||
|
if DVIBuilder is None: |
||||
|
# The suffix is hard-coded to '.dvi', not configurable via a |
||||
|
# construction variable like $DVISUFFIX, because the output |
||||
|
# file name is hard-coded within TeX. |
||||
|
DVIBuilder = SCons.Builder.Builder(action = {}, |
||||
|
source_scanner = SCons.Tool.LaTeXScanner, |
||||
|
suffix = '.dvi', |
||||
|
emitter = {}, |
||||
|
source_ext_match = None) |
||||
|
|
||||
|
env['BUILDERS']['DVI'] = DVIBuilder |
||||
|
|
||||
|
def exists(env): |
||||
|
# This only puts a skeleton Builder in place, so if someone |
||||
|
# references this Tool directly, it's always "available." |
||||
|
return 1 |
@ -0,0 +1,119 @@ |
|||||
|
"""SCons.Tool.dvipdf |
||||
|
|
||||
|
Tool-specific initialization for dvipdf. |
||||
|
|
||||
|
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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/dvipdf.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons.Action |
||||
|
import SCons.Defaults |
||||
|
import SCons.Tool.pdf |
||||
|
import SCons.Tool.tex |
||||
|
import SCons.Util |
||||
|
|
||||
|
_null = SCons.Scanner.LaTeX._null |
||||
|
|
||||
|
def DviPdfPsFunction(XXXDviAction, target = None, source= None, env=None): |
||||
|
"""A builder for DVI files that sets the TEXPICTS environment |
||||
|
variable before running dvi2ps or dvipdf.""" |
||||
|
|
||||
|
try: |
||||
|
abspath = source[0].attributes.path |
||||
|
except AttributeError : |
||||
|
abspath = '' |
||||
|
|
||||
|
saved_env = SCons.Scanner.LaTeX.modify_env_var(env, 'TEXPICTS', abspath) |
||||
|
|
||||
|
result = XXXDviAction(target, source, env) |
||||
|
|
||||
|
if saved_env is _null: |
||||
|
try: |
||||
|
del env['ENV']['TEXPICTS'] |
||||
|
except KeyError: |
||||
|
pass # was never set |
||||
|
else: |
||||
|
env['ENV']['TEXPICTS'] = saved_env |
||||
|
|
||||
|
return result |
||||
|
|
||||
|
def DviPdfFunction(target = None, source= None, env=None): |
||||
|
result = DviPdfPsFunction(PDFAction,target,source,env) |
||||
|
return result |
||||
|
|
||||
|
def DviPdfStrFunction(target = None, source= None, env=None): |
||||
|
"""A strfunction for dvipdf that returns the appropriate |
||||
|
command string for the no_exec options.""" |
||||
|
if env.GetOption("no_exec"): |
||||
|
result = env.subst('$DVIPDFCOM',0,target,source) |
||||
|
else: |
||||
|
result = '' |
||||
|
return result |
||||
|
|
||||
|
PDFAction = None |
||||
|
DVIPDFAction = None |
||||
|
|
||||
|
def PDFEmitter(target, source, env): |
||||
|
"""Strips any .aux or .log files from the input source list. |
||||
|
These are created by the TeX Builder that in all likelihood was |
||||
|
used to generate the .dvi file we're using as input, and we only |
||||
|
care about the .dvi file. |
||||
|
""" |
||||
|
def strip_suffixes(n): |
||||
|
return not SCons.Util.splitext(str(n))[1] in ['.aux', '.log'] |
||||
|
source = filter(strip_suffixes, source) |
||||
|
return (target, source) |
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add Builders and construction variables for dvipdf to an Environment.""" |
||||
|
global PDFAction |
||||
|
if PDFAction is None: |
||||
|
PDFAction = SCons.Action.Action('$DVIPDFCOM', '$DVIPDFCOMSTR') |
||||
|
|
||||
|
global DVIPDFAction |
||||
|
if DVIPDFAction is None: |
||||
|
DVIPDFAction = SCons.Action.Action(DviPdfFunction, strfunction = DviPdfStrFunction) |
||||
|
|
||||
|
import pdf |
||||
|
pdf.generate(env) |
||||
|
|
||||
|
bld = env['BUILDERS']['PDF'] |
||||
|
bld.add_action('.dvi', DVIPDFAction) |
||||
|
bld.add_emitter('.dvi', PDFEmitter) |
||||
|
|
||||
|
env['DVIPDF'] = 'dvipdf' |
||||
|
env['DVIPDFFLAGS'] = SCons.Util.CLVar('') |
||||
|
env['DVIPDFCOM'] = 'cd ${TARGET.dir} && $DVIPDF $DVIPDFFLAGS ${SOURCE.file} ${TARGET.file}' |
||||
|
|
||||
|
# Deprecated synonym. |
||||
|
env['PDFCOM'] = ['$DVIPDFCOM'] |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect('dvipdf') |
@ -0,0 +1,88 @@ |
|||||
|
"""SCons.Tool.dvips |
||||
|
|
||||
|
Tool-specific initialization for dvips. |
||||
|
|
||||
|
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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/dvips.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons.Action |
||||
|
import SCons.Builder |
||||
|
import SCons.Tool.dvipdf |
||||
|
import SCons.Util |
||||
|
|
||||
|
def DviPsFunction(target = None, source= None, env=None): |
||||
|
result = SCons.Tool.dvipdf.DviPdfPsFunction(PSAction,target,source,env) |
||||
|
return result |
||||
|
|
||||
|
def DviPsStrFunction(target = None, source= None, env=None): |
||||
|
"""A strfunction for dvipdf that returns the appropriate |
||||
|
command string for the no_exec options.""" |
||||
|
if env.GetOption("no_exec"): |
||||
|
result = env.subst('$PSCOM',0,target,source) |
||||
|
else: |
||||
|
result = '' |
||||
|
return result |
||||
|
|
||||
|
PSAction = None |
||||
|
DVIPSAction = None |
||||
|
PSBuilder = None |
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add Builders and construction variables for dvips to an Environment.""" |
||||
|
global PSAction |
||||
|
if PSAction is None: |
||||
|
PSAction = SCons.Action.Action('$PSCOM', '$PSCOMSTR') |
||||
|
|
||||
|
global DVIPSAction |
||||
|
if DVIPSAction is None: |
||||
|
DVIPSAction = SCons.Action.Action(DviPsFunction, strfunction = DviPsStrFunction) |
||||
|
|
||||
|
global PSBuilder |
||||
|
if PSBuilder is None: |
||||
|
PSBuilder = SCons.Builder.Builder(action = PSAction, |
||||
|
prefix = '$PSPREFIX', |
||||
|
suffix = '$PSSUFFIX', |
||||
|
src_suffix = '.dvi', |
||||
|
src_builder = 'DVI', |
||||
|
single_source=True) |
||||
|
|
||||
|
env['BUILDERS']['PostScript'] = PSBuilder |
||||
|
|
||||
|
env['DVIPS'] = 'dvips' |
||||
|
env['DVIPSFLAGS'] = SCons.Util.CLVar('') |
||||
|
# I'm not quite sure I got the directories and filenames right for variant_dir |
||||
|
# We need to be in the correct directory for the sake of latex \includegraphics eps included files. |
||||
|
env['PSCOM'] = 'cd ${TARGET.dir} && $DVIPS $DVIPSFLAGS -o ${TARGET.file} ${SOURCE.file}' |
||||
|
env['PSPREFIX'] = '' |
||||
|
env['PSSUFFIX'] = '.ps' |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect('dvips') |
@ -0,0 +1,56 @@ |
|||||
|
"""engine.SCons.Tool.f77 |
||||
|
|
||||
|
Tool-specific initialization for the generic Posix 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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/f77.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons.Defaults |
||||
|
import SCons.Scanner.Fortran |
||||
|
import SCons.Tool |
||||
|
import SCons.Util |
||||
|
from SCons.Tool.FortranCommon import add_all_to_env, add_f77_to_env |
||||
|
|
||||
|
compilers = ['f77'] |
||||
|
|
||||
|
def generate(env): |
||||
|
add_all_to_env(env) |
||||
|
add_f77_to_env(env) |
||||
|
|
||||
|
fcomp = env.Detect(compilers) or 'f77' |
||||
|
env['F77'] = fcomp |
||||
|
env['SHF77'] = fcomp |
||||
|
|
||||
|
env['FORTRAN'] = fcomp |
||||
|
env['SHFORTRAN'] = fcomp |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect(compilers) |
@ -0,0 +1,56 @@ |
|||||
|
"""engine.SCons.Tool.f90 |
||||
|
|
||||
|
Tool-specific initialization for the generic Posix f90 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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/f90.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons.Defaults |
||||
|
import SCons.Scanner.Fortran |
||||
|
import SCons.Tool |
||||
|
import SCons.Util |
||||
|
from SCons.Tool.FortranCommon import add_all_to_env, add_f90_to_env |
||||
|
|
||||
|
compilers = ['f90'] |
||||
|
|
||||
|
def generate(env): |
||||
|
add_all_to_env(env) |
||||
|
add_f90_to_env(env) |
||||
|
|
||||
|
fc = env.Detect(compilers) or 'f90' |
||||
|
env['F90'] = fc |
||||
|
env['SHF90'] = fc |
||||
|
|
||||
|
env['FORTRAN'] = fc |
||||
|
env['SHFORTRAN'] = fc |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect(compilers) |
@ -0,0 +1,57 @@ |
|||||
|
"""engine.SCons.Tool.f95 |
||||
|
|
||||
|
Tool-specific initialization for the generic Posix f95 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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/f95.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons.Defaults |
||||
|
import SCons.Tool |
||||
|
import SCons.Util |
||||
|
import fortran |
||||
|
from SCons.Tool.FortranCommon import add_all_to_env, add_f95_to_env |
||||
|
|
||||
|
compilers = ['f95'] |
||||
|
|
||||
|
def generate(env): |
||||
|
add_all_to_env(env) |
||||
|
add_f95_to_env(env) |
||||
|
|
||||
|
fcomp = env.Detect(compilers) or 'f95' |
||||
|
env['F95'] = fcomp |
||||
|
env['SHF95'] = fcomp |
||||
|
|
||||
|
env['FORTRAN'] = fcomp |
||||
|
env['SHFORTRAN'] = fcomp |
||||
|
|
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect(compilers) |
@ -0,0 +1,92 @@ |
|||||
|
"""SCons.Tool.filesystem |
||||
|
|
||||
|
Tool-specific initialization for the filesystem tools. |
||||
|
|
||||
|
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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/filesystem.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons |
||||
|
from SCons.Tool.install import copyFunc |
||||
|
|
||||
|
copyToBuilder, copyAsBuilder = None, None |
||||
|
|
||||
|
def copyto_emitter(target, source, env): |
||||
|
""" changes the path of the source to be under the target (which |
||||
|
are assumed to be directories. |
||||
|
""" |
||||
|
n_target = [] |
||||
|
|
||||
|
for t in target: |
||||
|
n_target = n_target + map( lambda s, t=t: t.File( str( s ) ), source ) |
||||
|
|
||||
|
return (n_target, source) |
||||
|
|
||||
|
def copy_action_func(target, source, env): |
||||
|
assert( len(target) == len(source) ), "\ntarget: %s\nsource: %s" %(map(str, target),map(str, source)) |
||||
|
|
||||
|
for t, s in zip(target, source): |
||||
|
if copyFunc(t.get_path(), s.get_path(), env): |
||||
|
return 1 |
||||
|
|
||||
|
return 0 |
||||
|
|
||||
|
def copy_action_str(target, source, env): |
||||
|
return env.subst_target_source(env['COPYSTR'], 0, target, source) |
||||
|
|
||||
|
copy_action = SCons.Action.Action( copy_action_func, copy_action_str ) |
||||
|
|
||||
|
def generate(env): |
||||
|
try: |
||||
|
env['BUILDERS']['CopyTo'] |
||||
|
env['BUILDERS']['CopyAs'] |
||||
|
except KeyError, e: |
||||
|
global copyToBuilder |
||||
|
if copyToBuilder is None: |
||||
|
copyToBuilder = SCons.Builder.Builder( |
||||
|
action = copy_action, |
||||
|
target_factory = env.fs.Dir, |
||||
|
source_factory = env.fs.Entry, |
||||
|
multi = 1, |
||||
|
emitter = [ copyto_emitter, ] ) |
||||
|
|
||||
|
global copyAsBuilder |
||||
|
if copyAsBuilder is None: |
||||
|
copyAsBuilder = SCons.Builder.Builder( |
||||
|
action = copy_action, |
||||
|
target_factory = env.fs.Entry, |
||||
|
source_factory = env.fs.Entry ) |
||||
|
|
||||
|
env['BUILDERS']['CopyTo'] = copyToBuilder |
||||
|
env['BUILDERS']['CopyAs'] = copyAsBuilder |
||||
|
|
||||
|
env['COPYSTR'] = 'Copy file(s): "$SOURCES" to "$TARGETS"' |
||||
|
|
||||
|
def exists(env): |
||||
|
return 1 |
@ -0,0 +1,57 @@ |
|||||
|
"""SCons.Tool.fortran |
||||
|
|
||||
|
Tool-specific initialization for a generic Posix f77/f90 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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/fortran.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import re |
||||
|
import string |
||||
|
|
||||
|
import SCons.Action |
||||
|
import SCons.Defaults |
||||
|
import SCons.Scanner.Fortran |
||||
|
import SCons.Tool |
||||
|
import SCons.Util |
||||
|
from SCons.Tool.FortranCommon import add_all_to_env, add_fortran_to_env |
||||
|
|
||||
|
compilers = ['f95', 'f90', 'f77'] |
||||
|
|
||||
|
def generate(env): |
||||
|
add_all_to_env(env) |
||||
|
add_fortran_to_env(env) |
||||
|
|
||||
|
fc = env.Detect(compilers) or 'f77' |
||||
|
env['SHFORTRAN'] = fc |
||||
|
env['FORTRAN'] = fc |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect(compilers) |
@ -0,0 +1,84 @@ |
|||||
|
"""SCons.Tool.g++ |
||||
|
|
||||
|
Tool-specific initialization for g++. |
||||
|
|
||||
|
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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/g++.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import os.path |
||||
|
import re |
||||
|
import subprocess |
||||
|
|
||||
|
import SCons.Tool |
||||
|
import SCons.Util |
||||
|
|
||||
|
cplusplus = __import__('c++', globals(), locals(), []) |
||||
|
|
||||
|
compilers = ['g++'] |
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add Builders and construction variables for g++ to an Environment.""" |
||||
|
static_obj, shared_obj = SCons.Tool.createObjBuilders(env) |
||||
|
|
||||
|
cplusplus.generate(env) |
||||
|
|
||||
|
env['CXX'] = env.Detect(compilers) |
||||
|
|
||||
|
# 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' |
||||
|
# determine compiler version |
||||
|
if env['CXX']: |
||||
|
#pipe = SCons.Action._subproc(env, [env['CXX'], '-dumpversion'], |
||||
|
pipe = SCons.Action._subproc(env, [env['CXX'], '--version'], |
||||
|
stdin = 'devnull', |
||||
|
stderr = 'devnull', |
||||
|
stdout = subprocess.PIPE) |
||||
|
if pipe.wait() != 0: return |
||||
|
# -dumpversion was added in GCC 3.0. As long as we're supporting |
||||
|
# GCC versions older than that, we should use --version and a |
||||
|
# regular expression. |
||||
|
#line = pipe.stdout.read().strip() |
||||
|
#if line: |
||||
|
# env['CXXVERSION'] = line |
||||
|
line = pipe.stdout.readline() |
||||
|
match = re.search(r'[0-9]+(\.[0-9]+)+', line) |
||||
|
if match: |
||||
|
env['CXXVERSION'] = match.group(0) |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect(compilers) |
@ -0,0 +1,67 @@ |
|||||
|
"""engine.SCons.Tool.g77 |
||||
|
|
||||
|
Tool-specific initialization for g77. |
||||
|
|
||||
|
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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/g77.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons.Util |
||||
|
from SCons.Tool.FortranCommon import add_all_to_env, add_f77_to_env |
||||
|
|
||||
|
compilers = ['g77', 'f77'] |
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add Builders and construction variables for g77 to an Environment.""" |
||||
|
add_all_to_env(env) |
||||
|
add_f77_to_env(env) |
||||
|
|
||||
|
fcomp = env.Detect(compilers) or 'g77' |
||||
|
if env['PLATFORM'] in ['cygwin', 'win32']: |
||||
|
env['SHFORTRANFLAGS'] = SCons.Util.CLVar('$FORTRANFLAGS') |
||||
|
env['SHF77FLAGS'] = SCons.Util.CLVar('$F77FLAGS') |
||||
|
else: |
||||
|
env['SHFORTRANFLAGS'] = SCons.Util.CLVar('$FORTRANFLAGS -fPIC') |
||||
|
env['SHF77FLAGS'] = SCons.Util.CLVar('$F77FLAGS -fPIC') |
||||
|
|
||||
|
env['FORTRAN'] = fcomp |
||||
|
env['SHFORTRAN'] = '$FORTRAN' |
||||
|
|
||||
|
env['F77'] = fcomp |
||||
|
env['SHF77'] = '$F77' |
||||
|
|
||||
|
env['INCFORTRANPREFIX'] = "-I" |
||||
|
env['INCFORTRANSUFFIX'] = "" |
||||
|
|
||||
|
env['INCF77PREFIX'] = "-I" |
||||
|
env['INCF77SUFFIX'] = "" |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect(compilers) |
@ -0,0 +1,47 @@ |
|||||
|
"""SCons.Tool.gas |
||||
|
|
||||
|
Tool-specific initialization for as, the Gnu 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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/gas.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
as_module = __import__('as', globals(), locals(), []) |
||||
|
|
||||
|
assemblers = ['as', 'gas'] |
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add Builders and construction variables for as to an Environment.""" |
||||
|
as_module.generate(env) |
||||
|
|
||||
|
env['AS'] = env.Detect(assemblers) or 'as' |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect(assemblers) |
@ -0,0 +1,74 @@ |
|||||
|
"""SCons.Tool.gcc |
||||
|
|
||||
|
Tool-specific initialization for gcc. |
||||
|
|
||||
|
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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/gcc.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import cc |
||||
|
import os |
||||
|
import re |
||||
|
import subprocess |
||||
|
|
||||
|
import SCons.Util |
||||
|
|
||||
|
compilers = ['gcc', 'cc'] |
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add Builders and construction variables for gcc to an Environment.""" |
||||
|
cc.generate(env) |
||||
|
|
||||
|
env['CC'] = env.Detect(compilers) or 'gcc' |
||||
|
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 |
||||
|
# -dumpversion was added in GCC 3.0. As long as we're supporting |
||||
|
# GCC versions older than that, we should use --version and a |
||||
|
# regular expression. |
||||
|
#line = pipe.stdout.read().strip() |
||||
|
#if line: |
||||
|
# env['CCVERSION'] = line |
||||
|
line = pipe.stdout.readline() |
||||
|
match = re.search(r'[0-9]+(\.[0-9]+)+', line) |
||||
|
if match: |
||||
|
env['CCVERSION'] = match.group(0) |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect(compilers) |
@ -0,0 +1,58 @@ |
|||||
|
"""SCons.Tool.gfortran |
||||
|
|
||||
|
Tool-specific initialization for gfortran, the GNU Fortran 95/Fortran |
||||
|
2003 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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/gfortran.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons.Util |
||||
|
|
||||
|
import fortran |
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add Builders and construction variables for gfortran to an |
||||
|
Environment.""" |
||||
|
fortran.generate(env) |
||||
|
|
||||
|
for dialect in ['F77', 'F90', 'FORTRAN', 'F95']: |
||||
|
env['%s' % dialect] = 'gfortran' |
||||
|
env['SH%s' % dialect] = '$%s' % dialect |
||||
|
if env['PLATFORM'] in ['cygwin', 'win32']: |
||||
|
env['SH%sFLAGS' % dialect] = SCons.Util.CLVar('$%sFLAGS' % dialect) |
||||
|
else: |
||||
|
env['SH%sFLAGS' % dialect] = SCons.Util.CLVar('$%sFLAGS -fPIC' % dialect) |
||||
|
|
||||
|
env['INC%sPREFIX' % dialect] = "-I" |
||||
|
env['INC%sSUFFIX' % dialect] = "" |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect('gfortran') |
@ -0,0 +1,57 @@ |
|||||
|
"""SCons.Tool.gnulink |
||||
|
|
||||
|
Tool-specific initialization for the gnu 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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/gnulink.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons.Util |
||||
|
|
||||
|
import link |
||||
|
|
||||
|
linkers = ['g++', 'gcc'] |
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add Builders and construction variables for gnulink to an Environment.""" |
||||
|
link.generate(env) |
||||
|
|
||||
|
if env['PLATFORM'] == 'hpux': |
||||
|
env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -shared -fPIC') |
||||
|
|
||||
|
# __RPATH is set to $_RPATH in the platform specification if that |
||||
|
# platform supports it. |
||||
|
env.Append(LINKFLAGS=['$__RPATH']) |
||||
|
env['RPATHPREFIX'] = '-Wl,-rpath=' |
||||
|
env['RPATHSUFFIX'] = '' |
||||
|
env['_RPATH'] = '${_concat(RPATHPREFIX, RPATH, RPATHSUFFIX, __env__)}' |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect(linkers) |
@ -0,0 +1,75 @@ |
|||||
|
"""SCons.Tool.gs |
||||
|
|
||||
|
Tool-specific initialization for Ghostscript. |
||||
|
|
||||
|
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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/gs.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons.Action |
||||
|
import SCons.Platform |
||||
|
import SCons.Util |
||||
|
|
||||
|
# Ghostscript goes by different names on different platforms... |
||||
|
platform = SCons.Platform.platform_default() |
||||
|
|
||||
|
if platform == 'os2': |
||||
|
gs = 'gsos2' |
||||
|
elif platform == 'win32': |
||||
|
gs = 'gswin32c' |
||||
|
else: |
||||
|
gs = 'gs' |
||||
|
|
||||
|
GhostscriptAction = None |
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add Builders and construction variables for Ghostscript to an |
||||
|
Environment.""" |
||||
|
|
||||
|
global GhostscriptAction |
||||
|
if GhostscriptAction is None: |
||||
|
GhostscriptAction = SCons.Action.Action('$GSCOM', '$GSCOMSTR') |
||||
|
|
||||
|
import pdf |
||||
|
pdf.generate(env) |
||||
|
|
||||
|
bld = env['BUILDERS']['PDF'] |
||||
|
bld.add_action('.ps', GhostscriptAction) |
||||
|
|
||||
|
env['GS'] = gs |
||||
|
env['GSFLAGS'] = SCons.Util.CLVar('-dNOPAUSE -dBATCH -sDEVICE=pdfwrite') |
||||
|
env['GSCOM'] = '$GS $GSFLAGS -sOutputFile=$TARGET $SOURCES' |
||||
|
|
||||
|
|
||||
|
def exists(env): |
||||
|
if env.has_key('PS2PDF'): |
||||
|
return env.Detect(env['PS2PDF']) |
||||
|
else: |
||||
|
return env.Detect(gs) or SCons.Util.WhereIs(gs) |
@ -0,0 +1,79 @@ |
|||||
|
"""SCons.Tool.hpc++ |
||||
|
|
||||
|
Tool-specific initialization for c++ on HP/UX. |
||||
|
|
||||
|
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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/hpc++.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import os.path |
||||
|
import string |
||||
|
|
||||
|
import SCons.Util |
||||
|
|
||||
|
cplusplus = __import__('c++', globals(), locals(), []) |
||||
|
|
||||
|
acc = None |
||||
|
|
||||
|
# search for the acc compiler and linker front end |
||||
|
|
||||
|
try: |
||||
|
dirs = os.listdir('/opt') |
||||
|
except (IOError, OSError): |
||||
|
# Not being able to read the directory because it doesn't exist |
||||
|
# (IOError) or isn't readable (OSError) is okay. |
||||
|
dirs = [] |
||||
|
|
||||
|
for dir in dirs: |
||||
|
cc = '/opt/' + dir + '/bin/aCC' |
||||
|
if os.path.exists(cc): |
||||
|
acc = cc |
||||
|
break |
||||
|
|
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add Builders and construction variables for g++ to an Environment.""" |
||||
|
cplusplus.generate(env) |
||||
|
|
||||
|
if acc: |
||||
|
env['CXX'] = acc or 'aCC' |
||||
|
env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS +Z') |
||||
|
# determine version of aCC |
||||
|
line = os.popen(acc + ' -V 2>&1').readline().rstrip() |
||||
|
if string.find(line, 'aCC: HP ANSI C++') == 0: |
||||
|
env['CXXVERSION'] = string.split(line)[-1] |
||||
|
|
||||
|
if env['PLATFORM'] == 'cygwin': |
||||
|
env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS') |
||||
|
else: |
||||
|
env['SHCXXFLAGS'] = SCons.Util.CLVar('$CXXFLAGS +Z') |
||||
|
|
||||
|
def exists(env): |
||||
|
return acc |
@ -0,0 +1,47 @@ |
|||||
|
"""SCons.Tool.hpcc |
||||
|
|
||||
|
Tool-specific initialization for HP aCC and cc. |
||||
|
|
||||
|
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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/hpcc.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons.Util |
||||
|
|
||||
|
import cc |
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add Builders and construction variables for aCC & cc to an Environment.""" |
||||
|
cc.generate(env) |
||||
|
|
||||
|
env['CXX'] = 'aCC' |
||||
|
env['SHCCFLAGS'] = SCons.Util.CLVar('$CCFLAGS +Z') |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect('aCC') |
@ -0,0 +1,71 @@ |
|||||
|
"""SCons.Tool.hplink |
||||
|
|
||||
|
Tool-specific initialization for the HP 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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/hplink.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import os |
||||
|
import os.path |
||||
|
|
||||
|
import SCons.Util |
||||
|
|
||||
|
import link |
||||
|
|
||||
|
ccLinker = None |
||||
|
|
||||
|
# search for the acc compiler and linker front end |
||||
|
|
||||
|
try: |
||||
|
dirs = os.listdir('/opt') |
||||
|
except (IOError, OSError): |
||||
|
# Not being able to read the directory because it doesn't exist |
||||
|
# (IOError) or isn't readable (OSError) is okay. |
||||
|
dirs = [] |
||||
|
|
||||
|
for dir in dirs: |
||||
|
linker = '/opt/' + dir + '/bin/aCC' |
||||
|
if os.path.exists(linker): |
||||
|
ccLinker = linker |
||||
|
break |
||||
|
|
||||
|
def generate(env): |
||||
|
""" |
||||
|
Add Builders and construction variables for Visual Age linker to |
||||
|
an Environment. |
||||
|
""" |
||||
|
link.generate(env) |
||||
|
|
||||
|
env['LINKFLAGS'] = SCons.Util.CLVar('-Wl,+s -Wl,+vnocompatwarnings') |
||||
|
env['SHLINKFLAGS'] = SCons.Util.CLVar('$LINKFLAGS -b') |
||||
|
env['SHLIBSUFFIX'] = '.sl' |
||||
|
|
||||
|
def exists(env): |
||||
|
return ccLinker |
@ -0,0 +1,53 @@ |
|||||
|
"""engine.SCons.Tool.icc |
||||
|
|
||||
|
Tool-specific initialization for the OS/2 icc 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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/icc.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import cc |
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add Builders and construction variables for the OS/2 to an Environment.""" |
||||
|
cc.generate(env) |
||||
|
|
||||
|
env['CC'] = 'icc' |
||||
|
env['CCCOM'] = '$CC $CFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET' |
||||
|
env['CXXCOM'] = '$CXX $CXXFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS /c $SOURCES /Fo$TARGET' |
||||
|
env['CPPDEFPREFIX'] = '/D' |
||||
|
env['CPPDEFSUFFIX'] = '' |
||||
|
env['INCPREFIX'] = '/I' |
||||
|
env['INCSUFFIX'] = '' |
||||
|
env['CFILESUFFIX'] = '.c' |
||||
|
env['CXXFILESUFFIX'] = '.cc' |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect('icc') |
@ -0,0 +1,46 @@ |
|||||
|
"""engine.SCons.Tool.icl |
||||
|
|
||||
|
Tool-specific initialization for the Intel C/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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/icl.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons.Tool.intelc |
||||
|
|
||||
|
# This has been completely superceded by intelc.py, which can |
||||
|
# handle both Windows and Linux versions. |
||||
|
|
||||
|
def generate(*args, **kw): |
||||
|
"""Add Builders and construction variables for icl to an Environment.""" |
||||
|
return apply(SCons.Tool.intelc.generate, args, kw) |
||||
|
|
||||
|
def exists(*args, **kw): |
||||
|
return apply(SCons.Tool.intelc.exists, args, kw) |
@ -0,0 +1,66 @@ |
|||||
|
"""SCons.Tool.ifl |
||||
|
|
||||
|
Tool-specific initialization for the Intel 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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/ifl.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons.Defaults |
||||
|
from SCons.Scanner.Fortran import FortranScan |
||||
|
from FortranCommon import add_all_to_env |
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add Builders and construction variables for ifl to an Environment.""" |
||||
|
fscan = FortranScan("FORTRANPATH") |
||||
|
SCons.Tool.SourceFileScanner.add_scanner('.i', fscan) |
||||
|
SCons.Tool.SourceFileScanner.add_scanner('.i90', fscan) |
||||
|
|
||||
|
if not env.has_key('FORTRANFILESUFFIXES'): |
||||
|
env['FORTRANFILESUFFIXES'] = ['.i'] |
||||
|
else: |
||||
|
env['FORTRANFILESUFFIXES'].append('.i') |
||||
|
|
||||
|
if not env.has_key('F90FILESUFFIXES'): |
||||
|
env['F90FILESUFFIXES'] = ['.i90'] |
||||
|
else: |
||||
|
env['F90FILESUFFIXES'].append('.i90') |
||||
|
|
||||
|
add_all_to_env(env) |
||||
|
|
||||
|
env['FORTRAN'] = 'ifl' |
||||
|
env['SHFORTRAN'] = '$FORTRAN' |
||||
|
env['FORTRANCOM'] = '$FORTRAN $FORTRANFLAGS $_FORTRANINCFLAGS /c $SOURCES /Fo$TARGET' |
||||
|
env['FORTRANPPCOM'] = '$FORTRAN $FORTRANFLAGS $CPPFLAGS $_CPPDEFFLAGS $_FORTRANINCFLAGS /c $SOURCES /Fo$TARGET' |
||||
|
env['SHFORTRANCOM'] = '$SHFORTRAN $SHFORTRANFLAGS $_FORTRANINCFLAGS /c $SOURCES /Fo$TARGET' |
||||
|
env['SHFORTRANPPCOM'] = '$SHFORTRAN $SHFORTRANFLAGS $CPPFLAGS $_CPPDEFFLAGS $_FORTRANINCFLAGS /c $SOURCES /Fo$TARGET' |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect('ifl') |
@ -0,0 +1,83 @@ |
|||||
|
"""SCons.Tool.ifort |
||||
|
|
||||
|
Tool-specific initialization for newer versions of the Intel Fortran Compiler |
||||
|
for Linux/Windows (and possibly Mac OS X). |
||||
|
|
||||
|
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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/ifort.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import string |
||||
|
|
||||
|
import SCons.Defaults |
||||
|
from SCons.Scanner.Fortran import FortranScan |
||||
|
from FortranCommon import add_all_to_env |
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add Builders and construction variables for ifort to an Environment.""" |
||||
|
# ifort supports Fortran 90 and Fortran 95 |
||||
|
# Additionally, ifort recognizes more file extensions. |
||||
|
fscan = FortranScan("FORTRANPATH") |
||||
|
SCons.Tool.SourceFileScanner.add_scanner('.i', fscan) |
||||
|
SCons.Tool.SourceFileScanner.add_scanner('.i90', fscan) |
||||
|
|
||||
|
if not env.has_key('FORTRANFILESUFFIXES'): |
||||
|
env['FORTRANFILESUFFIXES'] = ['.i'] |
||||
|
else: |
||||
|
env['FORTRANFILESUFFIXES'].append('.i') |
||||
|
|
||||
|
if not env.has_key('F90FILESUFFIXES'): |
||||
|
env['F90FILESUFFIXES'] = ['.i90'] |
||||
|
else: |
||||
|
env['F90FILESUFFIXES'].append('.i90') |
||||
|
|
||||
|
add_all_to_env(env) |
||||
|
|
||||
|
fc = 'ifort' |
||||
|
|
||||
|
for dialect in ['F77', 'F90', 'FORTRAN', 'F95']: |
||||
|
env['%s' % dialect] = fc |
||||
|
env['SH%s' % dialect] = '$%s' % dialect |
||||
|
env['SH%sFLAGS' % dialect] = SCons.Util.CLVar('$%sFLAGS -fPIC' % dialect) |
||||
|
|
||||
|
if env['PLATFORM'] == 'win32': |
||||
|
# On Windows, the ifort compiler specifies the object on the |
||||
|
# command line with -object:, not -o. Massage the necessary |
||||
|
# command-line construction variables. |
||||
|
for dialect in ['F77', 'F90', 'FORTRAN', 'F95']: |
||||
|
for var in ['%sCOM' % dialect, '%sPPCOM' % dialect, |
||||
|
'SH%sCOM' % dialect, 'SH%sPPCOM' % dialect]: |
||||
|
env[var] = string.replace(env[var], '-o $TARGET', '-object:$TARGET') |
||||
|
env['FORTRANMODDIRPREFIX'] = "/module:" |
||||
|
else: |
||||
|
env['FORTRANMODDIRPREFIX'] = "-module " |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect('ifort') |
@ -0,0 +1,53 @@ |
|||||
|
"""SCons.Tool.ilink |
||||
|
|
||||
|
Tool-specific initialization for the OS/2 ilink 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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/ilink.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons.Defaults |
||||
|
import SCons.Tool |
||||
|
import SCons.Util |
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add Builders and construction variables for ilink to an Environment.""" |
||||
|
SCons.Tool.createProgBuilder(env) |
||||
|
|
||||
|
env['LINK'] = 'ilink' |
||||
|
env['LINKFLAGS'] = SCons.Util.CLVar('') |
||||
|
env['LINKCOM'] = '$LINK $LINKFLAGS /O:$TARGET $SOURCES $( $_LIBDIRFLAGS $) $_LIBFLAGS' |
||||
|
env['LIBDIRPREFIX']='/LIBPATH:' |
||||
|
env['LIBDIRSUFFIX']='' |
||||
|
env['LIBLINKPREFIX']='' |
||||
|
env['LIBLINKSUFFIX']='$LIBSUFFIX' |
||||
|
|
||||
|
def exists(env): |
||||
|
return env.Detect('ilink') |
@ -0,0 +1,54 @@ |
|||||
|
"""SCons.Tool.ilink32 |
||||
|
|
||||
|
XXX |
||||
|
|
||||
|
""" |
||||
|
|
||||
|
# |
||||
|
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/ilink32.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import SCons.Tool |
||||
|
import SCons.Tool.bcc32 |
||||
|
import SCons.Util |
||||
|
|
||||
|
def generate(env): |
||||
|
"""Add Builders and construction variables for ilink to an |
||||
|
Environment.""" |
||||
|
SCons.Tool.createSharedLibBuilder(env) |
||||
|
SCons.Tool.createProgBuilder(env) |
||||
|
|
||||
|
env['LINK'] = '$CC' |
||||
|
env['LINKFLAGS'] = SCons.Util.CLVar('') |
||||
|
env['LINKCOM'] = '$LINK -q $LINKFLAGS $SOURCES $LIBS' |
||||
|
env['LIBDIRPREFIX']='' |
||||
|
env['LIBDIRSUFFIX']='' |
||||
|
env['LIBLINKPREFIX']='' |
||||
|
env['LIBLINKSUFFIX']='$LIBSUFFIX' |
||||
|
|
||||
|
|
||||
|
def exists(env): |
||||
|
# Uses bcc32 to do linking as it generally knows where the standard |
||||
|
# LIBS are and set up the linking correctly |
||||
|
return SCons.Tool.bcc32.findIt('bcc32', env) |
@ -0,0 +1,223 @@ |
|||||
|
"""SCons.Tool.install |
||||
|
|
||||
|
Tool-specific initialization for the install tool. |
||||
|
|
||||
|
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 (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation |
||||
|
# |
||||
|
# Permission is hereby granted, free of charge, to any person obtaining |
||||
|
# a copy of this software and associated documentation files (the |
||||
|
# "Software"), to deal in the Software without restriction, including |
||||
|
# without limitation the rights to use, copy, modify, merge, publish, |
||||
|
# distribute, sublicense, and/or sell copies of the Software, and to |
||||
|
# permit persons to whom the Software is furnished to do so, subject to |
||||
|
# the following conditions: |
||||
|
# |
||||
|
# The above copyright notice and this permission notice shall be included |
||||
|
# in all copies or substantial portions of the Software. |
||||
|
# |
||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY |
||||
|
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE |
||||
|
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
||||
|
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
||||
|
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
||||
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
||||
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||||
|
# |
||||
|
|
||||
|
__revision__ = "src/engine/SCons/Tool/install.py 3842 2008/12/20 22:59:52 scons" |
||||
|
|
||||
|
import os |
||||
|
import shutil |
||||
|
import stat |
||||
|
|
||||
|
import SCons.Action |
||||
|
from SCons.Util import make_path_relative |
||||
|
|
||||
|
# |
||||
|
# We keep track of *all* installed files. |
||||
|
_INSTALLED_FILES = [] |
||||
|
_UNIQUE_INSTALLED_FILES = None |
||||
|
|
||||
|
# |
||||
|
# Functions doing the actual work of the Install Builder. |
||||
|
# |
||||
|
def copyFunc(dest, source, env): |
||||
|
"""Install a source file or directory into a destination by copying, |
||||
|
(including copying permission/mode bits).""" |
||||
|
|
||||
|
if os.path.isdir(source): |
||||
|
if os.path.exists(dest): |
||||
|
if not os.path.isdir(dest): |
||||
|
raise SCons.Errors.UserError, "cannot overwrite non-directory `%s' with a directory `%s'" % (str(dest), str(source)) |
||||
|
else: |
||||
|
parent = os.path.split(dest)[0] |
||||
|
if not os.path.exists(parent): |
||||
|
os.makedirs(parent) |
||||
|
shutil.copytree(source, dest) |
||||
|
else: |
||||
|
shutil.copy2(source, dest) |
||||
|
st = os.stat(source) |
||||
|
os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE) |
||||
|
|
||||
|
return 0 |
||||
|
|
||||
|
def installFunc(target, source, env): |
||||
|
"""Install a source file into a target using the function specified |
||||
|
as the INSTALL construction variable.""" |
||||
|
try: |
||||
|
install = env['INSTALL'] |
||||
|
except KeyError: |
||||
|
raise SCons.Errors.UserError('Missing INSTALL construction variable.') |
||||
|
|
||||
|
assert len(target)==len(source), \ |
||||
|
"Installing source %s into target %s: target and source lists must have same length."%(map(str, source), map(str, target)) |
||||
|
for t,s in zip(target,source): |
||||
|
if install(t.get_path(),s.get_path(),env): |
||||
|
return 1 |
||||
|
|
||||
|
return 0 |
||||
|
|
||||
|
def stringFunc(target, source, env): |
||||
|
installstr = env.get('INSTALLSTR') |
||||
|
if installstr: |
||||
|
return env.subst_target_source(installstr, 0, target, source) |
||||
|
target = str(target[0]) |
||||
|
source = str(source[0]) |
||||
|
if os.path.isdir(source): |
||||
|
type = 'directory' |
||||
|
else: |
||||
|
type = 'file' |
||||
|
return 'Install %s: "%s" as "%s"' % (type, source, target) |
||||
|
|
||||
|
# |
||||
|
# Emitter functions |
||||
|
# |
||||
|
def add_targets_to_INSTALLED_FILES(target, source, env): |
||||
|
""" an emitter that adds all target files to the list stored in the |
||||
|
_INSTALLED_FILES global variable. This way all installed files of one |
||||
|
scons call will be collected. |
||||
|
""" |
||||
|
global _INSTALLED_FILES, _UNIQUE_INSTALLED_FILES |
||||
|
_INSTALLED_FILES.extend(target) |
||||
|
_UNIQUE_INSTALLED_FILES = None |
||||
|
return (target, source) |
||||
|
|
||||
|
class DESTDIR_factory: |
||||
|
""" a node factory, where all files will be relative to the dir supplied |
||||
|
in the constructor. |
||||
|
""" |
||||
|
def __init__(self, env, dir): |
||||
|
self.env = env |
||||
|
self.dir = env.arg2nodes( dir, env.fs.Dir )[0] |
||||
|
|
||||
|
def Entry(self, name): |
||||
|
name = make_path_relative(name) |
||||
|
return self.dir.Entry(name) |
||||
|
|
||||
|
def Dir(self, name): |
||||
|
name = make_path_relative(name) |
||||
|
return self.dir.Dir(name) |
||||
|
|
||||
|
# |
||||
|
# The Builder Definition |
||||
|
# |
||||
|
install_action = SCons.Action.Action(installFunc, stringFunc) |
||||
|
installas_action = SCons.Action.Action(installFunc, stringFunc) |
||||
|
|
||||
|
BaseInstallBuilder = None |
||||
|
|
||||
|
def InstallBuilderWrapper(env, target=None, source=None, dir=None, **kw): |
||||
|
if target and dir: |
||||
|
import SCons.Errors |
||||
|
raise SCons.Errors.UserError, "Both target and dir defined for Install(), only one may be defined." |
||||
|
if not dir: |
||||
|
dir=target |
||||
|
|
||||
|
import SCons.Script |
||||
|
install_sandbox = SCons.Script.GetOption('install_sandbox') |
||||
|
if install_sandbox: |
||||
|
target_factory = DESTDIR_factory(env, install_sandbox) |
||||
|
else: |
||||
|
target_factory = env.fs |
||||
|
|
||||
|
try: |
||||
|
dnodes = env.arg2nodes(dir, target_factory.Dir) |
||||
|
except TypeError: |
||||
|
raise SCons.Errors.UserError, "Target `%s' of Install() is a file, but should be a directory. Perhaps you have the Install() arguments backwards?" % str(dir) |
||||
|
sources = env.arg2nodes(source, env.fs.Entry) |
||||
|
tgt = [] |
||||
|
for dnode in dnodes: |
||||
|
for src in sources: |
||||
|
# Prepend './' so the lookup doesn't interpret an initial |
||||
|
# '#' on the file name portion as meaning the Node should |
||||
|
# be relative to the top-level SConstruct directory. |
||||
|
target = env.fs.Entry('.'+os.sep+src.name, dnode) |
||||
|
#tgt.extend(BaseInstallBuilder(env, target, src, **kw)) |
||||
|
tgt.extend(apply(BaseInstallBuilder, (env, target, src), kw)) |
||||
|
return tgt |
||||
|
|
||||
|
def InstallAsBuilderWrapper(env, target=None, source=None, **kw): |
||||
|
result = [] |
||||
|
for src, tgt in map(lambda x, y: (x, y), source, target): |
||||
|
#result.extend(BaseInstallBuilder(env, tgt, src, **kw)) |
||||
|
result.extend(apply(BaseInstallBuilder, (env, tgt, src), kw)) |
||||
|
return result |
||||
|
|
||||
|
added = None |
||||
|
|
||||
|
def generate(env): |
||||
|
|
||||
|
from SCons.Script import AddOption, GetOption |
||||
|
global added |
||||
|
if not added: |
||||
|
added = 1 |
||||
|
AddOption('--install-sandbox', |
||||
|
dest='install_sandbox', |
||||
|
type="string", |
||||
|
action="store", |
||||
|
help='A directory under which all installed files will be placed.') |
||||
|
|
||||
|
global BaseInstallBuilder |
||||
|
if BaseInstallBuilder is None: |
||||
|
install_sandbox = GetOption('install_sandbox') |
||||
|
if install_sandbox: |
||||
|
target_factory = DESTDIR_factory(env, install_sandbox) |
||||
|
else: |
||||
|
target_factory = env.fs |
||||
|
|
||||
|
BaseInstallBuilder = SCons.Builder.Builder( |
||||
|
action = install_action, |
||||
|
target_factory = target_factory.Entry, |
||||
|
source_factory = env.fs.Entry, |
||||
|
multi = 1, |
||||
|
emitter = [ add_targets_to_INSTALLED_FILES, ], |
||||
|
name = 'InstallBuilder') |
||||
|
|
||||
|
env['BUILDERS']['_InternalInstall'] = InstallBuilderWrapper |
||||
|
env['BUILDERS']['_InternalInstallAs'] = InstallAsBuilderWrapper |
||||
|
|
||||
|
# We'd like to initialize this doing something like the following, |
||||
|
# but there isn't yet support for a ${SOURCE.type} expansion that |
||||
|
# will print "file" or "directory" depending on what's being |
||||
|
# installed. For now we punt by not initializing it, and letting |
||||
|
# the stringFunc() that we put in the action fall back to the |
||||
|
# hand-crafted default string if it's not set. |
||||
|
# |
||||
|
#try: |
||||
|
# env['INSTALLSTR'] |
||||
|
#except KeyError: |
||||
|
# env['INSTALLSTR'] = 'Install ${SOURCE.type}: "$SOURCES" as "$TARGETS"' |
||||
|
|
||||
|
try: |
||||
|
env['INSTALL'] |
||||
|
except KeyError: |
||||
|
env['INSTALL'] = copyFunc |
||||
|
|
||||
|
def exists(env): |
||||
|
return 1 |
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue