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