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 defaultSpawn(cmd, args, env):
54 args = [ 'sh', '-c' ] + \
55 [ string.join(map(lambda x: string.replace(str(x),
60 os.execvpe('sh', args, env)
62 exitval = exitvalmap[e[0]]
63 sys.stderr.write("scons: %s: %s\n" % (cmd, e[1]))
67 pid, stat = os.waitpid(pid, 0)
73 def pathsearch(cmd, env):
74 # In order to deal with the fact that 1.5.2 doesn't have
75 # os.spawnvpe(), roll our own PATH search.
76 if os.path.isabs(cmd):
77 if not os.path.exists(cmd):
79 if not SCons.Util.is_List(exts):
80 exts = string.split(exts, os.pathsep)
89 if not SCons.Util.is_List(path):
90 path = string.split(path, os.pathsep)
92 if not SCons.Util.is_List(exts):
93 exts = string.split(exts, os.pathsep)
97 pairs.append((dir, e))
98 for dir, ext in pairs:
99 f = os.path.join(dir, cmd)
102 if os.path.exists(f):
106 # Attempt to find cmd.exe (for WinNT/2k/XP) or
107 # command.com for Win9x
110 # First see if we can look in the registry...
111 if SCons.Util.can_read_reg:
113 # Look for Windows NT system root
114 k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
115 'Software\\Microsoft\\Windows NT\\CurrentVersion')
116 val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot')
117 cmd_interp = os.path.join(val, 'System32\\cmd.exe')
118 except SCons.Util.RegError:
120 # Okay, try the Windows 9x system root
121 k=SCons.Util.RegOpenKeyEx(SCons.Util.hkey_mod.HKEY_LOCAL_MACHINE,
122 'Software\\Microsoft\\Windows\\CurrentVersion')
123 val, tok = SCons.Util.RegQueryValueEx(k, 'SystemRoot')
124 cmd_interp = os.path.join(val, 'command.com')
128 cmd_interp = pathsearch('cmd', os.environ)
130 cmd_interp = pathsearch('command', os.environ)
132 # The upshot of all this is that, if you are using Python 1.5.2,
133 # you had better have cmd or command.com in your PATH when you run
136 def defaultSpawn(cmd, args, env):
138 sys.stderr.write("scons: Could not find command interpreter, is it in your PATH?\n")
142 args = [ cmd_interp, '/C' ] + args
143 ret = os.spawnve(os.P_WAIT, cmd_interp, args, env)
145 ret = exitvalmap[e[0]]
146 sys.stderr.write("scons: %s: %s\n" % (cmd, e[1]))
149 def defaultSpawn(cmd, args, env):
150 sys.stderr.write("scons: Unknown os '%s', cannot spawn command interpreter.\n" % os.name)
151 sys.stderr.write("scons: Set your command handler with SetCommandHandler().\n")
156 def SetCommandHandler(func):
161 """A factory for action objects."""
162 if isinstance(act, ActionBase):
165 return FunctionAction(act)
166 elif SCons.Util.is_String(act):
167 return CommandAction(act)
168 elif SCons.Util.is_List(act):
169 return ListAction(act)
174 """Base class for actions that create output objects."""
175 def __cmp__(self, other):
176 return cmp(self.__dict__, other.__dict__)
178 def show(self, string):
181 def subst_dict(self, **kw):
182 """Create a dictionary for substitution of construction
185 This translates the following special arguments:
187 env - the construction environment itself,
188 the values of which (CC, CCFLAGS, etc.)
189 are copied straight into the dictionary
191 target - the target (object or array of objects),
192 used to generate the TARGET and TARGETS
193 construction variables
195 source - the source (object or array of objects),
196 used to generate the SOURCES construction
199 Any other keyword arguments are copied into the
203 if kw.has_key('env'):
204 dict.update(kw['env'])
214 if kw.has_key('target'):
217 if not SCons.Util.is_List(t):
221 except AttributeError:
223 dict['TARGETS'] = SCons.Util.PathList(map(os.path.normpath, map(str, t)))
225 dict['TARGET'] = dict['TARGETS'][0]
227 if kw.has_key('source'):
230 if not SCons.Util.is_List(s):
232 dict['SOURCES'] = SCons.Util.PathList(map(os.path.normpath, map(str, s)))
236 # Autogenerate necessary construction variables.
237 SCons.Util.autogenerate(dict, dir = cwd)
241 class CommandAction(ActionBase):
242 """Class for command-execution actions."""
243 def __init__(self, string):
244 self.command = string
246 def execute(self, **kw):
248 dict = apply(self.subst_dict, (), kw)
249 cmd_list = SCons.Util.scons_subst_list(self.command, dict, {})
250 for cmd_line in cmd_list:
253 self.show(string.join(cmd_line))
256 ENV = kw['env']['ENV']
258 import SCons.Defaults
259 ENV = SCons.Defaults.ConstructionEnvironment['ENV']
260 ret = spawn(cmd_line[0], cmd_line, ENV)
265 def get_contents(self, **kw):
266 """Return the signature contents of this action's command line.
268 For signature purposes, it doesn't matter what targets or
269 sources we use, so long as we use the same ones every time
270 so the signature stays the same. We supply an array of two
271 of each to allow for distinction between TARGET and TARGETS.
273 kw['target'] = ['__t1__', '__t2__']
274 kw['source'] = ['__s1__', '__s2__']
275 dict = apply(self.subst_dict, (), kw)
276 return SCons.Util.scons_subst(self.command, dict, {})
278 class FunctionAction(ActionBase):
279 """Class for Python function actions."""
280 def __init__(self, function):
281 self.function = function
283 def execute(self, **kw):
285 # XXX: WHAT SHOULD WE PRINT HERE?
287 if kw.has_key('target'):
288 if SCons.Util.is_List(kw['target']):
289 kw['target'] = map(str, kw['target'])
291 kw['target'] = str(kw['target'])
292 if kw.has_key('source'):
293 kw['source'] = map(str, kw['source'])
294 return apply(self.function, (), kw)
296 def get_contents(self, **kw):
297 """Return the signature contents of this callable action.
299 By providing direct access to the code object of the
300 function, Python makes this extremely easy. Hooray!
302 #XXX DOES NOT ACCOUNT FOR CHANGES IN ENVIRONMENT VARIABLES
303 #THE FUNCTION MAY USE
305 # "self.function" is a function.
306 code = self.function.func_code.co_code
308 # "self.function" is a callable object.
309 code = self.function.__call__.im_func.func_code.co_code
312 class ListAction(ActionBase):
313 """Class for lists of other actions."""
314 def __init__(self, list):
315 self.list = map(lambda x: Action(x), list)
317 def execute(self, **kw):
319 r = apply(l.execute, (), kw)
324 def get_contents(self, **kw):
325 """Return the signature contents of this action list.
327 Simple concatenation of the signatures of the elements.
330 return reduce(lambda x, y: x + str(y.get_contents()), self.list, "")