Merged revisions 1826-1882 via svnmerge from
[scons.git] / src / engine / SCons / Script / __init__.py
1 """SCons.Script
2
3 This file implements the main() function used by the scons script.
4
5 Architecturally, this *is* the scons script, and will likely only be
6 called from the external "scons" wrapper.  Consequently, anything here
7 should not be, or be considered, part of the build engine.  If it's
8 something that we expect other software to want to use, it should go in
9 some other module.  If it's specific to the "scons" script invocation,
10 it goes here.
11
12 """
13
14 #
15 # __COPYRIGHT__
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__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
38
39 import time
40 start_time = time.time()
41
42 import os
43 import string
44 import sys
45 import UserList
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 + string.split(os.environ.get('SCONSFLAGS', ''))
62 if "--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 (inability to --debug=memoizer on
69         # Python 1.5.2 because it doesn't have metaclasses).  Arrange
70         # for it to be displayed or not after warnings are configured.
71         import Main
72         exc_type, exc_value, tb = sys.exc_info()
73         Main.delayed_warnings.append(exc_type, exc_value)
74 del _args
75
76 import SCons.Action
77 import SCons.Builder
78 import SCons.Environment
79 import SCons.Node.FS
80 import SCons.Options
81 import SCons.Platform
82 import SCons.Scanner
83 import SCons.SConf
84 import SCons.Subst
85 import SCons.Tool
86 import SCons.Util
87 import SCons.Defaults
88
89 import Main
90
91 main                    = 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.
104 BuildTask               = Main.BuildTask
105 CleanTask               = Main.CleanTask
106 QuestionTask            = Main.QuestionTask
107 #PrintHelp               = Main.PrintHelp
108 OptParser               = Main.OptParser
109 SConscriptSettableOptions = Main.SConscriptSettableOptions
110
111 keep_going_on_error     = Main.keep_going_on_error
112 #print_dtree             = Main.print_dtree
113 print_explanations      = Main.print_explanations
114 print_includes          = Main.print_includes
115 print_objects           = Main.print_objects
116 print_time              = Main.print_time
117 #print_tree              = Main.print_tree
118 memory_stats            = Main.memory_stats
119 ignore_errors           = Main.ignore_errors
120 #sconscript_time         = Main.sconscript_time
121 #command_time            = Main.command_time
122 #exit_status             = Main.exit_status
123 #profiling               = Main.profiling
124 repositories            = Main.repositories
125
126 #
127 import SConscript
128 _SConscript = SConscript
129
130 call_stack              = _SConscript.call_stack
131
132 #
133 Action                  = SCons.Action.Action
134 AllowSubstExceptions    = SCons.Subst.SetAllowableExceptions
135 BoolOption              = SCons.Options.BoolOption
136 Builder                 = SCons.Builder.Builder
137 Configure               = _SConscript.Configure
138 EnumOption              = SCons.Options.EnumOption
139 Environment             = SCons.Environment.Environment
140 FindPathDirs            = SCons.Scanner.FindPathDirs
141 ListOption              = SCons.Options.ListOption
142 PackageOption           = SCons.Options.PackageOption
143 PathOption              = SCons.Options.PathOption
144 Platform                = SCons.Platform.Platform
145 Return                  = _SConscript.Return
146 Scanner                 = SCons.Scanner.Base
147 Tool                    = SCons.Tool.Tool
148 WhereIs                 = SCons.Util.WhereIs
149
150 # Action factories.
151 Chmod                   = SCons.Defaults.Chmod
152 Copy                    = SCons.Defaults.Copy
153 Delete                  = SCons.Defaults.Delete
154 Mkdir                   = SCons.Defaults.Mkdir
155 Move                    = SCons.Defaults.Move
156 Touch                   = SCons.Defaults.Touch
157
158 # Pre-made, public scanners.
159 CScanner                = SCons.Tool.CScanner
160 DScanner                = SCons.Tool.DScanner
161 DirScanner              = SCons.Defaults.DirScanner
162 ProgramScanner          = SCons.Tool.ProgramScanner
163 SourceFileScanner       = SCons.Tool.SourceFileScanner
164
165 # Functions we might still convert to Environment methods.
166 CScan                   = SCons.Defaults.CScan
167 DefaultEnvironment      = SCons.Defaults.DefaultEnvironment
168
169 # Other variables we provide.
170 class TargetList(UserList.UserList):
171     def _do_nothing(self, *args, **kw):
172         pass
173     def _add_Default(self, list):
174         self.extend(list)
175     def _clear(self):
176         del self[:]
177
178 ARGUMENTS               = {}
179 ARGLIST                 = []
180 BUILD_TARGETS           = TargetList()
181 COMMAND_LINE_TARGETS    = []
182 DEFAULT_TARGETS         = []
183
184 # BUILD_TARGETS can be modified in the SConscript files.  If so, we
185 # want to treat the modified BUILD_TARGETS list as if they specified
186 # targets on the command line.  To do that, though, we need to know if
187 # BUILD_TARGETS was modified through "official" APIs or by hand.  We do
188 # this by updating two lists in parallel, the documented BUILD_TARGETS
189 # list, above, and this internal _build_plus_default targets list which
190 # should only have "official" API changes.  Then Script/Main.py can
191 # compare these two afterwards to figure out if the user added their
192 # own targets to BUILD_TARGETS.
193 _build_plus_default = TargetList()
194
195 def _Add_Arguments(alist):
196     for arg in alist:
197         a, b = string.split(arg, '=', 1)
198         ARGUMENTS[a] = b
199         ARGLIST.append((a, b))
200
201 def _Add_Targets(tlist):
202     if tlist:
203         COMMAND_LINE_TARGETS.extend(tlist)
204         BUILD_TARGETS.extend(tlist)
205         BUILD_TARGETS._add_Default = BUILD_TARGETS._do_nothing
206         BUILD_TARGETS._clear = BUILD_TARGETS._do_nothing
207         _build_plus_default.extend(tlist)
208         _build_plus_default._add_Default = _build_plus_default._do_nothing
209         _build_plus_default._clear = _build_plus_default._do_nothing
210
211 def _Set_Default_Targets_Has_Been_Called(d, fs):
212     return DEFAULT_TARGETS
213
214 def _Set_Default_Targets_Has_Not_Been_Called(d, fs):
215     if d is None:
216         d = [fs.Dir('.')]
217     return d
218
219 _Get_Default_Targets = _Set_Default_Targets_Has_Not_Been_Called
220
221 def _Set_Default_Targets(env, tlist):
222     global DEFAULT_TARGETS
223     global _Get_Default_Targets
224     _Get_Default_Targets = _Set_Default_Targets_Has_Been_Called
225     for t in tlist:
226         if t is None:
227             # Delete the elements from the list in-place, don't
228             # reassign an empty list to DEFAULT_TARGETS, so that the
229             # variables will still point to the same object we point to.
230             del DEFAULT_TARGETS[:]
231             BUILD_TARGETS._clear()
232             _build_plus_default._clear()
233         elif isinstance(t, SCons.Node.Node):
234             DEFAULT_TARGETS.append(t)
235             BUILD_TARGETS._add_Default([t])
236             _build_plus_default._add_Default([t])
237         else:
238             nodes = env.arg2nodes(t, env.fs.Entry)
239             DEFAULT_TARGETS.extend(nodes)
240             BUILD_TARGETS._add_Default(nodes)
241             _build_plus_default._add_Default(nodes)
242
243 #
244 help_text = None
245
246 def HelpFunction(text):
247     global help_text
248     if SCons.Script.help_text is None:
249         SCons.Script.help_text = text
250     else:
251         help_text = help_text + text
252
253 #
254 # Will be non-zero if we are reading an SConscript file.
255 sconscript_reading = 0
256
257 #
258 def Options(files=None, args=ARGUMENTS):
259     return SCons.Options.Options(files, args)
260
261 # The list of global functions to add to the SConscript name space
262 # that end up calling corresponding methods or Builders in the
263 # DefaultEnvironment().
264 GlobalDefaultEnvironmentFunctions = [
265     # Methods from the SConsEnvironment class, above.
266     'Default',
267     'EnsurePythonVersion',
268     'EnsureSConsVersion',
269     'Exit',
270     'Export',
271     'GetLaunchDir',
272     'GetOption',
273     'Help',
274     'Import',
275     #'SConscript', is handled separately, below.
276     'SConscriptChdir',
277     'SetOption',
278
279     # Methods from the Environment.Base class.
280     'AddPostAction',
281     'AddPreAction',
282     'Alias',
283     'AlwaysBuild',
284     'BuildDir',
285     'CacheDir',
286     'Clean',
287     #The Command() method is handled separately, below.
288     'Depends',
289     'Dir',
290     'NoClean',
291     'NoCache',
292     'Entry',
293     'Execute',
294     'File',
295     'FindFile',
296     'Flatten',
297     'GetBuildPath',
298     'Ignore',
299     'Install',
300     'InstallAs',
301     'Literal',
302     'Local',
303     'ParseDepends',
304     'Precious',
305     'Repository',
306     'SConsignFile',
307     'SideEffect',
308     'SourceCode',
309     'SourceSignatures',
310     'Split',
311     'TargetSignatures',
312     'Value',
313 ]
314
315 GlobalDefaultBuilders = [
316     # Supported builders.
317     'CFile',
318     'CXXFile',
319     'DVI',
320     'Jar',
321     'Java',
322     'JavaH',
323     'Library',
324     'M4',
325     'MSVSProject',
326     'Object',
327     'PCH',
328     'PDF',
329     'PostScript',
330     'Program',
331     'RES',
332     'RMIC',
333     'SharedLibrary',
334     'SharedObject',
335     'StaticLibrary',
336     'StaticObject',
337     'Tar',
338     'TypeLibrary',
339     'Zip',
340 ]
341
342 for name in GlobalDefaultEnvironmentFunctions + GlobalDefaultBuilders:
343     exec "%s = _SConscript.DefaultEnvironmentCall(%s)" % (name, repr(name))
344 del name
345
346 # There are a handful of variables that used to live in the
347 # Script/SConscript.py module that some SConscript files out there were
348 # accessing directly as SCons.Script.SConscript.*.  The problem is that
349 # "SConscript" in this namespace is no longer a module, it's a global
350 # function call--or more precisely, an object that implements a global
351 # function call through the default Environment.  Nevertheless, we can
352 # maintain backwards compatibility for SConscripts that were reaching in
353 # this way by hanging some attributes off the "SConscript" object here.
354 SConscript = _SConscript.DefaultEnvironmentCall('SConscript')
355
356 # Make SConscript look enough like the module it used to be so
357 # that pychecker doesn't barf.
358 SConscript.__name__ = 'SConscript'
359
360 SConscript.Arguments = ARGUMENTS
361 SConscript.ArgList = ARGLIST
362 SConscript.BuildTargets = BUILD_TARGETS
363 SConscript.CommandLineTargets = COMMAND_LINE_TARGETS
364 SConscript.DefaultTargets = DEFAULT_TARGETS
365
366 # The global Command() function must be handled differently than the
367 # global functions for other construction environment methods because
368 # we want people to be able to use Actions that must expand $TARGET
369 # and $SOURCE later, when (and if) the Action is invoked to build
370 # the target(s).  We do this with the subst=1 argument, which creates
371 # a DefaultEnvironmentCall instance that wraps up a normal default
372 # construction environment that performs variable substitution, not a
373 # proxy that doesn't.
374 #
375 # There's a flaw here, though, because any other $-variables on a command
376 # line will *also* be expanded, each to a null string, but that should
377 # only be a problem in the unusual case where someone was passing a '$'
378 # on a command line and *expected* the $ to get through to the shell
379 # because they were calling Command() and not env.Command()...  This is
380 # unlikely enough that we're going to leave this as is and cross that
381 # bridge if someone actually comes to it.
382 Command = _SConscript.DefaultEnvironmentCall('Command', subst=1)