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