diff options
-rw-r--r-- | doc/man/scons.1 | 69 | ||||
-rw-r--r-- | src/CHANGES.txt | 2 | ||||
-rw-r--r-- | src/engine/MANIFEST.in | 1 | ||||
-rw-r--r-- | src/engine/SCons/Action.py | 281 | ||||
-rw-r--r-- | src/engine/SCons/ActionTests.py | 190 | ||||
-rw-r--r-- | src/engine/SCons/Builder.py | 251 | ||||
-rw-r--r-- | src/engine/SCons/Script/__init__.py | 4 |
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'], |