3 This encapsulates information about executing any sort of action that
4 can build one or more target Nodes (typically files) from one or more
5 source Nodes (also typically files) given a specific Environment.
7 The base class here is ActionBase. The base class supplies just a few
8 OO utility methods and some generic methods for displaying information
9 about an Action in response to the various commands that control printing.
11 A second-level base class is _ActionAction. This extends ActionBase
12 by providing the methods that can be used to show and perform an
13 action. True Action objects will subclass _ActionAction; Action
14 factory class objects will subclass ActionBase.
16 The heavy lifting is handled by subclasses for the different types of
17 actions we might execute:
20 CommandGeneratorAction
24 The subclasses supply the following public interface methods used by
28 THE public interface, "calling" an Action object executes the
29 command or Python function. This also takes care of printing
30 a pre-substitution command for debugging purposes.
33 Fetches the "contents" of an Action for signature calculation
34 plus the varlist. This is what gets MD5 checksummed to decide
35 if a target needs to be rebuilt because its action changed.
38 Returns a string representation of the Action *without*
39 command substitution, but allows a CommandGeneratorAction to
40 generate the right action based on the specified target,
41 source and env. This is used by the Signature subsystem
42 (through the Executor) to obtain an (imprecise) representation
43 of the Action operation for informative purposes.
46 Subclasses also supply the following methods for internal use within
50 Returns a string approximation of the Action; no variable
51 substitution is performed.
54 The internal method that really, truly, actually handles the
55 execution of a command or Python function. This is used so
56 that the __call__() methods can take care of displaying any
57 pre-substitution representations, and *then* execute an action
58 without worrying about the specific Actions involved.
61 Fetches the "contents" of a subclass for signature calculation.
62 The varlist is added to this to produce the Action's contents.
65 Returns a substituted string representation of the Action.
66 This is used by the _ActionAction.show() command to display the
67 command/function that will be executed to generate the target(s).
69 There is a related independent ActionCaller class that looks like a
70 regular Action, and which serves as a wrapper for arbitrary functions
71 that we want to let the user specify the arguments to now, but actually
72 execute later (when an out-of-date check determines that it's needed to
73 be executed, for example). Objects of this class are returned by an
74 ActionFactory class that provides a __call__() method as a convenient
75 way for wrapping up the functions.
79 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation
81 # Permission is hereby granted, free of charge, to any person obtaining
82 # a copy of this software and associated documentation files (the
83 # "Software"), to deal in the Software without restriction, including
84 # without limitation the rights to use, copy, modify, merge, publish,
85 # distribute, sublicense, and/or sell copies of the Software, and to
86 # permit persons to whom the Software is furnished to do so, subject to
87 # the following conditions:
89 # The above copyright notice and this permission notice shall be included
90 # in all copies or substantial portions of the Software.
92 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
93 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
94 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
95 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
96 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
97 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
98 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
100 __revision__ = "src/engine/SCons/Action.py 3842 2008/12/20 22:59:52 scons"
109 from SCons.Debug import logInstanceCreation
111 import SCons.Executor
115 # we use these a lot, so try to optimize them
116 is_String = SCons.Util.is_String
117 is_List = SCons.Util.is_List
124 print_actions_presub = 0
129 except AttributeError:
132 def default_exitstatfunc(s):
136 SET_LINENO = dis.SET_LINENO
137 HAVE_ARGUMENT = dis.HAVE_ARGUMENT
138 except AttributeError:
139 remove_set_lineno_codes = lambda x: x
141 def remove_set_lineno_codes(code):
148 if op >= HAVE_ARGUMENT:
150 result.append(code[i:i+3])
155 return string.join(result, '')
158 def _callable_contents(obj):
159 """Return the signature contents of a callable Python object.
162 # Test if obj is a method.
163 return _function_contents(obj.im_func)
165 except AttributeError:
167 # Test if obj is a callable object.
168 return _function_contents(obj.__call__.im_func)
170 except AttributeError:
172 # Test if obj is a code object.
173 return _code_contents(obj)
175 except AttributeError:
176 # Test if obj is a function object.
177 return _function_contents(obj)
180 def _object_contents(obj):
181 """Return the signature contents of any Python object.
183 We have to handle the case where object contains a code object
184 since it can be pickled directly.
187 # Test if obj is a method.
188 return _function_contents(obj.im_func)
190 except AttributeError:
192 # Test if obj is a callable object.
193 return _function_contents(obj.__call__.im_func)
195 except AttributeError:
197 # Test if obj is a code object.
198 return _code_contents(obj)
200 except AttributeError:
202 # Test if obj is a function object.
203 return _function_contents(obj)
205 except AttributeError:
206 # Should be a pickable Python object.
208 return cPickle.dumps(obj)
209 except (cPickle.PicklingError, TypeError):
210 # This is weird, but it seems that nested classes
211 # are unpickable. The Python docs say it should
212 # always be a PicklingError, but some Python
213 # versions seem to return TypeError. Just do
218 def _code_contents(code):
219 """Return the signature contents of a code object.
221 By providing direct access to the code object of the
222 function, Python makes this extremely easy. Hooray!
224 Unfortunately, older versions of Python include line
225 number indications in the compiled byte code. Boo!
226 So we remove the line number byte codes to prevent
227 recompilations from moving a Python function.
232 # The code contents depends on the number of local variables
233 # but not their actual names.
234 contents.append("%s,%s" % (code.co_argcount, len(code.co_varnames)))
236 contents.append(",%s,%s" % (len(code.co_cellvars), len(code.co_freevars)))
237 except AttributeError:
238 # Older versions of Python do not support closures.
239 contents.append(",0,0")
241 # The code contents depends on any constants accessed by the
242 # function. Note that we have to call _object_contents on each
243 # constants because the code object of nested functions can
244 # show-up among the constants.
246 # Note that we also always ignore the first entry of co_consts
247 # which contains the function doc string. We assume that the
248 # function does not access its doc string.
249 contents.append(',(' + string.join(map(_object_contents,code.co_consts[1:]),',') + ')')
251 # The code contents depends on the variable names used to
252 # accessed global variable, as changing the variable name changes
253 # the variable actually accessed and therefore changes the
255 contents.append(',(' + string.join(map(_object_contents,code.co_names),',') + ')')
258 # The code contents depends on its actual code!!!
259 contents.append(',(' + str(remove_set_lineno_codes(code.co_code)) + ')')
261 return string.join(contents, '')
264 def _function_contents(func):
265 """Return the signature contents of a function."""
267 contents = [_code_contents(func.func_code)]
269 # The function contents depends on the value of defaults arguments
270 if func.func_defaults:
271 contents.append(',(' + string.join(map(_object_contents,func.func_defaults),',') + ')')
273 contents.append(',()')
275 # The function contents depends on the closure captured cell values.
277 closure = func.func_closure or []
278 except AttributeError:
279 # Older versions of Python do not support closures.
282 #xxx = [_object_contents(x.cell_contents) for x in closure]
284 xxx = map(lambda x: _object_contents(x.cell_contents), closure)
285 except AttributeError:
287 contents.append(',(' + string.join(xxx, ',') + ')')
289 return string.join(contents, '')
292 def _actionAppend(act1, act2):
293 # This function knows how to slap two actions together.
294 # Mainly, it handles ListActions by concatenating into
295 # a single ListAction.
298 if a1 is None or a2 is None:
299 raise TypeError, "Cannot append %s to %s" % (type(act1), type(act2))
300 if isinstance(a1, ListAction):
301 if isinstance(a2, ListAction):
302 return ListAction(a1.list + a2.list)
304 return ListAction(a1.list + [ a2 ])
306 if isinstance(a2, ListAction):
307 return ListAction([ a1 ] + a2.list)
309 return ListAction([ a1, a2 ])
311 def _do_create_keywords(args, kw):
312 """This converts any arguments after the action argument into
313 their equivalent keywords and adds them to the kw argument.
315 v = kw.get('varlist', ())
316 # prevent varlist="FOO" from being interpreted as ['F', 'O', 'O']
317 if is_String(v): v = (v,)
318 kw['varlist'] = tuple(v)
320 # turn positional args into equivalent keywords
322 if cmdstrfunc is None or is_String(cmdstrfunc):
323 kw['cmdstr'] = cmdstrfunc
324 elif callable(cmdstrfunc):
325 kw['strfunction'] = cmdstrfunc
327 raise SCons.Errors.UserError(
328 'Invalid command display variable type. '
329 'You must either pass a string or a callback which '
330 'accepts (target, source, env) as parameters.')
332 kw['varlist'] = args[1:] + kw['varlist']
333 if kw.get('strfunction', _null) is not _null \
334 and kw.get('cmdstr', _null) is not _null:
335 raise SCons.Errors.UserError(
336 'Cannot have both strfunction and cmdstr args to Action()')
338 def _do_create_action(act, kw):
339 """This is the actual "implementation" for the
340 Action factory method, below. This handles the
341 fact that passing lists to Action() itself has
342 different semantics than passing lists as elements
345 The former will create a ListAction, the latter
346 will create a CommandAction by converting the inner
347 list elements to strings."""
349 if isinstance(act, ActionBase):
353 #TODO(1.5) return CommandAction(act, **kw)
354 return apply(CommandAction, (act,), kw)
358 gen = kw['generator']
363 action_type = CommandGeneratorAction
365 action_type = FunctionAction
366 return action_type(act, kw)
369 var=SCons.Util.get_environment_var(act)
371 # This looks like a string that is purely an Environment
372 # variable reference, like "$FOO" or "${FOO}". We do
373 # something special here...we lazily evaluate the contents
374 # of that Environment variable, so a user could put something
375 # like a function or a CommandGenerator in that variable
376 # instead of a string.
377 return LazyAction(var, kw)
378 commands = string.split(str(act), '\n')
379 if len(commands) == 1:
380 #TODO(1.5) return CommandAction(commands[0], **kw)
381 return apply(CommandAction, (commands[0],), kw)
382 # The list of string commands may include a LazyAction, so we
383 # reprocess them via _do_create_list_action.
384 return _do_create_list_action(commands, kw)
387 def _do_create_list_action(act, kw):
388 """A factory for list actions. Convert the input list into Actions
389 and then wrap them in a ListAction."""
392 aa = _do_create_action(a, kw)
393 if aa is not None: acts.append(aa)
399 return ListAction(acts)
401 def Action(act, *args, **kw):
402 """A factory for action objects."""
403 # Really simple: the _do_create_* routines do the heavy lifting.
404 _do_create_keywords(args, kw)
406 return _do_create_list_action(act, kw)
407 return _do_create_action(act, kw)
410 """Base class for all types of action objects that can be held by
411 other objects (Builders, Executors, etc.) This provides the
412 common methods for manipulating and combining those actions."""
414 def __cmp__(self, other):
415 return cmp(self.__dict__, other)
417 def genstring(self, target, source, env):
420 def get_contents(self, target, source, env):
421 result = [ self.get_presig(target, source, env) ]
422 # This should never happen, as the Action() factory should wrap
423 # the varlist, but just in case an action is created directly,
424 # we duplicate this check here.
426 if is_String(vl): vl = (vl,)
428 result.append(env.subst('${'+v+'}'))
429 return string.join(result, '')
431 def __add__(self, other):
432 return _actionAppend(self, other)
434 def __radd__(self, other):
435 return _actionAppend(other, self)
437 def presub_lines(self, env):
438 # CommandGeneratorAction needs a real environment
439 # in order to return the proper string here, since
440 # it may call LazyAction, which looks up a key
441 # in that env. So we temporarily remember the env here,
442 # and CommandGeneratorAction will use this env
443 # when it calls its _generate method.
444 self.presub_env = env
445 lines = string.split(str(self), '\n')
446 self.presub_env = None # don't need this any more
449 def get_executor(self, env, overrides, tlist, slist, executor_kw):
450 """Return the Executor for this Action."""
451 return SCons.Executor.Executor(self, env, overrides,
452 tlist, slist, executor_kw)
454 class _ActionAction(ActionBase):
455 """Base class for actions that create output objects."""
456 def __init__(self, cmdstr=_null, strfunction=_null, varlist=(),
457 presub=_null, chdir=None, exitstatfunc=None,
460 if strfunction is not _null:
461 if strfunction is None:
464 self.strfunction = strfunction
465 self.varlist = varlist
469 exitstatfunc = default_exitstatfunc
470 self.exitstatfunc = exitstatfunc
472 def print_cmd_line(self, s, target, source, env):
473 sys.stdout.write(s + "\n")
475 def __call__(self, target, source, env,
481 if not is_List(target):
483 if not is_List(source):
489 presub = print_actions_presub
490 if exitstatfunc is _null: exitstatfunc = self.exitstatfunc
491 if show is _null: show = print_actions
492 if execute is _null: execute = execute_actions
493 if chdir is _null: chdir = self.chdir
496 save_cwd = os.getcwd()
498 chdir = str(chdir.abspath)
499 except AttributeError:
500 if not is_String(chdir):
501 chdir = str(target[0].dir)
503 t = string.join(map(str, target), ' and ')
504 l = string.join(self.presub_lines(env), '\n ')
505 out = "Building %s with action:\n %s\n" % (t, l)
506 sys.stdout.write(out)
508 if show and self.strfunction:
509 cmd = self.strfunction(target, source, env)
512 cmd = ('os.chdir(%s)\n' % repr(chdir)) + cmd
515 except AttributeError:
516 print_func = self.print_cmd_line
518 print_func = get('PRINT_CMD_LINE_FUNC')
520 print_func = self.print_cmd_line
521 print_func(cmd, target, source, env)
527 stat = self.execute(target, source, env)
528 if isinstance(stat, SCons.Errors.BuildError):
529 s = exitstatfunc(stat.status)
535 stat = exitstatfunc(stat)
540 print_func('os.chdir(%s)' % repr(save_cwd), target, source, env)
545 def _string_from_cmd_list(cmd_list):
546 """Takes a list of command line arguments and returns a pretty
547 representation for printing."""
549 for arg in map(str, cmd_list):
550 if ' ' in arg or '\t' in arg:
551 arg = '"' + arg + '"'
553 return string.join(cl)
555 # A fiddlin' little function that has an 'import SCons.Environment' which
556 # can't be moved to the top level without creating an import loop. Since
557 # this import creates a local variable named 'SCons', it blocks access to
558 # the global variable, so we move it here to prevent complaints about local
559 # variables being used uninitialized.
561 def get_default_ENV(env):
567 import SCons.Environment
568 # This is a hideously expensive way to get a default shell
569 # environment. What it really should do is run the platform
570 # setup to get the default ENV. Fortunately, it's incredibly
571 # rare for an Environment not to have a shell environment, so
572 # we're not going to worry about it overmuch.
573 default_ENV = SCons.Environment.Environment()['ENV']
576 # This function is still in draft mode. We're going to need something like
577 # it in the long run as more and more places use subprocess, but I'm sure
578 # it'll have to be tweaked to get the full desired functionality.
579 # one special arg (so far?), 'error', to tell what to do with exceptions.
580 def _subproc(env, cmd, error = 'ignore', **kw):
581 """Do common setup for a subprocess.Popen() call"""
582 # allow std{in,out,err} to be "'devnull'"
584 if is_String(io) and io == 'devnull':
585 kw['stdin'] = open(os.devnull)
586 io = kw.get('stdout')
587 if is_String(io) and io == 'devnull':
588 kw['stdout'] = open(os.devnull, 'w')
589 io = kw.get('stderr')
590 if is_String(io) and io == 'devnull':
591 kw['stderr'] = open(os.devnull, 'w')
593 # Figure out what shell environment to use
594 ENV = kw.get('env', None)
595 if ENV is None: ENV = get_default_ENV(env)
597 # Ensure that the ENV values are all strings:
599 for key, value in ENV.items():
601 # If the value is a list, then we assume it is a path list,
602 # because that's a pretty common list-like value to stick
603 # in an environment variable:
604 value = SCons.Util.flatten_sequence(value)
605 new_env[key] = string.join(map(str, value), os.pathsep)
607 # It's either a string or something else. If it's a string,
608 # we still want to call str() because it might be a *Unicode*
609 # string, which makes subprocess.Popen() gag. If it isn't a
610 # string or a list, then we just coerce it to a string, which
611 # is the proper way to handle Dir and File instances and will
612 # produce something reasonable for just about everything else:
613 new_env[key] = str(value)
617 #FUTURE return subprocess.Popen(cmd, **kw)
618 return apply(subprocess.Popen, (cmd,), kw)
619 except EnvironmentError, e:
620 if error == 'raise': raise
621 # return a dummy Popen instance that only returns error
623 def __init__(self, e): self.exception = e
624 def communicate(self): return ('','')
625 def wait(self): return -self.exception.errno
628 def read(self): return ''
629 def readline(self): return ''
630 stdout = stderr = f()
633 class CommandAction(_ActionAction):
634 """Class for command-execution actions."""
635 def __init__(self, cmd, **kw):
636 # Cmd can actually be a list or a single item; if it's a
637 # single item it should be the command string to execute; if a
638 # list then it should be the words of the command string to
639 # execute. Only a single command should be executed by this
640 # object; lists of commands should be handled by embedding
641 # these objects in a ListAction object (which the Action()
642 # factory above does). cmd will be passed to
643 # Environment.subst_list() for substituting environment
645 if __debug__: logInstanceCreation(self, 'Action.CommandAction')
647 #TODO(1.5) _ActionAction.__init__(self, **kw)
648 apply(_ActionAction.__init__, (self,), kw)
650 if filter(is_List, cmd):
651 raise TypeError, "CommandAction should be given only " \
656 if is_List(self.cmd_list):
657 return string.join(map(str, self.cmd_list), ' ')
658 return str(self.cmd_list)
660 def process(self, target, source, env):
661 result = env.subst_list(self.cmd_list, 0, target, source)
665 try: c = result[0][0][0]
666 except IndexError: c = None
667 if c == '@': silent = 1
668 elif c == '-': ignore = 1
670 result[0][0] = result[0][0][1:]
673 result[0] = result[0][1:]
676 return result, ignore, silent
678 def strfunction(self, target, source, env):
679 if self.cmdstr is None:
681 if self.cmdstr is not _null:
682 from SCons.Subst import SUBST_RAW
683 c = env.subst(self.cmdstr, SUBST_RAW, target, source)
686 cmd_list, ignore, silent = self.process(target, source, env)
689 return _string_from_cmd_list(cmd_list[0])
691 def execute(self, target, source, env):
692 """Execute a command action.
694 This will handle lists of commands as well as individual commands,
695 because construction variable substitution may turn a single
696 "command" into a list. This means that this class can actually
697 handle lists of commands, even though that's not how we use it
700 escape_list = SCons.Subst.escape_list
701 flatten_sequence = SCons.Util.flatten_sequence
706 raise SCons.Errors.UserError('Missing SHELL construction variable.')
711 raise SCons.Errors.UserError('Missing SPAWN construction variable.')
714 spawn = env.subst(spawn, raw=1, conv=lambda x: x)
716 escape = env.get('ESCAPE', lambda x: x)
718 ENV = get_default_ENV(env)
720 # Ensure that the ENV values are all strings:
721 for key, value in ENV.items():
722 if not is_String(value):
724 # If the value is a list, then we assume it is a
725 # path list, because that's a pretty common list-like
726 # value to stick in an environment variable:
727 value = flatten_sequence(value)
728 ENV[key] = string.join(map(str, value), os.pathsep)
730 # If it isn't a string or a list, then we just coerce
731 # it to a string, which is the proper way to handle
732 # Dir and File instances and will produce something
733 # reasonable for just about everything else:
734 ENV[key] = str(value)
736 cmd_list, ignore, silent = self.process(target, map(rfile, source), env)
738 # Use len() to filter out any "command" that's zero-length.
739 for cmd_line in filter(len, cmd_list):
740 # Escape the command line for the interpreter we are using.
741 cmd_line = escape_list(cmd_line, escape)
742 result = spawn(shell, escape, cmd_line[0], cmd_line, ENV)
743 if not ignore and result:
744 msg = "Error %s" % result
745 return SCons.Errors.BuildError(errstr=msg,
751 def get_presig(self, target, source, env):
752 """Return the signature contents of this action's command line.
754 This strips $(-$) and everything in between the string,
755 since those parts don't affect signatures.
757 from SCons.Subst import SUBST_SIG
760 cmd = string.join(map(str, cmd))
763 return env.subst_target_source(cmd, SUBST_SIG, target, source)
765 def get_implicit_deps(self, target, source, env):
766 icd = env.get('IMPLICIT_COMMAND_DEPENDENCIES', True)
767 if is_String(icd) and icd[:1] == '$':
769 if not icd or icd in ('0', 'None'):
771 from SCons.Subst import SUBST_SIG
772 cmd_list = env.subst_list(self.cmd_list, SUBST_SIG, target, source)
774 for cmd_line in cmd_list:
776 d = env.WhereIs(str(cmd_line[0]))
778 res.append(env.fs.File(d))
781 class CommandGeneratorAction(ActionBase):
782 """Class for command-generator actions."""
783 def __init__(self, generator, kw):
784 if __debug__: logInstanceCreation(self, 'Action.CommandGeneratorAction')
785 self.generator = generator
787 self.varlist = kw.get('varlist', ())
789 def _generate(self, target, source, env, for_signature):
790 # ensure that target is a list, to make it easier to write
791 # generator functions:
792 if not is_List(target):
795 ret = self.generator(target=target, source=source, env=env, for_signature=for_signature)
796 #TODO(1.5) gen_cmd = Action(ret, **self.gen_kw)
797 gen_cmd = apply(Action, (ret,), self.gen_kw)
799 raise SCons.Errors.UserError("Object returned from command generator: %s cannot be used to create an Action." % repr(ret))
804 env = self.presub_env
805 except AttributeError:
808 env = SCons.Defaults.DefaultEnvironment()
809 act = self._generate([], [], env, 1)
812 def genstring(self, target, source, env):
813 return self._generate(target, source, env, 1).genstring(target, source, env)
815 def __call__(self, target, source, env, exitstatfunc=_null, presub=_null,
816 show=_null, execute=_null, chdir=_null):
817 act = self._generate(target, source, env, 0)
818 return act(target, source, env, exitstatfunc, presub,
819 show, execute, chdir)
821 def get_presig(self, target, source, env):
822 """Return the signature contents of this action's command line.
824 This strips $(-$) and everything in between the string,
825 since those parts don't affect signatures.
827 return self._generate(target, source, env, 1).get_presig(target, source, env)
829 def get_implicit_deps(self, target, source, env):
830 return self._generate(target, source, env, 1).get_implicit_deps(target, source, env)
834 # A LazyAction is a kind of hybrid generator and command action for
835 # strings of the form "$VAR". These strings normally expand to other
836 # strings (think "$CCCOM" to "$CC -c -o $TARGET $SOURCE"), but we also
837 # want to be able to replace them with functions in the construction
838 # environment. Consequently, we want lazy evaluation and creation of
839 # an Action in the case of the function, but that's overkill in the more
840 # normal case of expansion to other strings.
842 # So we do this with a subclass that's both a generator *and*
843 # a command action. The overridden methods all do a quick check
844 # of the construction variable, and if it's a string we just call
845 # the corresponding CommandAction method to do the heavy lifting.
846 # If not, then we call the same-named CommandGeneratorAction method.
847 # The CommandGeneratorAction methods work by using the overridden
848 # _generate() method, that is, our own way of handling "generation" of
849 # an action based on what's in the construction variable.
851 class LazyAction(CommandGeneratorAction, CommandAction):
853 def __init__(self, var, kw):
854 if __debug__: logInstanceCreation(self, 'Action.LazyAction')
855 #FUTURE CommandAction.__init__(self, '${'+var+'}', **kw)
856 apply(CommandAction.__init__, (self, '${'+var+'}'), kw)
857 self.var = SCons.Util.to_String(var)
860 def get_parent_class(self, env):
861 c = env.get(self.var)
862 if is_String(c) and not '\n' in c:
864 return CommandGeneratorAction
866 def _generate_cache(self, env):
867 c = env.get(self.var, '')
868 #TODO(1.5) gen_cmd = Action(c, **self.gen_kw)
869 gen_cmd = apply(Action, (c,), self.gen_kw)
871 raise SCons.Errors.UserError("$%s value %s cannot be used to create an Action." % (self.var, repr(c)))
874 def _generate(self, target, source, env, for_signature):
875 return self._generate_cache(env)
877 def __call__(self, target, source, env, *args, **kw):
878 args = (self, target, source, env) + args
879 c = self.get_parent_class(env)
880 #TODO(1.5) return c.__call__(*args, **kw)
881 return apply(c.__call__, args, kw)
883 def get_presig(self, target, source, env):
884 c = self.get_parent_class(env)
885 return c.get_presig(self, target, source, env)
889 class FunctionAction(_ActionAction):
890 """Class for Python function actions."""
892 def __init__(self, execfunction, kw):
893 if __debug__: logInstanceCreation(self, 'Action.FunctionAction')
895 self.execfunction = execfunction
897 self.funccontents = _callable_contents(execfunction)
898 except AttributeError:
900 # See if execfunction will do the heavy lifting for us.
901 self.gc = execfunction.get_contents
902 except AttributeError:
903 # This is weird, just do the best we can.
904 self.funccontents = _object_contents(execfunction)
906 #TODO(1.5) _ActionAction.__init__(self, **kw)
907 apply(_ActionAction.__init__, (self,), kw)
909 def function_name(self):
911 return self.execfunction.__name__
912 except AttributeError:
914 return self.execfunction.__class__.__name__
915 except AttributeError:
916 return "unknown_python_function"
918 def strfunction(self, target, source, env):
919 if self.cmdstr is None:
921 if self.cmdstr is not _null:
922 from SCons.Subst import SUBST_RAW
923 c = env.subst(self.cmdstr, SUBST_RAW, target, source)
929 str_for_display = s.str_for_display
930 except AttributeError:
933 s = str_for_display()
935 return '[' + string.join(map(quote, a), ", ") + ']'
937 strfunc = self.execfunction.strfunction
938 except AttributeError:
943 if callable(strfunc):
944 return strfunc(target, source, env)
945 name = self.function_name()
948 return "%s(%s, %s)" % (name, tstr, sstr)
951 name = self.function_name()
952 if name == 'ActionCaller':
953 return str(self.execfunction)
954 return "%s(target, source, env)" % name
956 def execute(self, target, source, env):
957 exc_info = (None,None,None)
959 rsources = map(rfile, source)
961 result = self.execfunction(target=target, source=rsources, env=env)
962 except KeyboardInterrupt, e:
964 except SystemExit, e:
968 exc_info = sys.exc_info()
971 result = SCons.Errors.convert_to_BuildError(result, exc_info)
974 result.command=self.strfunction(target, source, env)
976 # FIXME: This maintains backward compatibility with respect to
977 # which type of exceptions were returned by raising an
978 # exception and which ones were returned by value. It would
979 # probably be best to always return them by value here, but
980 # some codes do not check the return value of Actions and I do
981 # not have the time to modify them at this point.
983 not isinstance(exc_info[1],EnvironmentError)):
988 # Break the cycle between the traceback object and this
989 # function stack frame. See the sys.exc_info() doc info for
990 # more information about this issue.
994 def get_presig(self, target, source, env):
995 """Return the signature contents of this callable action."""
997 return self.gc(target, source, env)
998 except AttributeError:
999 return self.funccontents
1001 def get_implicit_deps(self, target, source, env):
1004 class ListAction(ActionBase):
1005 """Class for lists of other actions."""
1006 def __init__(self, list):
1007 if __debug__: logInstanceCreation(self, 'Action.ListAction')
1008 def list_of_actions(x):
1009 if isinstance(x, ActionBase):
1012 self.list = map(list_of_actions, list)
1013 # our children will have had any varlist
1014 # applied; we don't need to do it again
1017 def genstring(self, target, source, env):
1018 return string.join(map(lambda a, t=target, s=source, e=env:
1019 a.genstring(t, s, e),
1024 return string.join(map(str, self.list), '\n')
1026 def presub_lines(self, env):
1027 return SCons.Util.flatten_sequence(
1028 map(lambda a, env=env: a.presub_lines(env), self.list))
1030 def get_presig(self, target, source, env):
1031 """Return the signature contents of this action list.
1033 Simple concatenation of the signatures of the elements.
1035 return string.join(map(lambda x, t=target, s=source, e=env:
1036 x.get_contents(t, s, e),
1040 def __call__(self, target, source, env, exitstatfunc=_null, presub=_null,
1041 show=_null, execute=_null, chdir=_null):
1042 for act in self.list:
1043 stat = act(target, source, env, exitstatfunc, presub,
1044 show, execute, chdir)
1049 def get_implicit_deps(self, target, source, env):
1051 for act in self.list:
1052 result.extend(act.get_implicit_deps(target, source, env))
1056 """A class for delaying calling an Action function with specific
1057 (positional and keyword) arguments until the Action is actually
1060 This class looks to the rest of the world like a normal Action object,
1061 but what it's really doing is hanging on to the arguments until we
1062 have a target, source and env to use for the expansion.
1064 def __init__(self, parent, args, kw):
1065 self.parent = parent
1069 def get_contents(self, target, source, env):
1070 actfunc = self.parent.actfunc
1072 # "self.actfunc" is a function.
1073 contents = str(actfunc.func_code.co_code)
1074 except AttributeError:
1075 # "self.actfunc" is a callable object.
1077 contents = str(actfunc.__call__.im_func.func_code.co_code)
1078 except AttributeError:
1079 # No __call__() method, so it might be a builtin
1080 # or something like that. Do the best we can.
1081 contents = str(actfunc)
1082 contents = remove_set_lineno_codes(contents)
1085 def subst(self, s, target, source, env):
1086 # If s is a list, recursively apply subst()
1087 # to every element in the list
1091 result.append(self.subst(elem, target, source, env))
1092 return self.parent.convert(result)
1094 # Special-case hack: Let a custom function wrapped in an
1095 # ActionCaller get at the environment through which the action
1096 # was called by using this hard-coded value as a special return.
1100 return env.subst(s, 1, target, source)
1101 return self.parent.convert(s)
1103 def subst_args(self, target, source, env):
1104 return map(lambda x, self=self, t=target, s=source, e=env:
1105 self.subst(x, t, s, e),
1108 def subst_kw(self, target, source, env):
1110 for key in self.kw.keys():
1111 kw[key] = self.subst(self.kw[key], target, source, env)
1114 def __call__(self, target, source, env):
1115 args = self.subst_args(target, source, env)
1116 kw = self.subst_kw(target, source, env)
1117 #TODO(1.5) return self.parent.actfunc(*args, **kw)
1118 return apply(self.parent.actfunc, args, kw)
1120 def strfunction(self, target, source, env):
1121 args = self.subst_args(target, source, env)
1122 kw = self.subst_kw(target, source, env)
1123 #TODO(1.5) return self.parent.strfunc(*args, **kw)
1124 return apply(self.parent.strfunc, args, kw)
1127 #TODO(1.5) return self.parent.strfunc(*self.args, **self.kw)
1128 return apply(self.parent.strfunc, self.args, self.kw)
1130 class ActionFactory:
1131 """A factory class that will wrap up an arbitrary function
1132 as an SCons-executable Action object.
1134 The real heavy lifting here is done by the ActionCaller class.
1135 We just collect the (positional and keyword) arguments that we're
1136 called with and give them to the ActionCaller object we create,
1137 so it can hang onto them until it needs them.
1139 def __init__(self, actfunc, strfunc, convert=lambda x: x):
1140 self.actfunc = actfunc
1141 self.strfunc = strfunc
1142 self.convert = convert
1144 def __call__(self, *args, **kw):
1145 ac = ActionCaller(self, args, kw)
1146 action = Action(ac, strfunction=ac.strfunction)