1"""SCons.Script
2
3This file implements the main() function used by the scons script.
4
5Architecturally, this *is* the scons script, and will likely only be
6called from the external "scons" wrapper.  Consequently, anything here
7should not be, or be considered, part of the build engine.  If it's
8something that we expect other software to want to use, it should go in
9some other module.  If it's specific to the "scons" script invocation,
10it goes here.
11
12"""
13
14#
15# Copyright (c) 2001 - 2014 The SCons Foundation
16#
17# Permission is hereby granted, free of charge, to any person obtaining
18# a copy of this software and associated documentation files (the
19# "Software"), to deal in the Software without restriction, including
20# without limitation the rights to use, copy, modify, merge, publish,
21# distribute, sublicense, and/or sell copies of the Software, and to
22# permit persons to whom the Software is furnished to do so, subject to
23# the following conditions:
24#
25# The above copyright notice and this permission notice shall be included
26# in all copies or substantial portions of the Software.
27#
28# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
29# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
30# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
32# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35#
36
37__revision__ = "src/engine/SCons/Script/__init__.py  2014/07/05 09:42:21 garyo"
38
39import time
40start_time = time.time()
41
42import collections
43import os
44import sys
45
46# Special chicken-and-egg handling of the "--debug=memoizer" flag:
47#
48# SCons.Memoize contains a metaclass implementation that affects how
49# the other classes are instantiated.  The Memoizer may add shim methods
50# to classes that have methods that cache computed values in order to
51# count and report the hits and misses.
52#
53# If we wait to enable the Memoization until after we've parsed the
54# command line options normally, it will be too late, because the Memoizer
55# will have already analyzed the classes that it's Memoizing and decided
56# to not add the shims.  So we use a special-case, up-front check for
57# the "--debug=memoizer" flag and enable Memoizer before we import any
58# of the other modules that use it.
59
60_args = sys.argv + os.environ.get('SCONSFLAGS', '').split()
61if "--debug=memoizer" in _args:
62    import SCons.Memoize
63    import SCons.Warnings
64    try:
65        SCons.Memoize.EnableMemoization()
66    except SCons.Warnings.Warning:
67        # Some warning was thrown.  Arrange for it to be displayed
68        # or not after warnings are configured.
69        import Main
70        exc_type, exc_value, tb = sys.exc_info()
71        Main.delayed_warnings.append((exc_type, exc_value))
72del _args
73
74import SCons.Action
75import SCons.Builder
76import SCons.Environment
77import SCons.Node.FS
78import SCons.Options
79import SCons.Platform
80import SCons.Scanner
81import SCons.SConf
82import SCons.Subst
83import SCons.Tool
84import SCons.Util
85import SCons.Variables
86import SCons.Defaults
87
88import Main
89
90main                    = Main.main
91
92# The following are global class definitions and variables that used to
93# live directly in this module back before 0.96.90, when it contained
94# a lot of code.  Some SConscript files in widely-distributed packages
95# (Blender is the specific example) actually reached into SCons.Script
96# directly to use some of these.  Rather than break those SConscript
97# files, we're going to propagate these names into the SCons.Script
98# namespace here.
99#
100# Some of these are commented out because it's *really* unlikely anyone
101# used them, but we're going to leave the comment here to try to make
102# it obvious what to do if the situation arises.
103BuildTask               = Main.BuildTask
104CleanTask               = Main.CleanTask
105QuestionTask            = Main.QuestionTask
106#PrintHelp               = Main.PrintHelp
107#SConscriptSettableOptions = Main.SConscriptSettableOptions
108
109AddOption               = Main.AddOption
110GetOption               = Main.GetOption
111SetOption               = Main.SetOption
112Progress                = Main.Progress
113GetBuildFailures        = Main.GetBuildFailures
114
115#keep_going_on_error     = Main.keep_going_on_error
116#print_dtree             = Main.print_dtree
117#print_explanations      = Main.print_explanations
118#print_includes          = Main.print_includes
119#print_objects           = Main.print_objects
120#print_time              = Main.print_time
121#print_tree              = Main.print_tree
122#memory_stats            = Main.memory_stats
123#ignore_errors           = Main.ignore_errors
124#sconscript_time         = Main.sconscript_time
125#command_time            = Main.command_time
126#exit_status             = Main.exit_status
127#profiling               = Main.profiling
128#repositories            = Main.repositories
129
130#
131import SConscript
132_SConscript = SConscript
133
134call_stack              = _SConscript.call_stack
135
136#
137Action                  = SCons.Action.Action
138AddMethod               = SCons.Util.AddMethod
139AllowSubstExceptions    = SCons.Subst.SetAllowableExceptions
140Builder                 = SCons.Builder.Builder
141Configure               = _SConscript.Configure
142Environment             = SCons.Environment.Environment
143#OptParser               = SCons.SConsOptions.OptParser
144FindPathDirs            = SCons.Scanner.FindPathDirs
145Platform                = SCons.Platform.Platform
146Return                  = _SConscript.Return
147Scanner                 = SCons.Scanner.Base
148Tool                    = SCons.Tool.Tool
149WhereIs                 = SCons.Util.WhereIs
150
151#
152BoolVariable            = SCons.Variables.BoolVariable
153EnumVariable            = SCons.Variables.EnumVariable
154ListVariable            = SCons.Variables.ListVariable
155PackageVariable         = SCons.Variables.PackageVariable
156PathVariable            = SCons.Variables.PathVariable
157
158# Deprecated names that will go away some day.
159BoolOption              = SCons.Options.BoolOption
160EnumOption              = SCons.Options.EnumOption
161ListOption              = SCons.Options.ListOption
162PackageOption           = SCons.Options.PackageOption
163PathOption              = SCons.Options.PathOption
164
165# Action factories.
166Chmod                   = SCons.Defaults.Chmod
167Copy                    = SCons.Defaults.Copy
168Delete                  = SCons.Defaults.Delete
169Mkdir                   = SCons.Defaults.Mkdir
170Move                    = SCons.Defaults.Move
171Touch                   = SCons.Defaults.Touch
172
173# Pre-made, public scanners.
174CScanner                = SCons.Tool.CScanner
175DirScanner              = SCons.Defaults.DirScanner
176ProgramScanner          = SCons.Tool.ProgramScanner
177SourceFileScanner       = SCons.Tool.SourceFileScanner
178
179# Functions we might still convert to Environment methods.
180CScan                   = SCons.Defaults.CScan
181DefaultEnvironment      = SCons.Defaults.DefaultEnvironment
182
183# Other variables we provide.
184class TargetList(collections.UserList):
185    def _do_nothing(self, *args, **kw):
186        pass
187    def _add_Default(self, list):
188        self.extend(list)
189    def _clear(self):
190        del self[:]
191
192ARGUMENTS               = {}
193ARGLIST                 = []
194BUILD_TARGETS           = TargetList()
195COMMAND_LINE_TARGETS    = []
196DEFAULT_TARGETS         = []
197
198# BUILD_TARGETS can be modified in the SConscript files.  If so, we
199# want to treat the modified BUILD_TARGETS list as if they specified
200# targets on the command line.  To do that, though, we need to know if
201# BUILD_TARGETS was modified through "official" APIs or by hand.  We do
202# this by updating two lists in parallel, the documented BUILD_TARGETS
203# list, above, and this internal _build_plus_default targets list which
204# should only have "official" API changes.  Then Script/Main.py can
205# compare these two afterwards to figure out if the user added their
206# own targets to BUILD_TARGETS.
207_build_plus_default = TargetList()
208
209def _Add_Arguments(alist):
210    for arg in alist:
211        a, b = arg.split('=', 1)
212        ARGUMENTS[a] = b
213        ARGLIST.append((a, b))
214
215def _Add_Targets(tlist):
216    if tlist:
217        COMMAND_LINE_TARGETS.extend(tlist)
218        BUILD_TARGETS.extend(tlist)
219        BUILD_TARGETS._add_Default = BUILD_TARGETS._do_nothing
220        BUILD_TARGETS._clear = BUILD_TARGETS._do_nothing
221        _build_plus_default.extend(tlist)
222        _build_plus_default._add_Default = _build_plus_default._do_nothing
223        _build_plus_default._clear = _build_plus_default._do_nothing
224
225def _Set_Default_Targets_Has_Been_Called(d, fs):
226    return DEFAULT_TARGETS
227
228def _Set_Default_Targets_Has_Not_Been_Called(d, fs):
229    if d is None:
230        d = [fs.Dir('.')]
231    return d
232
233_Get_Default_Targets = _Set_Default_Targets_Has_Not_Been_Called
234
235def _Set_Default_Targets(env, tlist):
236    global DEFAULT_TARGETS
237    global _Get_Default_Targets
238    _Get_Default_Targets = _Set_Default_Targets_Has_Been_Called
239    for t in tlist:
240        if t is None:
241            # Delete the elements from the list in-place, don't
242            # reassign an empty list to DEFAULT_TARGETS, so that the
243            # variables will still point to the same object we point to.
244            del DEFAULT_TARGETS[:]
245            BUILD_TARGETS._clear()
246            _build_plus_default._clear()
247        elif isinstance(t, SCons.Node.Node):
248            DEFAULT_TARGETS.append(t)
249            BUILD_TARGETS._add_Default([t])
250            _build_plus_default._add_Default([t])
251        else:
252            nodes = env.arg2nodes(t, env.fs.Entry)
253            DEFAULT_TARGETS.extend(nodes)
254            BUILD_TARGETS._add_Default(nodes)
255            _build_plus_default._add_Default(nodes)
256
257#
258help_text = None
259
260def HelpFunction(text):
261    global help_text
262    if SCons.Script.help_text is None:
263        SCons.Script.help_text = text
264    else:
265        help_text = help_text + text
266
267#
268# Will be non-zero if we are reading an SConscript file.
269sconscript_reading = 0
270
271#
272def Variables(files=[], args=ARGUMENTS):
273    return SCons.Variables.Variables(files, args)
274
275def Options(files=[], args=ARGUMENTS):
276    return SCons.Options.Options(files, args)
277
278# The list of global functions to add to the SConscript name space
279# that end up calling corresponding methods or Builders in the
280# DefaultEnvironment().
281GlobalDefaultEnvironmentFunctions = [
282    # Methods from the SConsEnvironment class, above.
283    'Default',
284    'EnsurePythonVersion',
285    'EnsureSConsVersion',
286    'Exit',
287    'Export',
288    'GetLaunchDir',
289    'Help',
290    'Import',
291    #'SConscript', is handled separately, below.
292    'SConscriptChdir',
293
294    # Methods from the Environment.Base class.
295    'AddPostAction',
296    'AddPreAction',
297    'Alias',
298    'AlwaysBuild',
299    'BuildDir',
300    'CacheDir',
301    'Clean',
302    #The Command() method is handled separately, below.
303    'Decider',
304    'Depends',
305    'Dir',
306    'NoClean',
307    'NoCache',
308    'Entry',
309    'Execute',
310    'File',
311    'FindFile',
312    'FindInstalledFiles',
313    'FindSourceFiles',
314    'Flatten',
315    'GetBuildPath',
316    'Glob',
317    'Ignore',
318    'Install',
319    'InstallAs',
320    'Literal',
321    'Local',
322    'ParseDepends',
323    'Precious',
324    'Repository',
325    'Requires',
326    'SConsignFile',
327    'SideEffect',
328    'SourceCode',
329    'SourceSignatures',
330    'Split',
331    'Tag',
332    'TargetSignatures',
333    'Value',
334    'VariantDir',
335]
336
337GlobalDefaultBuilders = [
338    # Supported builders.
339    'CFile',
340    'CXXFile',
341    'DVI',
342    'Jar',
343    'Java',
344    'JavaH',
345    'Library',
346    'M4',
347    'MSVSProject',
348    'Object',
349    'PCH',
350    'PDF',
351    'PostScript',
352    'Program',
353    'RES',
354    'RMIC',
355    'SharedLibrary',
356    'SharedObject',
357    'StaticLibrary',
358    'StaticObject',
359    'Tar',
360    'TypeLibrary',
361    'Zip',
362    'Package',
363]
364
365for name in GlobalDefaultEnvironmentFunctions + GlobalDefaultBuilders:
366    exec "%s = _SConscript.DefaultEnvironmentCall(%s)" % (name, repr(name))
367del name
368
369# There are a handful of variables that used to live in the
370# Script/SConscript.py module that some SConscript files out there were
371# accessing directly as SCons.Script.SConscript.*.  The problem is that
372# "SConscript" in this namespace is no longer a module, it's a global
373# function call--or more precisely, an object that implements a global
374# function call through the default Environment.  Nevertheless, we can
375# maintain backwards compatibility for SConscripts that were reaching in
376# this way by hanging some attributes off the "SConscript" object here.
377SConscript = _SConscript.DefaultEnvironmentCall('SConscript')
378
379# Make SConscript look enough like the module it used to be so
380# that pychecker doesn't barf.
381SConscript.__name__ = 'SConscript'
382
383SConscript.Arguments = ARGUMENTS
384SConscript.ArgList = ARGLIST
385SConscript.BuildTargets = BUILD_TARGETS
386SConscript.CommandLineTargets = COMMAND_LINE_TARGETS
387SConscript.DefaultTargets = DEFAULT_TARGETS
388
389# The global Command() function must be handled differently than the
390# global functions for other construction environment methods because
391# we want people to be able to use Actions that must expand $TARGET
392# and $SOURCE later, when (and if) the Action is invoked to build
393# the target(s).  We do this with the subst=1 argument, which creates
394# a DefaultEnvironmentCall instance that wraps up a normal default
395# construction environment that performs variable substitution, not a
396# proxy that doesn't.
397#
398# There's a flaw here, though, because any other $-variables on a command
399# line will *also* be expanded, each to a null string, but that should
400# only be a problem in the unusual case where someone was passing a '$'
401# on a command line and *expected* the $ to get through to the shell
402# because they were calling Command() and not env.Command()...  This is
403# unlikely enough that we're going to leave this as is and cross that
404# bridge if someone actually comes to it.
405Command = _SConscript.DefaultEnvironmentCall('Command', subst=1)
406
407# Local Variables:
408# tab-width:4
409# indent-tabs-mode:nil
410# End:
411# vim: set expandtab tabstop=4 shiftwidth=4:
412