fc0ab26ba3faed30bfbcf8a34993a0c5fe7be70f
[senf.git] / scons / scons-1.2.0 / engine / SCons / Defaults.py
1 """SCons.Defaults
2
3 Builders and other things for the local site.  Here's where we'll
4 duplicate the functionality of autoconf until we move it into the
5 installation procedure or use something like qmconf.
6
7 The code that reads the registry to find MSVC components was borrowed
8 from distutils.msvccompiler.
9
10 """
11
12 #
13 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 The SCons Foundation
14 #
15 # Permission is hereby granted, free of charge, to any person obtaining
16 # a copy of this software and associated documentation files (the
17 # "Software"), to deal in the Software without restriction, including
18 # without limitation the rights to use, copy, modify, merge, publish,
19 # distribute, sublicense, and/or sell copies of the Software, and to
20 # permit persons to whom the Software is furnished to do so, subject to
21 # the following conditions:
22 #
23 # The above copyright notice and this permission notice shall be included
24 # in all copies or substantial portions of the Software.
25 #
26 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
27 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
28 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 #
34
35 __revision__ = "src/engine/SCons/Defaults.py 3842 2008/12/20 22:59:52 scons"
36
37
38
39 import os
40 import os.path
41 import shutil
42 import stat
43 import string
44 import time
45 import types
46 import sys
47
48 import SCons.Action
49 import SCons.Builder
50 import SCons.CacheDir
51 import SCons.Environment
52 import SCons.PathList
53 import SCons.Subst
54 import SCons.Tool
55
56 # A placeholder for a default Environment (for fetching source files
57 # from source code management systems and the like).  This must be
58 # initialized later, after the top-level directory is set by the calling
59 # interface.
60 _default_env = None
61
62 # Lazily instantiate the default environment so the overhead of creating
63 # it doesn't apply when it's not needed.
64 def _fetch_DefaultEnvironment(*args, **kw):
65     """
66     Returns the already-created default construction environment.
67     """
68     global _default_env
69     return _default_env
70
71 def DefaultEnvironment(*args, **kw):
72     """
73     Initial public entry point for creating the default construction
74     Environment.
75
76     After creating the environment, we overwrite our name
77     (DefaultEnvironment) with the _fetch_DefaultEnvironment() function,
78     which more efficiently returns the initialized default construction
79     environment without checking for its existence.
80
81     (This function still exists with its _default_check because someone
82     else (*cough* Script/__init__.py *cough*) may keep a reference
83     to this function.  So we can't use the fully functional idiom of
84     having the name originally be a something that *only* creates the
85     construction environment and then overwrites the name.)
86     """
87     global _default_env
88     if not _default_env:
89         import SCons.Util
90         _default_env = apply(SCons.Environment.Environment, args, kw)
91         if SCons.Util.md5:
92             _default_env.Decider('MD5')
93         else:
94             _default_env.Decider('timestamp-match')
95         global DefaultEnvironment
96         DefaultEnvironment = _fetch_DefaultEnvironment
97         _default_env._CacheDir_path = None
98     return _default_env
99
100 # Emitters for setting the shared attribute on object files,
101 # and an action for checking that all of the source files
102 # going into a shared library are, in fact, shared.
103 def StaticObjectEmitter(target, source, env):
104     for tgt in target:
105         tgt.attributes.shared = None
106     return (target, source)
107
108 def SharedObjectEmitter(target, source, env):
109     for tgt in target:
110         tgt.attributes.shared = 1
111     return (target, source)
112
113 def SharedFlagChecker(source, target, env):
114     same = env.subst('$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME')
115     if same == '0' or same == '' or same == 'False':
116         for src in source:
117             try:
118                 shared = src.attributes.shared
119             except AttributeError:
120                 shared = None
121             if not shared:
122                 raise SCons.Errors.UserError, "Source file: %s is static and is not compatible with shared target: %s" % (src, target[0])
123
124 SharedCheck = SCons.Action.Action(SharedFlagChecker, None)
125
126 # Some people were using these variable name before we made
127 # SourceFileScanner part of the public interface.  Don't break their
128 # SConscript files until we've given them some fair warning and a
129 # transition period.
130 CScan = SCons.Tool.CScanner
131 DScan = SCons.Tool.DScanner
132 LaTeXScan = SCons.Tool.LaTeXScanner
133 ObjSourceScan = SCons.Tool.SourceFileScanner
134 ProgScan = SCons.Tool.ProgramScanner
135
136 # These aren't really tool scanners, so they don't quite belong with
137 # the rest of those in Tool/__init__.py, but I'm not sure where else
138 # they should go.  Leave them here for now.
139 import SCons.Scanner.Dir
140 DirScanner = SCons.Scanner.Dir.DirScanner()
141 DirEntryScanner = SCons.Scanner.Dir.DirEntryScanner()
142
143 # Actions for common languages.
144 CAction = SCons.Action.Action("$CCCOM", "$CCCOMSTR")
145 ShCAction = SCons.Action.Action("$SHCCCOM", "$SHCCCOMSTR")
146 CXXAction = SCons.Action.Action("$CXXCOM", "$CXXCOMSTR")
147 ShCXXAction = SCons.Action.Action("$SHCXXCOM", "$SHCXXCOMSTR")
148
149 ASAction = SCons.Action.Action("$ASCOM", "$ASCOMSTR")
150 ASPPAction = SCons.Action.Action("$ASPPCOM", "$ASPPCOMSTR")
151
152 LinkAction = SCons.Action.Action("$LINKCOM", "$LINKCOMSTR")
153 ShLinkAction = SCons.Action.Action("$SHLINKCOM", "$SHLINKCOMSTR")
154
155 LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR")
156
157 # Common tasks that we allow users to perform in platform-independent
158 # ways by creating ActionFactory instances.
159 ActionFactory = SCons.Action.ActionFactory
160
161 def get_paths_str(dest):
162     # If dest is a list, we need to manually call str() on each element
163     if SCons.Util.is_List(dest):
164         elem_strs = []
165         for element in dest:
166             elem_strs.append('"' + str(element) + '"')
167         return '[' + string.join(elem_strs, ', ') + ']'
168     else:
169         return '"' + str(dest) + '"'
170
171 def chmod_func(dest, mode):
172     SCons.Node.FS.invalidate_node_memos(dest)
173     if not SCons.Util.is_List(dest):
174         dest = [dest]
175     for element in dest:
176         os.chmod(str(element), mode)
177
178 def chmod_strfunc(dest, mode):
179     return 'Chmod(%s, 0%o)' % (get_paths_str(dest), mode)
180
181 Chmod = ActionFactory(chmod_func, chmod_strfunc)
182
183 def copy_func(dest, src):
184     SCons.Node.FS.invalidate_node_memos(dest)
185     if SCons.Util.is_List(src) and os.path.isdir(dest):
186         for file in src:
187             shutil.copy2(file, dest)
188         return 0
189     elif os.path.isfile(src):
190         return shutil.copy2(src, dest)
191     else:
192         return shutil.copytree(src, dest, 1)
193
194 Copy = ActionFactory(copy_func,
195                      lambda dest, src: 'Copy("%s", "%s")' % (dest, src),
196                      convert=str)
197
198 def delete_func(dest, must_exist=0):
199     SCons.Node.FS.invalidate_node_memos(dest)
200     if not SCons.Util.is_List(dest):
201         dest = [dest]
202     for entry in dest:
203         entry = str(entry)
204         if not must_exist and not os.path.exists(entry):
205             continue
206         if not os.path.exists(entry) or os.path.isfile(entry):
207             os.unlink(entry)
208             continue
209         else:
210             shutil.rmtree(entry, 1)
211             continue
212
213 def delete_strfunc(dest, must_exist=0):
214     return 'Delete(%s)' % get_paths_str(dest)
215
216 Delete = ActionFactory(delete_func, delete_strfunc)
217
218 def mkdir_func(dest):
219     SCons.Node.FS.invalidate_node_memos(dest)
220     if not SCons.Util.is_List(dest):
221         dest = [dest]
222     for entry in dest:
223         os.makedirs(str(entry))
224
225 Mkdir = ActionFactory(mkdir_func,
226                       lambda dir: 'Mkdir(%s)' % get_paths_str(dir))
227
228 def move_func(dest, src):
229     SCons.Node.FS.invalidate_node_memos(dest)
230     SCons.Node.FS.invalidate_node_memos(src)
231     os.rename(src, dest)
232
233 Move = ActionFactory(move_func,
234                      lambda dest, src: 'Move("%s", "%s")' % (dest, src),
235                      convert=str)
236
237 def touch_func(dest):
238     SCons.Node.FS.invalidate_node_memos(dest)
239     if not SCons.Util.is_List(dest):
240         dest = [dest]
241     for file in dest:
242         file = str(file)
243         mtime = int(time.time())
244         if os.path.exists(file):
245             atime = os.path.getatime(file)
246         else:
247             open(file, 'w')
248             atime = mtime
249         os.utime(file, (atime, mtime))
250
251 Touch = ActionFactory(touch_func,
252                       lambda file: 'Touch(%s)' % get_paths_str(file))
253
254 # Internal utility functions
255
256 def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None):
257     """
258     Creates a new list from 'list' by first interpolating each element
259     in the list using the 'env' dictionary and then calling f on the
260     list, and finally calling _concat_ixes to concatenate 'prefix' and
261     'suffix' onto each element of the list.
262     """
263     if not list:
264         return list
265
266     l = f(SCons.PathList.PathList(list).subst_path(env, target, source))
267     if not l is None:
268         list = l
269
270     return _concat_ixes(prefix, list, suffix, env)
271
272 def _concat_ixes(prefix, list, suffix, env):
273     """
274     Creates a new list from 'list' by concatenating the 'prefix' and
275     'suffix' arguments onto each element of the list.  A trailing space
276     on 'prefix' or leading space on 'suffix' will cause them to be put
277     into separate list elements rather than being concatenated.
278     """
279
280     result = []
281
282     # ensure that prefix and suffix are strings
283     prefix = str(env.subst(prefix, SCons.Subst.SUBST_RAW))
284     suffix = str(env.subst(suffix, SCons.Subst.SUBST_RAW))
285
286     for x in list:
287         if isinstance(x, SCons.Node.FS.File):
288             result.append(x)
289             continue
290         x = str(x)
291         if x:
292
293             if prefix:
294                 if prefix[-1] == ' ':
295                     result.append(prefix[:-1])
296                 elif x[:len(prefix)] != prefix:
297                     x = prefix + x
298
299             result.append(x)
300
301             if suffix:
302                 if suffix[0] == ' ':
303                     result.append(suffix[1:])
304                 elif x[-len(suffix):] != suffix:
305                     result[-1] = result[-1]+suffix
306
307     return result
308
309 def _stripixes(prefix, list, suffix, stripprefixes, stripsuffixes, env, c=None):
310     """
311     This is a wrapper around _concat()/_concat_ixes() that checks for the
312     existence of prefixes or suffixes on list elements and strips them
313     where it finds them.  This is used by tools (like the GNU linker)
314     that need to turn something like 'libfoo.a' into '-lfoo'.
315     """
316     
317     if not list:
318         return list
319
320     if not callable(c):
321         env_c = env['_concat']
322         if env_c != _concat and callable(env_c):
323             # There's a custom _concat() method in the construction
324             # environment, and we've allowed people to set that in
325             # the past (see test/custom-concat.py), so preserve the
326             # backwards compatibility.
327             c = env_c
328         else:
329             c = _concat_ixes
330     
331     stripprefixes = map(env.subst, SCons.Util.flatten(stripprefixes))
332     stripsuffixes = map(env.subst, SCons.Util.flatten(stripsuffixes))
333
334     stripped = []
335     for l in SCons.PathList.PathList(list).subst_path(env, None, None):
336         if isinstance(l, SCons.Node.FS.File):
337             stripped.append(l)
338             continue
339
340         if not SCons.Util.is_String(l):
341             l = str(l)
342
343         for stripprefix in stripprefixes:
344             lsp = len(stripprefix)
345             if l[:lsp] == stripprefix:
346                 l = l[lsp:]
347                 # Do not strip more than one prefix
348                 break
349
350         for stripsuffix in stripsuffixes:
351             lss = len(stripsuffix)
352             if l[-lss:] == stripsuffix:
353                 l = l[:-lss]
354                 # Do not strip more than one suffix
355                 break
356
357         stripped.append(l)
358
359     return c(prefix, stripped, suffix, env)
360
361 def _defines(prefix, defs, suffix, env, c=_concat_ixes):
362     """A wrapper around _concat_ixes that turns a list or string
363     into a list of C preprocessor command-line definitions.
364     """
365     if SCons.Util.is_List(defs):
366         l = []
367         for d in defs:
368             if SCons.Util.is_List(d) or type(d) is types.TupleType:
369                 l.append(str(d[0]) + '=' + str(d[1]))
370             else:
371                 l.append(str(d))
372     elif SCons.Util.is_Dict(defs):
373         # The items in a dictionary are stored in random order, but
374         # if the order of the command-line options changes from
375         # invocation to invocation, then the signature of the command
376         # line will change and we'll get random unnecessary rebuilds.
377         # Consequently, we have to sort the keys to ensure a
378         # consistent order...
379         l = []
380         keys = defs.keys()
381         keys.sort()
382         for k in keys:
383             v = defs[k]
384             if v is None:
385                 l.append(str(k))
386             else:
387                 l.append(str(k) + '=' + str(v))
388     else:
389         l = [str(defs)]
390     return c(prefix, env.subst_path(l), suffix, env)
391     
392 class NullCmdGenerator:
393     """This is a callable class that can be used in place of other
394     command generators if you don't want them to do anything.
395
396     The __call__ method for this class simply returns the thing
397     you instantiated it with.
398
399     Example usage:
400     env["DO_NOTHING"] = NullCmdGenerator
401     env["LINKCOM"] = "${DO_NOTHING('$LINK $SOURCES $TARGET')}"
402     """
403
404     def __init__(self, cmd):
405         self.cmd = cmd
406
407     def __call__(self, target, source, env, for_signature=None):
408         return self.cmd
409
410 class Variable_Method_Caller:
411     """A class for finding a construction variable on the stack and
412     calling one of its methods.
413
414     We use this to support "construction variables" in our string
415     eval()s that actually stand in for methods--specifically, use
416     of "RDirs" in call to _concat that should actually execute the
417     "TARGET.RDirs" method.  (We used to support this by creating a little
418     "build dictionary" that mapped RDirs to the method, but this got in
419     the way of Memoizing construction environments, because we had to
420     create new environment objects to hold the variables.)
421     """
422     def __init__(self, variable, method):
423         self.variable = variable
424         self.method = method
425     def __call__(self, *args, **kw):
426         try: 1/0
427         except ZeroDivisionError: 
428             # Don't start iterating with the current stack-frame to
429             # prevent creating reference cycles (f_back is safe).
430             frame = sys.exc_info()[2].tb_frame.f_back
431         variable = self.variable
432         while frame:
433             if frame.f_locals.has_key(variable):
434                 v = frame.f_locals[variable]
435                 if v:
436                     method = getattr(v, self.method)
437                     return apply(method, args, kw)
438             frame = frame.f_back
439         return None
440
441 ConstructionEnvironment = {
442     'BUILDERS'      : {},
443     'SCANNERS'      : [],
444     'CONFIGUREDIR'  : '#/.sconf_temp',
445     'CONFIGURELOG'  : '#/config.log',
446     'CPPSUFFIXES'   : SCons.Tool.CSuffixes,
447     'DSUFFIXES'     : SCons.Tool.DSuffixes,
448     'ENV'           : {},
449     'IDLSUFFIXES'   : SCons.Tool.IDLSuffixes,
450     'LATEXSUFFIXES' : SCons.Tool.LaTeXSuffixes,
451     '_concat'       : _concat,
452     '_defines'      : _defines,
453     '_stripixes'    : _stripixes,
454     '_LIBFLAGS'     : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
455     '_LIBDIRFLAGS'  : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
456     '_CPPINCFLAGS'  : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
457     '_CPPDEFFLAGS'  : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
458     'TEMPFILE'      : NullCmdGenerator,
459     'Dir'           : Variable_Method_Caller('TARGET', 'Dir'),
460     'Dirs'          : Variable_Method_Caller('TARGET', 'Dirs'),
461     'File'          : Variable_Method_Caller('TARGET', 'File'),
462     'RDirs'         : Variable_Method_Caller('TARGET', 'RDirs'),
463 }