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.
7 The code that reads the registry to find MSVC components was borrowed
8 from distutils.msvccompiler.
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:
23 # The above copyright notice and this permission notice shall be included
24 # in all copies or substantial portions of the Software.
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.
35 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
50 import SCons.Environment
54 # A placeholder for a default Environment (for fetching source files
55 # from source code management systems and the like). This must be
56 # initialized later, after the top-level directory is set by the calling
60 # Lazily instantiate the default environment so the overhead of creating
61 # it doesn't apply when it's not needed.
62 def DefaultEnvironment(*args, **kw):
65 _default_env = apply(SCons.Environment.Environment, args, kw)
66 _default_env._build_signature = 1
67 _default_env._calc_module = SCons.Sig.default_module
70 # Emitters for setting the shared attribute on object files,
71 # and an action for checking that all of the source files
72 # going into a shared library are, in fact, shared.
73 def StaticObjectEmitter(target, source, env):
75 tgt.attributes.shared = None
76 return (target, source)
78 def SharedObjectEmitter(target, source, env):
80 tgt.attributes.shared = 1
81 return (target, source)
83 def SharedFlagChecker(source, target, env):
84 same = env.subst('$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME')
85 if same == '0' or same == '' or same == 'False':
88 shared = src.attributes.shared
89 except AttributeError:
92 raise SCons.Errors.UserError, "Source file: %s is static and is not compatible with shared target: %s" % (src, target[0])
94 SharedCheck = SCons.Action.Action(SharedFlagChecker, None)
96 # Some people were using these variable name before we made
97 # SourceFileScanner part of the public interface. Don't break their
98 # SConscript files until we've given them some fair warning and a
100 CScan = SCons.Tool.CScanner
101 DScan = SCons.Tool.DScanner
102 ObjSourceScan = SCons.Tool.SourceFileScanner
103 ProgScan = SCons.Tool.ProgramScanner
105 # This isn't really a tool scanner, so it doesn't quite belong with
106 # the rest of those in Tool/__init__.py, but I'm not sure where else it
107 # should go. Leave it here for now.
108 import SCons.Scanner.Dir
109 DirScanner = SCons.Scanner.Dir.DirScanner()
111 # Actions for common languages.
112 CAction = SCons.Action.Action("$CCCOM", "$CCCOMSTR")
113 ShCAction = SCons.Action.Action("$SHCCCOM", "$SHCCCOMSTR")
114 CXXAction = SCons.Action.Action("$CXXCOM", "$CXXCOMSTR")
115 ShCXXAction = SCons.Action.Action("$SHCXXCOM", "$SHCXXCOMSTR")
117 ASAction = SCons.Action.Action("$ASCOM", "$ASCOMSTR")
118 ASPPAction = SCons.Action.Action("$ASPPCOM", "$ASPPCOMSTR")
120 LinkAction = SCons.Action.Action("$LINKCOM", "$LINKCOMSTR")
121 ShLinkAction = SCons.Action.Action("$SHLINKCOM", "$SHLINKCOMSTR")
123 LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR")
126 """Common function to generate a DVI file Builder."""
127 return SCons.Builder.Builder(action = {},
128 # The suffix is not configurable via a
129 # construction variable like $DVISUFFIX
130 # because the output file name is
131 # hard-coded within TeX.
135 """A function for generating the PDF Builder."""
136 return SCons.Builder.Builder(action = { },
137 prefix = '$PDFPREFIX',
138 suffix = '$PDFSUFFIX')
140 # Common tasks that we allow users to perform in platform-independent
141 # ways by creating ActionFactory instances.
142 ActionFactory = SCons.Action.ActionFactory
144 Chmod = ActionFactory(os.chmod,
145 lambda dest, mode: 'Chmod("%s", 0%o)' % (dest, mode))
147 def copy_func(dest, src):
148 if os.path.isfile(src):
149 return shutil.copy(src, dest)
151 return shutil.copytree(src, dest, 1)
153 Copy = ActionFactory(copy_func,
154 lambda dest, src: 'Copy("%s", "%s")' % (dest, src))
156 def delete_func(entry, must_exist=0):
157 if not must_exist and not os.path.exists(entry):
159 if not os.path.exists(entry) or os.path.isfile(entry):
160 return os.unlink(entry)
162 return shutil.rmtree(entry, 1)
164 def delete_strfunc(entry, must_exist=0):
165 return 'Delete("%s")' % entry
167 Delete = ActionFactory(delete_func, delete_strfunc)
169 Mkdir = ActionFactory(os.makedirs,
170 lambda dir: 'Mkdir("%s")' % dir)
172 Move = ActionFactory(lambda dest, src: os.rename(src, dest),
173 lambda dest, src: 'Move("%s", "%s")' % (dest, src))
175 def touch_func(file):
176 mtime = int(time.time())
177 if os.path.exists(file):
178 atime = os.path.getatime(file)
182 return os.utime(file, (atime, mtime))
184 Touch = ActionFactory(touch_func,
185 lambda file: 'Touch("%s")' % file)
187 # Internal utility functions
188 def copyFunc(dest, source, env):
189 """Install a source file into a destination by copying it (and its
190 permission/mode bits)."""
191 shutil.copy2(source, dest)
193 os.chmod(dest, stat.S_IMODE(st[stat.ST_MODE]) | stat.S_IWRITE)
196 def _concat(prefix, list, suffix, env, f=lambda x: x, target=None):
197 """Creates a new list from 'list' by first interpolating each
198 element in the list using the 'env' dictionary and then calling f
199 on the list, and finally concatenating 'prefix' and 'suffix' onto
200 each element of the list. A trailing space on 'prefix' or leading
201 space on 'suffix' will cause them to be put into separate list
202 elements rather than being concatenated."""
207 if SCons.Util.is_List(list):
208 list = SCons.Util.flatten(list)
209 list = f(env.subst_path(list, target=target))
213 # ensure that prefix and suffix are strings
214 prefix = str(env.subst(prefix, SCons.Util.SUBST_RAW))
215 suffix = str(env.subst(suffix, SCons.Util.SUBST_RAW))
218 if isinstance(x, SCons.Node.FS.File):
225 if prefix[-1] == ' ':
226 result.append(prefix[:-1])
227 elif x[:len(prefix)] != prefix:
234 result.append(suffix[1:])
235 elif x[-len(suffix):] != suffix:
236 result[-1] = result[-1]+suffix
240 def _stripixes(prefix, list, suffix, stripprefix, stripsuffix, env, c=None):
241 """This is a wrapper around _concat() that checks for the existence
242 of prefixes or suffixes on list elements and strips them where it
243 finds them. This is used by tools (like the GNU linker) that need
244 to turn something like 'libfoo.a' into '-lfoo'."""
247 if callable(env["_concat"]):
251 def f(list, sp=stripprefix, ss=stripsuffix):
254 if isinstance(l, SCons.Node.FS.File):
257 if not SCons.Util.is_String(l):
259 if l[:len(sp)] == sp:
261 if l[-len(ss):] == ss:
265 return c(prefix, list, suffix, env, f)
267 def _defines(prefix, defs, suffix, env, c=_concat):
268 """A wrapper around _concat that turns a list or string
269 into a list of C preprocessor command-line definitions.
271 if SCons.Util.is_List(defs):
274 if SCons.Util.is_List(d) or type(d) is types.TupleType:
275 l.append(str(d[0]) + '=' + str(d[1]))
278 elif SCons.Util.is_Dict(defs):
279 # The items in a dictionary are stored in random order, but
280 # if the order of the command-line options changes from
281 # invocation to invocation, then the signature of the command
282 # line will change and we'll get random unnecessary rebuilds.
283 # Consequently, we have to sort the keys to ensure a
284 # consistent order...
293 l.append(str(k) + '=' + str(v))
296 return c(prefix, l, suffix, env)
298 class NullCmdGenerator:
299 """This is a callable class that can be used in place of other
300 command generators if you don't want them to do anything.
302 The __call__ method for this class simply returns the thing
303 you instantiated it with.
306 env["DO_NOTHING"] = NullCmdGenerator
307 env["LINKCOM"] = "${DO_NOTHING('$LINK $SOURCES $TARGET')}"
310 def __init__(self, cmd):
313 def __call__(self, target, source, env, for_signature=None):
316 class Variable_Method_Caller:
317 """A class for finding a construction variable on the stack and
318 calling one of its methods.
320 We use this to support "construction variables" in our string
321 eval()s that actually stand in for methods--specifically, use
322 of "RDirs" in call to _concat that should actually execute the
323 "TARGET.RDirs" method. (We used to support this by creating a little
324 "build dictionary" that mapped RDirs to the method, but this got in
325 the way of Memoizing construction environments, because we had to
326 create new environment objects to hold the variables.)
328 def __init__(self, variable, method):
329 self.variable = variable
331 def __call__(self, *args, **kw):
333 except ZeroDivisionError: frame = sys.exc_info()[2].tb_frame
337 variable = frame.f_locals[self.variable]
343 method = getattr(variable, self.method)
344 return apply(method, args, kw)
346 ConstructionEnvironment = {
349 'CPPSUFFIXES' : SCons.Tool.CSuffixes,
350 'DSUFFIXES' : SCons.Tool.DSuffixes,
351 'IDLSUFFIXES' : SCons.Tool.IDLSuffixes,
353 'PDFSUFFIX' : '.pdf',
357 'INSTALL' : copyFunc,
359 '_defines' : _defines,
360 '_stripixes' : _stripixes,
361 '_LIBFLAGS' : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
362 '_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET)} $)',
363 '_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET)} $)',
364 '_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
365 'TEMPFILE' : NullCmdGenerator,
366 'Dir' : Variable_Method_Caller('TARGET', 'Dir'),
367 'File' : Variable_Method_Caller('TARGET', 'File'),
368 'RDirs' : Variable_Method_Caller('TARGET', 'RDirs'),