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.
13
# Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The SCons Foundation
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.
34
from __future__ import division
36
__revision__ = "src/engine/SCons/Defaults.py 5134 2010/08/16 23:02:40 bdeegan"
49
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 _fetch_DefaultEnvironment(*args, **kw):
64
Returns the already-created default construction environment.
69
def DefaultEnvironment(*args, **kw):
71
Initial public entry point for creating the default construction
74
After creating the environment, we overwrite our name
75
(DefaultEnvironment) with the _fetch_DefaultEnvironment() function,
76
which more efficiently returns the initialized default construction
77
environment without checking for its existence.
79
(This function still exists with its _default_check because someone
80
else (*cough* Script/__init__.py *cough*) may keep a reference
81
to this function. So we can't use the fully functional idiom of
82
having the name originally be a something that *only* creates the
83
construction environment and then overwrites the name.)
88
_default_env = SCons.Environment.Environment(*args, **kw)
90
_default_env.Decider('MD5')
92
_default_env.Decider('timestamp-match')
93
global DefaultEnvironment
94
DefaultEnvironment = _fetch_DefaultEnvironment
95
_default_env._CacheDir_path = None
98
# Emitters for setting the shared attribute on object files,
99
# and an action for checking that all of the source files
100
# going into a shared library are, in fact, shared.
101
def StaticObjectEmitter(target, source, env):
103
tgt.attributes.shared = None
104
return (target, source)
106
def SharedObjectEmitter(target, source, env):
108
tgt.attributes.shared = 1
109
return (target, source)
111
def SharedFlagChecker(source, target, env):
112
same = env.subst('$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME')
113
if same == '0' or same == '' or same == 'False':
116
shared = src.attributes.shared
117
except AttributeError:
120
raise SCons.Errors.UserError("Source file: %s is static and is not compatible with shared target: %s" % (src, target[0]))
122
SharedCheck = SCons.Action.Action(SharedFlagChecker, None)
124
# Some people were using these variable name before we made
125
# SourceFileScanner part of the public interface. Don't break their
126
# SConscript files until we've given them some fair warning and a
128
CScan = SCons.Tool.CScanner
129
DScan = SCons.Tool.DScanner
130
LaTeXScan = SCons.Tool.LaTeXScanner
131
ObjSourceScan = SCons.Tool.SourceFileScanner
132
ProgScan = SCons.Tool.ProgramScanner
134
# These aren't really tool scanners, so they don't quite belong with
135
# the rest of those in Tool/__init__.py, but I'm not sure where else
136
# they should go. Leave them here for now.
137
import SCons.Scanner.Dir
138
DirScanner = SCons.Scanner.Dir.DirScanner()
139
DirEntryScanner = SCons.Scanner.Dir.DirEntryScanner()
141
# Actions for common languages.
142
CAction = SCons.Action.Action("$CCCOM", "$CCCOMSTR")
143
ShCAction = SCons.Action.Action("$SHCCCOM", "$SHCCCOMSTR")
144
CXXAction = SCons.Action.Action("$CXXCOM", "$CXXCOMSTR")
145
ShCXXAction = SCons.Action.Action("$SHCXXCOM", "$SHCXXCOMSTR")
147
ASAction = SCons.Action.Action("$ASCOM", "$ASCOMSTR")
148
ASPPAction = SCons.Action.Action("$ASPPCOM", "$ASPPCOMSTR")
150
LinkAction = SCons.Action.Action("$LINKCOM", "$LINKCOMSTR")
151
ShLinkAction = SCons.Action.Action("$SHLINKCOM", "$SHLINKCOMSTR")
153
LdModuleLinkAction = SCons.Action.Action("$LDMODULECOM", "$LDMODULECOMSTR")
155
# Common tasks that we allow users to perform in platform-independent
156
# ways by creating ActionFactory instances.
157
ActionFactory = SCons.Action.ActionFactory
159
def get_paths_str(dest):
160
# If dest is a list, we need to manually call str() on each element
161
if SCons.Util.is_List(dest):
164
elem_strs.append('"' + str(element) + '"')
165
return '[' + ', '.join(elem_strs) + ']'
167
return '"' + str(dest) + '"'
169
def chmod_func(dest, mode):
170
SCons.Node.FS.invalidate_node_memos(dest)
171
if not SCons.Util.is_List(dest):
174
os.chmod(str(element), mode)
176
def chmod_strfunc(dest, mode):
177
return 'Chmod(%s, 0%o)' % (get_paths_str(dest), mode)
179
Chmod = ActionFactory(chmod_func, chmod_strfunc)
181
def copy_func(dest, src):
182
SCons.Node.FS.invalidate_node_memos(dest)
183
if SCons.Util.is_List(src) and os.path.isdir(dest):
185
shutil.copy2(file, dest)
187
elif os.path.isfile(src):
188
return shutil.copy2(src, dest)
190
return shutil.copytree(src, dest, 1)
192
Copy = ActionFactory(copy_func,
193
lambda dest, src: 'Copy("%s", "%s")' % (dest, src),
196
def delete_func(dest, must_exist=0):
197
SCons.Node.FS.invalidate_node_memos(dest)
198
if not SCons.Util.is_List(dest):
202
if not must_exist and not os.path.exists(entry):
204
if not os.path.exists(entry) or os.path.isfile(entry):
208
shutil.rmtree(entry, 1)
211
def delete_strfunc(dest, must_exist=0):
212
return 'Delete(%s)' % get_paths_str(dest)
214
Delete = ActionFactory(delete_func, delete_strfunc)
216
def mkdir_func(dest):
217
SCons.Node.FS.invalidate_node_memos(dest)
218
if not SCons.Util.is_List(dest):
222
os.makedirs(str(entry))
225
if (e.args[0] == errno.EEXIST or
226
(sys.platform=='win32' and e.args[0]==183)) \
227
and os.path.isdir(str(entry)):
228
pass # not an error if already exists
232
Mkdir = ActionFactory(mkdir_func,
233
lambda dir: 'Mkdir(%s)' % get_paths_str(dir))
235
def move_func(dest, src):
236
SCons.Node.FS.invalidate_node_memos(dest)
237
SCons.Node.FS.invalidate_node_memos(src)
238
shutil.move(src, dest)
240
Move = ActionFactory(move_func,
241
lambda dest, src: 'Move("%s", "%s")' % (dest, src),
244
def touch_func(dest):
245
SCons.Node.FS.invalidate_node_memos(dest)
246
if not SCons.Util.is_List(dest):
250
mtime = int(time.time())
251
if os.path.exists(file):
252
atime = os.path.getatime(file)
256
os.utime(file, (atime, mtime))
258
Touch = ActionFactory(touch_func,
259
lambda file: 'Touch(%s)' % get_paths_str(file))
261
# Internal utility functions
263
def _concat(prefix, list, suffix, env, f=lambda x: x, target=None, source=None):
265
Creates a new list from 'list' by first interpolating each element
266
in the list using the 'env' dictionary and then calling f on the
267
list, and finally calling _concat_ixes to concatenate 'prefix' and
268
'suffix' onto each element of the list.
273
l = f(SCons.PathList.PathList(list).subst_path(env, target, source))
277
return _concat_ixes(prefix, list, suffix, env)
279
def _concat_ixes(prefix, list, suffix, env):
281
Creates a new list from 'list' by concatenating the 'prefix' and
282
'suffix' arguments onto each element of the list. A trailing space
283
on 'prefix' or leading space on 'suffix' will cause them to be put
284
into separate list elements rather than being concatenated.
289
# ensure that prefix and suffix are strings
290
prefix = str(env.subst(prefix, SCons.Subst.SUBST_RAW))
291
suffix = str(env.subst(suffix, SCons.Subst.SUBST_RAW))
294
if isinstance(x, SCons.Node.FS.File):
301
if prefix[-1] == ' ':
302
result.append(prefix[:-1])
303
elif x[:len(prefix)] != prefix:
310
result.append(suffix[1:])
311
elif x[-len(suffix):] != suffix:
312
result[-1] = result[-1]+suffix
316
def _stripixes(prefix, itms, suffix, stripprefixes, stripsuffixes, env, c=None):
318
This is a wrapper around _concat()/_concat_ixes() that checks for
319
the existence of prefixes or suffixes on list items and strips them
320
where it finds them. This is used by tools (like the GNU linker)
321
that need to turn something like 'libfoo.a' into '-lfoo'.
328
env_c = env['_concat']
329
if env_c != _concat and callable(env_c):
330
# There's a custom _concat() method in the construction
331
# environment, and we've allowed people to set that in
332
# the past (see test/custom-concat.py), so preserve the
333
# backwards compatibility.
338
stripprefixes = list(map(env.subst, SCons.Util.flatten(stripprefixes)))
339
stripsuffixes = list(map(env.subst, SCons.Util.flatten(stripsuffixes)))
342
for l in SCons.PathList.PathList(itms).subst_path(env, None, None):
343
if isinstance(l, SCons.Node.FS.File):
347
if not SCons.Util.is_String(l):
350
for stripprefix in stripprefixes:
351
lsp = len(stripprefix)
352
if l[:lsp] == stripprefix:
354
# Do not strip more than one prefix
357
for stripsuffix in stripsuffixes:
358
lss = len(stripsuffix)
359
if l[-lss:] == stripsuffix:
361
# Do not strip more than one suffix
366
return c(prefix, stripped, suffix, env)
368
def processDefines(defs):
369
"""process defines, resolving strings, lists, dictionaries, into a list of
372
if SCons.Util.is_List(defs):
375
if SCons.Util.is_List(d) or isinstance(d, tuple):
376
l.append(str(d[0]) + '=' + str(d[1]))
379
elif SCons.Util.is_Dict(defs):
380
# The items in a dictionary are stored in random order, but
381
# if the order of the command-line options changes from
382
# invocation to invocation, then the signature of the command
383
# line will change and we'll get random unnecessary rebuilds.
384
# Consequently, we have to sort the keys to ensure a
385
# consistent order...
387
for k,v in sorted(defs.items()):
391
l.append(str(k) + '=' + str(v))
396
def _defines(prefix, defs, suffix, env, c=_concat_ixes):
397
"""A wrapper around _concat_ixes that turns a list or string
398
into a list of C preprocessor command-line definitions.
401
return c(prefix, env.subst_path(processDefines(defs)), suffix, env)
403
class NullCmdGenerator(object):
404
"""This is a callable class that can be used in place of other
405
command generators if you don't want them to do anything.
407
The __call__ method for this class simply returns the thing
408
you instantiated it with.
411
env["DO_NOTHING"] = NullCmdGenerator
412
env["LINKCOM"] = "${DO_NOTHING('$LINK $SOURCES $TARGET')}"
415
def __init__(self, cmd):
418
def __call__(self, target, source, env, for_signature=None):
421
class Variable_Method_Caller(object):
422
"""A class for finding a construction variable on the stack and
423
calling one of its methods.
425
We use this to support "construction variables" in our string
426
eval()s that actually stand in for methods--specifically, use
427
of "RDirs" in call to _concat that should actually execute the
428
"TARGET.RDirs" method. (We used to support this by creating a little
429
"build dictionary" that mapped RDirs to the method, but this got in
430
the way of Memoizing construction environments, because we had to
431
create new environment objects to hold the variables.)
433
def __init__(self, variable, method):
434
self.variable = variable
436
def __call__(self, *args, **kw):
438
except ZeroDivisionError:
439
# Don't start iterating with the current stack-frame to
440
# prevent creating reference cycles (f_back is safe).
441
frame = sys.exc_info()[2].tb_frame.f_back
442
variable = self.variable
444
if variable in frame.f_locals:
445
v = frame.f_locals[variable]
447
method = getattr(v, self.method)
448
return method(*args, **kw)
452
ConstructionEnvironment = {
455
'CONFIGUREDIR' : '#/.sconf_temp',
456
'CONFIGURELOG' : '#/config.log',
457
'CPPSUFFIXES' : SCons.Tool.CSuffixes,
458
'DSUFFIXES' : SCons.Tool.DSuffixes,
460
'IDLSUFFIXES' : SCons.Tool.IDLSuffixes,
461
# 'LATEXSUFFIXES' : SCons.Tool.LaTeXSuffixes, # moved to the TeX tools generate functions
463
'_defines' : _defines,
464
'_stripixes' : _stripixes,
465
'_LIBFLAGS' : '${_concat(LIBLINKPREFIX, LIBS, LIBLINKSUFFIX, __env__)}',
466
'_LIBDIRFLAGS' : '$( ${_concat(LIBDIRPREFIX, LIBPATH, LIBDIRSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
467
'_CPPINCFLAGS' : '$( ${_concat(INCPREFIX, CPPPATH, INCSUFFIX, __env__, RDirs, TARGET, SOURCE)} $)',
468
'_CPPDEFFLAGS' : '${_defines(CPPDEFPREFIX, CPPDEFINES, CPPDEFSUFFIX, __env__)}',
469
'TEMPFILE' : NullCmdGenerator,
470
'Dir' : Variable_Method_Caller('TARGET', 'Dir'),
471
'Dirs' : Variable_Method_Caller('TARGET', 'Dirs'),
472
'File' : Variable_Method_Caller('TARGET', 'File'),
473
'RDirs' : Variable_Method_Caller('TARGET', 'RDirs'),
478
# indent-tabs-mode:nil
480
# vim: set expandtab tabstop=4 shiftwidth=4: