8 # Copyright (c) 2001 Steven Knight
10 # Permission is hereby granted, free of charge, to any person obtaining
11 # a copy of this software and associated documentation files (the
12 # "Software"), to deal in the Software without restriction, including
13 # without limitation the rights to use, copy, modify, merge, publish,
14 # distribute, sublicense, and/or sell copies of the Software, and to
15 # permit persons to whom the Software is furnished to do so, subject to
16 # the following conditions:
18 # The above copyright notice and this permission notice shall be included
19 # in all copies or substantial portions of the Software.
21 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
22 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
23 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
47 if os.name == 'posix':
49 def spawn(cmd, args, env):
55 os.execvpe(cmd, args, env)
57 exitval = exitvalmap[e[0]]
58 sys.stderr.write("scons: %s: %s\n" % (cmd, e[1]))
62 pid, stat = os.waitpid(pid, 0)
68 def pathsearch(cmd, env):
69 # In order to deal with the fact that 1.5.2 doesn't have
70 # os.spawnvpe(), roll our own PATH search.
71 if os.path.isabs(cmd):
72 if not os.path.exists(cmd):
74 if not SCons.Util.is_List(exts):
75 exts = string.split(exts, os.pathsep)
82 if not SCons.Util.is_List(path):
83 path = string.split(path, os.pathsep)
85 if not SCons.Util.is_List(exts):
86 exts = string.split(exts, os.pathsep)
90 pairs.append((dir, e))
91 for dir, ext in pairs:
92 f = os.path.join(dir, cmd)
99 def spawn(cmd, args, env):
102 ret = os.spawnvpe(os.P_WAIT, cmd, args, env)
103 except AttributeError:
104 cmd = pathsearch(cmd, env)
105 ret = os.spawnve(os.P_WAIT, cmd, args, env)
107 ret = exitvalmap[e[0]]
108 sys.stderr.write("scons: %s: %s\n" % (cmd, e[1]))
112 """A factory for action objects."""
113 if isinstance(act, ActionBase):
116 return FunctionAction(act)
117 elif SCons.Util.is_String(act):
118 return CommandAction(act)
119 elif SCons.Util.is_List(act):
120 return ListAction(act)
125 """Base class for actions that create output objects."""
126 def __cmp__(self, other):
127 return cmp(self.__dict__, other.__dict__)
129 def show(self, string):
132 def subst_dict(self, **kw):
133 """Create a dictionary for substitution of construction
136 This translates the following special arguments:
138 env - the construction environment itself,
139 the values of which (CC, CCFLAGS, etc.)
140 are copied straight into the dictionary
142 target - the target (object or array of objects),
143 used to generate the TARGET and TARGETS
144 construction variables
146 source - the source (object or array of objects),
147 used to generate the SOURCES construction
150 Any other keyword arguments are copied into the
154 if kw.has_key('env'):
155 dict.update(kw['env'])
165 if kw.has_key('target'):
168 if not SCons.Util.is_List(t):
172 except AttributeError:
174 dict['TARGETS'] = SCons.Util.PathList(map(os.path.normpath, map(str, t)))
176 dict['TARGET'] = dict['TARGETS'][0]
178 if kw.has_key('source'):
181 if not SCons.Util.is_List(s):
183 dict['SOURCES'] = SCons.Util.PathList(map(os.path.normpath, map(str, s)))
187 # Autogenerate necessary construction variables.
188 SCons.Util.autogenerate(dict, dir = cwd)
192 class CommandAction(ActionBase):
193 """Class for command-execution actions."""
194 def __init__(self, string):
195 self.command = string
197 def execute(self, **kw):
199 dict = apply(self.subst_dict, (), kw)
200 cmd_list = SCons.Util.scons_subst_list(self.command, dict, {})
201 for cmd_line in cmd_list:
204 self.show(string.join(cmd_line))
207 ENV = kw['env']['ENV']
209 import SCons.Defaults
210 ENV = SCons.Defaults.ConstructionEnvironment['ENV']
211 ret = spawn(cmd_line[0], cmd_line, ENV)
216 def get_contents(self, **kw):
217 """Return the signature contents of this action's command line.
219 For signature purposes, it doesn't matter what targets or
220 sources we use, so long as we use the same ones every time
221 so the signature stays the same. We supply an array of two
222 of each to allow for distinction between TARGET and TARGETS.
224 kw['target'] = ['__t1__', '__t2__']
225 kw['source'] = ['__s1__', '__s2__']
226 dict = apply(self.subst_dict, (), kw)
227 return SCons.Util.scons_subst(self.command, dict, {})
229 class FunctionAction(ActionBase):
230 """Class for Python function actions."""
231 def __init__(self, function):
232 self.function = function
234 def execute(self, **kw):
236 # XXX: WHAT SHOULD WE PRINT HERE?
238 if kw.has_key('target'):
239 if SCons.Util.is_List(kw['target']):
240 kw['target'] = map(str, kw['target'])
242 kw['target'] = str(kw['target'])
243 if kw.has_key('source'):
244 kw['source'] = map(str, kw['source'])
245 return apply(self.function, (), kw)
247 def get_contents(self, **kw):
248 """Return the signature contents of this callable action.
250 By providing direct access to the code object of the
251 function, Python makes this extremely easy. Hooray!
253 #XXX DOES NOT ACCOUNT FOR CHANGES IN ENVIRONMENT VARIABLES
254 #THE FUNCTION MAY USE
256 # "self.function" is a function.
257 code = self.function.func_code.co_code
259 # "self.function" is a callable object.
260 code = self.function.__call__.im_func.func_code.co_code
263 class ListAction(ActionBase):
264 """Class for lists of other actions."""
265 def __init__(self, list):
266 self.list = map(lambda x: Action(x), list)
268 def execute(self, **kw):
270 r = apply(l.execute, (), kw)
275 def get_contents(self, **kw):
276 """Return the signature contents of this action list.
278 Simple concatenation of the signatures of the elements.
281 return reduce(lambda x, y: x + str(y.get_contents()), self.list, "")