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