summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/man/scons.169
-rw-r--r--src/CHANGES.txt2
-rw-r--r--src/engine/MANIFEST.in1
-rw-r--r--src/engine/SCons/Action.py281
-rw-r--r--src/engine/SCons/ActionTests.py190
-rw-r--r--src/engine/SCons/Builder.py251
-rw-r--r--src/engine/SCons/Script/__init__.py4
7 files changed, 524 insertions, 274 deletions
diff --git a/doc/man/scons.1 b/doc/man/scons.1
index bcf5898..c19641b 100644
--- a/doc/man/scons.1
+++ b/doc/man/scons.1
@@ -582,7 +582,7 @@ env.Depends('foo.c', 'foo.h')
.PP
.fi
-.SH Construction Variables
+.SS Construction Variables
A construction environment has an associated dictionary of construction
variables that are used by built-in or user-supplied build rules. A number
@@ -964,7 +964,8 @@ can be a relative or absolute path.
is an optional directory that will be used as the parent directory.
-.SH EXTENDING
+.SH EXTENDING SCONS
+.SS Builder Objects
.B scons
can be extended by adding new builders to a construction
environment using the
@@ -979,8 +980,12 @@ method used to create an instance of the builder.
.IP action
The command line string used to build the target from the source.
.B action
-can also be a dictionary mapping source file name suffixes to command line string,
-if the builder can accept multiple source file extensions.
+can also be a dictionary
+mapping source file name suffixes to command line string
+(if the builder should accept multiple source file extensions),
+a Python function,
+or an Action object
+(see the next section).
.IP prefix
The prefix that will be prepended to the target file name.
@@ -996,8 +1001,41 @@ Specifies a builder to use when a source file name suffix does not match
any of the suffixes of the builder. Using this argument produces a
multi-stage builder.
-.LP
+.SS Action Objects
+The Builder function will turn its
+.B action
+keyword argument into an appropriate
+internal Action object.
+Occasionally, it may be more efficient
+to create an explicit Action object
+and use it to initialize multiple
+Builder objects,
+rather than let each separate Builder object
+create a separate Action.
+
+The Action function takes a single argument
+and returns an appropriate object for the action
+represented by the type of the argument:
+
+.IP Action
+If the argument is already an Action object,
+the object is simply returned.
+.IP String
+If the argument is a string,
+a command-line Action is returned.
+.IP Function
+If the argument is a Python function,
+a function Action is returned.
+.IP List
+If the argument is a list,
+then a list of Action objects is returned.
+An Action object is created as necessary
+for each element in the list.
+.PP
+If the action argument is not one of the above,
+None is returned.
+.SS Variable Substitution
.B scons
performs construction variable interpolation on the strings that make up
the command line of builders before executing the command.
@@ -1006,57 +1044,44 @@ Variables are introduced by a
prefix.
Besides construction variables, scons provides the following
variables for each command execution:
-
.IP TARGET
The file name of the target being built, or the file name of the first
target if multiple targets are being built.
-
.IP TARGETS
-The file names of the targets being built.
-
+The file names of all targets being built.
.IP SOURCES
The file names of the sources of the build command.
-
.LP
-
For example, given the construction variable CC='cc', targets=['foo'], and
sources=['foo.c', 'bar.c']:
-
.IP
.nf
action='$CC -c -o $TARGET $SOURCES'
.PP
.fi
-
would produce the command line:
-
.IP
.nf
cc -c -o foo foo.c bar.c
.PP
.fi
-
Variable names may be surrounded by curly braces ({})
to separate the name from the trailing characters.
Within the curly braces, a variable name may have
a Python slice subscript appended to select one
or more items from a list.
In the previous example, the string:
-
.IP
.nf
${SOURCES[1]}
.PP
.fi
-
would produce:
-
.IP
.nf
bar.c
.PP
.fi
-
Additionally, a variable name may
have the following special
modifiers appended within the enclosing curly braces
@@ -1102,10 +1127,8 @@ ${TARGET.suffix} => .x
.SH EXAMPLES
-To help you get started using SCons
-(in lieu of a complete user guide),
-here is a
-brief overview of how to perform some common tasks:
+To help you get started using SCons,
+here is a brief overview of some common tasks:
.SS Basic Compilation From a Single Source File
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index 31763f5..2d29028 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -40,6 +40,8 @@ RELEASE 0.03 -
- Collect String, Dict, and List type-checking in common utility
routines so we can accept User{String,Dict,List}s all over.
+ - Put the Action factory and classes into their own module.
+
From Anthony Roach:
- Add a "duplicate" keyword argument to BuildDir() that can be set
diff --git a/src/engine/MANIFEST.in b/src/engine/MANIFEST.in
index 5c6c0b0..100abcb 100644
--- a/src/engine/MANIFEST.in
+++ b/src/engine/MANIFEST.in
@@ -1,4 +1,5 @@
SCons/__init__.py
+SCons/Action.py
SCons/Builder.py
SCons/Defaults.py
SCons/Environment.py
diff --git a/src/engine/SCons/Action.py b/src/engine/SCons/Action.py
new file mode 100644
index 0000000..7e53c2b
--- /dev/null
+++ b/src/engine/SCons/Action.py
@@ -0,0 +1,281 @@
+"""engine.SCons.Action
+
+XXX
+
+"""
+
+#
+# Copyright (c) 2001 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.
+#
+
+__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
+
+import os
+import os.path
+import string
+import sys
+
+import SCons.Util
+
+print_actions = 1;
+execute_actions = 1;
+
+exitvalmap = {
+ 2 : 127,
+ 13 : 126,
+}
+
+if os.name == 'posix':
+
+ def spawn(cmd, args, env):
+ pid = os.fork()
+ if not pid:
+ # Child process.
+ exitval = 127
+ try:
+ os.execvpe(cmd, args, env)
+ except OSError, e:
+ exitval = exitvalmap[e[0]]
+ sys.stderr.write("scons: %s: %s\n" % (cmd, e[1]))
+ os._exit(exitval)
+ else:
+ # Parent process.
+ pid, stat = os.waitpid(pid, 0)
+ ret = stat >> 8
+ return ret
+
+elif os.name == 'nt':
+
+ def pathsearch(cmd, env):
+ # In order to deal with the fact that 1.5.2 doesn't have
+ # os.spawnvpe(), roll our own PATH search.
+ if os.path.isabs(cmd):
+ if not os.path.exists(cmd):
+ exts = env['PATHEXT']
+ if not SCons.Util.is_List(exts):
+ exts = string.split(exts, os.pathsep)
+ for e in exts:
+ f = cmd + e
+ if os.path.exists(f):
+ return f
+ else:
+ path = env['PATH']
+ if not SCons.Util.is_List(path):
+ path = string.split(path, os.pathsep)
+ exts = env['PATHEXT']
+ if not SCons.Util.is_List(exts):
+ exts = string.split(exts, os.pathsep)
+ pairs = []
+ for dir in path:
+ for e in exts:
+ pairs.append((dir, e))
+ for dir, ext in pairs:
+ f = os.path.join(dir, cmd)
+ if not ext is None:
+ f = f + ext
+ if os.path.exists(f):
+ return f
+ return cmd
+
+ def spawn(cmd, args, env):
+ try:
+ try:
+ ret = os.spawnvpe(os.P_WAIT, cmd, args, env)
+ except AttributeError:
+ cmd = pathsearch(cmd, env)
+ ret = os.spawnve(os.P_WAIT, cmd, args, env)
+ except OSError, e:
+ ret = exitvalmap[e[0]]
+ sys.stderr.write("scons: %s: %s\n" % (cmd, e[1]))
+ return ret
+
+def Action(act):
+ """A factory for action objects."""
+ if isinstance(act, ActionBase):
+ return act
+ elif callable(act):
+ return FunctionAction(act)
+ elif SCons.Util.is_String(act):
+ return CommandAction(act)
+ elif SCons.Util.is_List(act):
+ return ListAction(act)
+ else:
+ return None
+
+class ActionBase:
+ """Base class for actions that create output objects."""
+ def __cmp__(self, other):
+ return cmp(self.__dict__, other.__dict__)
+
+ def show(self, string):
+ print string
+
+ def subst_dict(self, **kw):
+ """Create a dictionary for substitution of construction
+ variables.
+
+ This translates the following special arguments:
+
+ env - the construction environment itself,
+ the values of which (CC, CCFLAGS, etc.)
+ are copied straight into the dictionary
+
+ 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 construction
+ variable
+
+ Any other keyword arguments are copied into the
+ dictionary."""
+
+ dict = {}
+ if kw.has_key('env'):
+ dict.update(kw['env'])
+ del kw['env']
+
+ try:
+ cwd = kw['dir']
+ except:
+ cwd = None
+ else:
+ del kw['dir']
+
+ if kw.has_key('target'):
+ t = kw['target']
+ del kw['target']
+ if not SCons.Util.is_List(t):
+ t = [t]
+ try:
+ cwd = t[0].cwd
+ except AttributeError:
+ pass
+ dict['TARGETS'] = SCons.Util.PathList(map(os.path.normpath, map(str, t)))
+ if dict['TARGETS']:
+ dict['TARGET'] = dict['TARGETS'][0]
+
+ if kw.has_key('source'):
+ s = kw['source']
+ del kw['source']
+ if not SCons.Util.is_List(s):
+ s = [s]
+ dict['SOURCES'] = SCons.Util.PathList(map(os.path.normpath, map(str, s)))
+
+ dict.update(kw)
+
+ # Autogenerate necessary construction variables.
+ SCons.Util.autogenerate(dict, dir = cwd)
+
+ return dict
+
+class CommandAction(ActionBase):
+ """Class for command-execution actions."""
+ def __init__(self, string):
+ self.command = string
+
+ def execute(self, **kw):
+ import SCons.Util
+ dict = apply(self.subst_dict, (), kw)
+ cmd_list = SCons.Util.scons_subst_list(self.command, dict, {})
+ for cmd_line in cmd_list:
+ if len(cmd_line):
+ if print_actions:
+ self.show(string.join(cmd_line))
+ if execute_actions:
+ try:
+ ENV = kw['env']['ENV']
+ except:
+ import SCons.Defaults
+ ENV = SCons.Defaults.ConstructionEnvironment['ENV']
+ ret = spawn(cmd_line[0], cmd_line, ENV)
+ if ret:
+ return ret
+ return 0
+
+ def get_contents(self, **kw):
+ """Return the signature contents of this action's command line.
+
+ For signature purposes, it doesn't matter what targets or
+ sources we use, so long as we use the same ones every time
+ so the signature stays the same. We supply an array of two
+ of each to allow for distinction between TARGET and TARGETS.
+ """
+ kw['target'] = ['__t1__', '__t2__']
+ kw['source'] = ['__s1__', '__s2__']
+ dict = apply(self.subst_dict, (), kw)
+ return SCons.Util.scons_subst(self.command, dict, {})
+
+class FunctionAction(ActionBase):
+ """Class for Python function actions."""
+ def __init__(self, function):
+ self.function = function
+
+ def execute(self, **kw):
+ # if print_actions:
+ # XXX: WHAT SHOULD WE PRINT HERE?
+ if execute_actions:
+ if kw.has_key('target'):
+ if SCons.Util.is_List(kw['target']):
+ kw['target'] = map(str, kw['target'])
+ else:
+ kw['target'] = str(kw['target'])
+ if kw.has_key('source'):
+ kw['source'] = map(str, kw['source'])
+ return apply(self.function, (), kw)
+
+ def get_contents(self, **kw):
+ """Return the signature contents of this callable action.
+
+ By providing direct access to the code object of the
+ function, Python makes this extremely easy. Hooray!
+ """
+ #XXX DOES NOT ACCOUNT FOR CHANGES IN ENVIRONMENT VARIABLES
+ #THE FUNCTION MAY USE
+ try:
+ # "self.function" is a function.
+ code = self.function.func_code.co_code
+ except:
+ # "self.function" is a callable object.
+ code = self.function.__call__.im_func.func_code.co_code
+ return str(code)
+
+class ListAction(ActionBase):
+ """Class for lists of other actions."""
+ def __init__(self, list):
+ self.list = map(lambda x: Action(x), list)
+
+ def execute(self, **kw):
+ for l in self.list:
+ r = apply(l.execute, (), kw)
+ if r != 0:
+ return r
+ return 0
+
+ def get_contents(self, **kw):
+ """Return the signature contents of this action list.
+
+ Simple concatenation of the signatures of the elements.
+ """
+
+ return reduce(lambda x, y: x + str(y.get_contents()), self.list, "")
diff --git a/src/engine/SCons/ActionTests.py b/src/engine/SCons/ActionTests.py
new file mode 100644
index 0000000..c01f47c
--- /dev/null
+++ b/src/engine/SCons/ActionTests.py
@@ -0,0 +1,190 @@
+#
+# Copyright (c) 2001 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.
+#
+
+__revision__ = "src/engine/SCons/ActionTests.py __REVISION__ __DATE__ __DEVELOPER__"
+
+# Define a null function for use as a builder action.
+# Where this is defined in the file seems to affect its
+# byte-code contents, so try to minimize changes by
+# defining it here, before we even import anything.
+def Func():
+ pass
+
+import unittest
+
+import sys
+import unittest
+
+import SCons.Action
+import TestCmd
+
+class ActionTestCase(unittest.TestCase):
+
+ def runTest(self):
+ """Test the Action factory
+ """
+ def foo():
+ pass
+ a1 = SCons.Action.Action(foo)
+ assert isinstance(a1, SCons.Action.FunctionAction)
+
+ a2 = SCons.Action.Action("string")
+ assert isinstance(a2, SCons.Action.CommandAction)
+
+ a3 = SCons.Action.Action(["x", a2, "y"])
+ assert isinstance(a3, SCons.Action.ListAction)
+
+ a4 = SCons.Action.Action(1)
+ assert a4 is None, a4
+
+ a5 = SCons.Action.Action(a1)
+ assert a5 is a1
+
+class ActionBaseTestCase(unittest.TestCase):
+
+ def test_cmp(self):
+ """Test Action comparison
+ """
+ a1 = SCons.Action.Action("x")
+ a2 = SCons.Action.Action("x")
+ assert a1 == a2
+ a3 = SCons.Action.Action("y")
+ assert a1 != a3
+ assert a2 != a3
+
+ def test_subst_dict(self):
+ """Test substituting dictionary values in an Action
+ """
+ a = SCons.Action.Action("x")
+
+ d = a.subst_dict(env = {'a' : 'A', 'b' : 'B'})
+ assert d['a'] == 'A', d
+ assert d['b'] == 'B', d
+
+ d = a.subst_dict(target = 't', source = 's')
+ assert str(d['TARGETS']) == 't', d['TARGETS']
+ assert str(d['TARGET']) == 't', d['TARGET']
+ assert str(d['SOURCES']) == 's', d['SOURCES']
+
+ d = a.subst_dict(target = ['t1', 't2'], source = ['s1', 's2'])
+ TARGETS = map(lambda x: str(x), d['TARGETS'])
+ TARGETS.sort()
+ assert TARGETS == ['t1', 't2'], d['TARGETS']
+ assert str(d['TARGET']) == 't1', d['TARGET']
+ SOURCES = map(lambda x: str(x), d['SOURCES'])
+ SOURCES.sort()
+ assert SOURCES == ['s1', 's2'], d['SOURCES']
+
+class CommandActionTestCase(unittest.TestCase):
+
+ def test_init(self):
+ """Test creation of a command Action
+ """
+ a = SCons.Action.CommandAction("xyzzy")
+ assert a.command == "xyzzy"
+
+ def test_execute(self):
+ """Test executing a command Action
+ """
+ pass
+
+ def test_get_contents(self):
+ """Test fetching the contents of a command Action
+ """
+ a = SCons.Action.CommandAction("| $foo | $bar |")
+ c = a.get_contents(foo = 'FFF', bar = 'BBB')
+ assert c == "| FFF | BBB |"
+
+class FunctionActionTestCase(unittest.TestCase):
+
+ def test_init(self):
+ """Test creation of a function Action
+ """
+ def func():
+ pass
+ a = SCons.Action.FunctionAction(func)
+ assert a.function == func
+
+ def test_execute(self):
+ """Test executing a function Action
+ """
+ self.inc = 0
+ def f(s):
+ s.inc = s.inc + 1
+ return 0
+ a = SCons.Action.FunctionAction(f)
+ a.execute(s = self)
+ assert self.inc == 1, self.inc
+
+ def test_get_contents(self):
+ """Test fetching the contents of a function Action
+ """
+ a = SCons.Action.FunctionAction(Func)
+ c = a.get_contents()
+ assert c == "\177\036\000\177\037\000d\000\000S", repr(c)
+
+class ListActionTestCase(unittest.TestCase):
+
+ def test_init(self):
+ """Test creation of a list of subsidiary Actions
+ """
+ def func():
+ pass
+ a = SCons.Action.ListAction(["x", func, ["y", "z"]])
+ assert isinstance(a.list[0], SCons.Action.CommandAction)
+ assert isinstance(a.list[1], SCons.Action.FunctionAction)
+ assert isinstance(a.list[2], SCons.Action.ListAction)
+ assert isinstance(a.list[2].list[0], SCons.Action.CommandAction)
+ assert isinstance(a.list[2].list[1], SCons.Action.CommandAction)
+
+ def test_execute(self):
+ """Test executing a list of subsidiary Actions
+ """
+ self.inc = 0
+ def f(s):
+ s.inc = s.inc + 1
+ return 0
+ a = SCons.Action.ListAction([f, f, f])
+ a.execute(s = self)
+ assert self.inc == 3, self.inc
+
+ def test_get_contents(self):
+ """Test fetching the contents of a list of subsidiary Actions
+ """
+ a = SCons.Action.ListAction(["x", "y", "z"])
+ c = a.get_contents()
+ assert c == "xyz", c
+
+
+if __name__ == "__main__":
+ suite = unittest.TestSuite()
+ suite.addTest(ActionTestCase())
+ suite.addTest(ActionBaseTestCase("test_cmp"))
+ suite.addTest(ActionBaseTestCase("test_subst_dict"))
+ for tclass in [CommandActionTestCase,
+ FunctionActionTestCase,
+ ListActionTestCase]:
+ for func in ["test_init", "test_execute", "test_get_contents"]:
+ suite.addTest(tclass(func))
+ if not unittest.TextTestRunner().run(suite).wasSuccessful():
+ sys.exit(1)
diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py
index 796af0a..59e8834 100644
--- a/src/engine/SCons/Builder.py
+++ b/src/engine/SCons/Builder.py
@@ -31,85 +31,14 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
-import os
import os.path
import string
-import sys
-import types
from Errors import UserError
+import SCons.Action
import SCons.Node.FS
import SCons.Util
-exitvalmap = {
- 2 : 127,
- 13 : 126,
-}
-
-if os.name == 'posix':
-
- def spawn(cmd, args, env):
- pid = os.fork()
- if not pid:
- # Child process.
- exitval = 127
- try:
- os.execvpe(cmd, args, env)
- except OSError, e:
- exitval = exitvalmap[e[0]]
- sys.stderr.write("scons: %s: %s\n" % (cmd, e[1]))
- os._exit(exitval)
- else:
- # Parent process.
- pid, stat = os.waitpid(pid, 0)
- ret = stat >> 8
- return ret
-
-elif os.name == 'nt':
-
- def pathsearch(cmd, env):
- # In order to deal with the fact that 1.5.2 doesn't have
- # os.spawnvpe(), roll our own PATH search.
- if os.path.isabs(cmd):
- if not os.path.exists(cmd):
- exts = env['PATHEXT']
- if not SCons.Util.is_List(exts):
- exts = string.split(exts, os.pathsep)
- for e in exts:
- f = cmd + e
- if os.path.exists(f):
- return f
- else:
- path = env['PATH']
- if not SCons.Util.is_List(path):
- path = string.split(path, os.pathsep)
- exts = env['PATHEXT']
- if not SCons.Util.is_List(exts):
- exts = string.split(exts, os.pathsep)
- pairs = []
- for dir in path:
- for e in exts:
- pairs.append((dir, e))
- for dir, ext in pairs:
- f = os.path.join(dir, cmd)
- if not ext is None:
- f = f + ext
- if os.path.exists(f):
- return f
- return cmd
-
- def spawn(cmd, args, env):
- try:
- try:
- ret = os.spawnvpe(os.P_WAIT, cmd, args, env)
- except AttributeError:
- cmd = pathsearch(cmd, env)
- ret = os.spawnve(os.P_WAIT, cmd, args, env)
- except OSError, e:
- ret = exitvalmap[e[0]]
- sys.stderr.write("scons: %s: %s\n" % (cmd, e[1]))
- return ret
-
def Builder(**kw):
@@ -136,7 +65,7 @@ class BuilderBase:
node_factory = SCons.Node.FS.default_fs.File,
scanner = None):
self.name = name
- self.action = Action(action)
+ self.action = SCons.Action.Action(action)
self.prefix = prefix
self.suffix = suffix
@@ -336,179 +265,3 @@ class CompositeBuilder(BuilderBase):
return reduce(lambda x, y: x + y,
map(lambda b: b.src_suffixes(),
self.builder_dict.values()))
-
-print_actions = 1;
-execute_actions = 1;
-
-def Action(act):
- """A factory for action objects."""
- if callable(act):
- return FunctionAction(act)
- elif SCons.Util.is_String(act):
- return CommandAction(act)
- elif SCons.Util.is_List(act):
- return ListAction(act)
- else:
- return None
-
-class ActionBase:
- """Base class for actions that create output objects.
-
- We currently expect Actions will only be accessible through
- Builder objects, so they don't yet merit their own module."""
- def __cmp__(self, other):
- return cmp(self.__dict__, other.__dict__)
-
- def show(self, string):
- print string
-
- def subst_dict(self, **kw):
- """Create a dictionary for substitution of construction
- variables.
-
- This translates the following special arguments:
-
- env - the construction environment itself,
- the values of which (CC, CCFLAGS, etc.)
- are copied straight into the dictionary
-
- 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 construction
- variable
-
- Any other keyword arguments are copied into the
- dictionary."""
-
- dict = {}
- if kw.has_key('env'):
- dict.update(kw['env'])
- del kw['env']
-
- try:
- cwd = kw['dir']
- except:
- cwd = None
- else:
- del kw['dir']
-
- if kw.has_key('target'):
- t = kw['target']
- del kw['target']
- if not SCons.Util.is_List(t):
- t = [t]
- try:
- cwd = t[0].cwd
- except AttributeError:
- pass
- dict['TARGETS'] = SCons.Util.PathList(map(os.path.normpath, map(str, t)))
- if dict['TARGETS']:
- dict['TARGET'] = dict['TARGETS'][0]
-
- if kw.has_key('source'):
- s = kw['source']
- del kw['source']
- if not SCons.Util.is_List(s):
- s = [s]
- dict['SOURCES'] = SCons.Util.PathList(map(os.path.normpath, map(str, s)))
-
- dict.update(kw)
-
- # Autogenerate necessary construction variables.
- SCons.Util.autogenerate(dict, dir = cwd)
-
- return dict
-
-class CommandAction(ActionBase):
- """Class for command-execution actions."""
- def __init__(self, string):
- self.command = string
-
- def execute(self, **kw):
- import SCons.Util
- dict = apply(self.subst_dict, (), kw)
- cmd_list = SCons.Util.scons_subst_list(self.command, dict, {})
- for cmd_line in cmd_list:
- if len(cmd_line):
- if print_actions:
- self.show(string.join(cmd_line))
- if execute_actions:
- try:
- ENV = kw['env']['ENV']
- except:
- import SCons.Defaults
- ENV = SCons.Defaults.ConstructionEnvironment['ENV']
- ret = spawn(cmd_line[0], cmd_line, ENV)
- if ret:
- return ret
- return 0
-
- def get_contents(self, **kw):
- """Return the signature contents of this action's command line.
-
- For signature purposes, it doesn't matter what targets or
- sources we use, so long as we use the same ones every time
- so the signature stays the same. We supply an array of two
- of each to allow for distinction between TARGET and TARGETS.
- """
- kw['target'] = ['__t1__', '__t2__']
- kw['source'] = ['__s1__', '__s2__']
- dict = apply(self.subst_dict, (), kw)
- return SCons.Util.scons_subst(self.command, dict, {})
-
-class FunctionAction(ActionBase):
- """Class for Python function actions."""
- def __init__(self, function):
- self.function = function
-
- def execute(self, **kw):
- # if print_actions:
- # XXX: WHAT SHOULD WE PRINT HERE?
- if execute_actions:
- if kw.has_key('target'):
- if SCons.Util.is_List(kw['target']):
- kw['target'] = map(str, kw['target'])
- else:
- kw['target'] = str(kw['target'])
- if kw.has_key('source'):
- kw['source'] = map(str, kw['source'])
- return apply(self.function, (), kw)
-
- def get_contents(self, **kw):
- """Return the signature contents of this callable action.
-
- By providing direct access to the code object of the
- function, Python makes this extremely easy. Hooray!
- """
- #XXX DOES NOT ACCOUNT FOR CHANGES IN ENVIRONMENT VARIABLES
- #THE FUNCTION MAY USE
- try:
- # "self.function" is a function.
- code = self.function.func_code.co_code
- except:
- # "self.function" is a callable object.
- code = self.function.__call__.im_func.func_code.co_code
- return str(code)
-
-class ListAction(ActionBase):
- """Class for lists of other actions."""
- def __init__(self, list):
- self.list = map(lambda x: Action(x), list)
-
- def execute(self, **kw):
- for l in self.list:
- r = apply(l.execute, (), kw)
- if r != 0:
- return r
- return 0
-
- def get_contents(self, **kw):
- """Return the signature contents of this action list.
-
- Simple concatenation of the signatures of the elements.
- """
-
- return reduce(lambda x, y: x + str(y.get_contents()), self.list, "")
diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py
index 9b5430f..101e5d6 100644
--- a/src/engine/SCons/Script/__init__.py
+++ b/src/engine/SCons/Script/__init__.py
@@ -450,7 +450,7 @@ def options_init():
help = "Don't build; list files and where defined.")
def opt_n(opt, arg):
- SCons.Builder.execute_actions = None
+ SCons.Action.execute_actions = None
Option(func = opt_n,
short = 'n', long = ['no-exec', 'just-print', 'dry-run', 'recon'],
@@ -481,7 +481,7 @@ def options_init():
help = "Build dependencies in random order.")
def opt_s(opt, arg):
- SCons.Builder.print_actions = None
+ SCons.Action.print_actions = None
Option(func = opt_s,
short = 's', long = ['silent', 'quiet'],