161
282
sys.stderr.write(line+'\n')
285
def find_deepest_user_frame(tb):
287
Find the deepest stack frame that is not part of SCons.
289
Input is a "pre-processed" stack trace in the form
290
returned by traceback.extract_tb() or traceback.extract_stack()
295
# find the deepest traceback frame that is not part
299
if string.find(filename, os.sep+'SCons'+os.sep) == -1:
164
303
def _scons_user_error(e):
165
304
"""Handle user errors. Print out a message and a description of the
166
error, along with the line number and routine where it occured.
305
error, along with the line number and routine where it occured.
306
The file and line number will be the deepest stack frame that is
307
not part of SCons itself.
168
309
etype, value, tb = sys.exc_info()
169
while tb.tb_next is not None:
171
lineno = traceback.tb_lineno(tb)
172
filename = tb.tb_frame.f_code.co_filename
173
routine = tb.tb_frame.f_code.co_name
174
sys.stderr.write("\nSCons error: %s\n" % value)
310
filename, lineno, routine, dummy = find_deepest_user_frame(traceback.extract_tb(tb))
311
sys.stderr.write("\nscons: *** %s\n" % value)
175
312
sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine))
178
315
def _scons_user_warning(e):
179
316
"""Handle user warnings. Print out a message and a description of
180
317
the warning, along with the line number and routine where it occured.
318
The file and line number will be the deepest stack frame that is
319
not part of SCons itself.
182
321
etype, value, tb = sys.exc_info()
183
while tb.tb_next is not None:
185
lineno = traceback.tb_lineno(tb)
186
filename = tb.tb_frame.f_code.co_filename
187
routine = tb.tb_frame.f_code.co_name
188
sys.stderr.write("\nSCons warning: %s\n" % e)
189
sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine))
191
def _scons_other_errors():
322
filename, lineno, routine, dummy = find_deepest_user_frame(traceback.extract_tb(tb))
323
sys.stderr.write("\nscons: warning: %s\n" % e)
324
sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine))
326
def _scons_internal_warning(e):
327
"""Slightly different from _scons_user_warning in that we use the
328
*current call stack* rather than sys.exc_info() to get our stack trace.
329
This is used by the warnings framework to print warnings."""
330
filename, lineno, routine, dummy = find_deepest_user_frame(traceback.extract_stack())
331
sys.stderr.write("\nscons: warning: %s\n" % e[0])
332
sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine))
334
def _scons_internal_error():
192
335
"""Handle all errors but user errors. Print out a message telling
193
336
the user what to do in this case and print a normal trace.
338
print 'internal error'
196
339
traceback.print_exc()
201
# After options are initialized, the following variables are
204
option_list = [] # list of Option objects
205
short_opts = "" # string of short (single-character) options
206
long_opts = [] # array of long (--) options
207
opt_func = {} # mapping of option strings to functions
210
"""Initialize command-line options processing.
212
This is in a subroutine mainly so we can easily single-step over
217
"""Class for command-line option information.
219
This exists to provide a central location for everything
220
describing a command-line option, so that we can change
221
options without having to update the code to handle the
222
option in one place, the -h help message in another place,
223
etc. There are no methods here, only attributes.
225
You can initialize an Option with the following:
227
func The function that will be called when this
228
option is processed on the command line.
233
If there is no func, then this Option probably
234
stores an optstring to be printed.
237
The string to be printed in -h output. If no
238
helpline is specified but a help string is
239
specified (the usual case), a helpline will be
240
constructed automatically from the short, long,
241
arg, and help attributes. (In practice, then,
242
setting helpline without setting func allows you
243
to print arbitrary lines of text in the -h
246
short The string for short, single-hyphen
247
command-line options.
248
Do not include the hyphen:
250
'a' for -a, 'xy' for -x and -y, etc.
252
long An array of strings for long, double-hyphen
253
command-line options. Do not include
256
['my-option', 'verbose']
258
arg If this option takes an argument, this string
259
specifies how you want it to appear in the
260
-h output ('DIRECTORY', 'FILE', etc.).
262
help The help string that will be printed for
263
this option in the -h output. Must be
264
49 characters or fewer.
266
future If non-zero, this indicates that this feature
267
will be supported in a future release, not
268
the currently planned one. SCons will
269
recognize the option, but it won't show up
272
The following attribute is derived from the supplied attributes:
275
A string, with hyphens, describing the flags
276
for this option, as constructed from the
277
specified short, long and arg attributes.
279
All Option objects are stored in the global option_list list,
280
in the order in which they're created. This is the list
281
that's used to generate -h output, so the order in which the
282
objects are created is the order in which they're printed.
284
The upshot is that specifying a command-line option and having
285
everything work correctly is a matter of defining a function to
286
process its command-line argument (set the right flag, update
287
the right value), and then creating an appropriate Option object
288
at the correct point in the code below.
291
def __init__(self, func = None, helpline = None,
292
short = None, long = None, arg = None,
293
help = None, future = None):
304
opts = opts + ['-' + c]
308
l = map(lambda x,a=arg: x + "=" + a, self.long)
309
opts = opts + map(lambda x: '--' + x, l)
310
self.optstring = string.join(opts, ', ')
312
self.helpline = helpline
313
elif help and not future:
314
if len(self.optstring) <= 26:
315
sep = " " * (28 - len(self.optstring))
317
sep = self.helpstring = "\n" + " " * 30
318
self.helpline = " " + self.optstring + sep + self.help
322
option_list.append(self)
324
# Generic routine for to-be-written options, used by multiple
327
def opt_not_yet(opt, arg):
328
sys.stderr.write("Warning: the %s option is not yet implemented\n"
331
# In the following instantiations, the help string should be no
332
# longer than 49 characters. Use the following as a guide:
333
# help = "1234567890123456789012345678901234567890123456789"
335
def opt_ignore(opt, arg):
336
sys.stderr.write("Warning: ignoring %s option\n" % opt)
338
Option(func = opt_ignore,
339
short = 'bmSt', long = ['no-keep-going', 'stop', 'touch'],
340
help = "Ignored for compatibility.")
343
global task_class, calc
344
task_class = CleanTask
345
class CleanCalculator:
346
def bsig(self, node):
348
def csig(self, node):
350
def current(self, node, sig):
354
calc = CleanCalculator()
357
short = 'c', long = ['clean', 'remove'],
358
help = "Remove specified targets and dependencies.")
360
Option(func = opt_not_yet, future = 1,
361
long = ['cache-disable', 'no-cache'],
362
help = "Do not retrieve built targets from Cache.")
364
Option(func = opt_not_yet, future = 1,
365
long = ['cache-force', 'cache-populate'],
366
help = "Copy already-built targets into the Cache.")
368
Option(func = opt_not_yet, future = 1,
369
long = ['cache-show'],
370
help = "Print what would have built Cached targets.")
376
sys.stderr.write("Could not change directory to 'arg'\n")
379
short = 'C', long = ['directory'], arg = 'DIRECTORY',
380
help = "Change to DIRECTORY before doing anything.")
382
Option(func = opt_not_yet,
384
help = "Print file dependency information.")
386
def opt_debug(opt, arg):
389
args = [ sys.executable, "pdb.py" ] + \
390
filter(lambda x: x != "--debug=pdb", sys.argv)
391
if sys.platform == 'win32':
392
args[1] = os.path.join(sys.exec_prefix, "lib", "pdb.py")
393
sys.exit(os.spawnve(os.P_WAIT, args[0], args, os.environ))
342
def _varargs(option, parser):
345
arg = parser.rargs[0]
351
def _setup_warn(arg):
352
"""The --warn option. An argument to this option
353
should be of the form <warning-class> or no-<warning-class>.
354
The warning class is munged in order to get an actual class
355
name from the SCons.Warnings module to enable or disable.
356
The supplied <warning-class> is split on hyphens, each element
357
is captialized, then smushed back together. Then the string
358
"SCons.Warnings." is added to the front and "Warning" is added
359
to the back to get the fully qualified class name.
361
For example, --warn=deprecated will enable the
362
SCons.Warnings.DeprecatedWarning class.
364
--warn=no-dependency will disable the
365
SCons.Warnings.DependencyWarning class.
367
As a special case, --warn=all and --warn=no-all
368
will enable or disable (respectively) the base
369
class of all warnings, which is SCons.Warning.Warning."""
371
elems = string.split(string.lower(arg), '-')
377
if len(elems) == 1 and elems[0] == 'all':
378
class_name = "Warning"
382
return "SCons" + s[5:]
395
args[1] = os.path.join(sys.exec_prefix,
397
"python" + sys.version[0:3],
399
os.execvpe(args[0], args, os.environ)
384
return string.capitalize(s)
385
class_name = string.join(map(_capitalize, elems), '') + "Warning"
387
clazz = getattr(SCons.Warnings, class_name)
388
except AttributeError:
389
sys.stderr.write("No warning type: '%s'\n" % arg)
392
SCons.Warnings.enableWarningClass(clazz)
403
sys.stderr.write("Warning: %s is not a valid debug type\n"
406
Option(func = opt_debug,
407
long = ['debug'], arg='TYPE',
408
help = "Print various types of debugging information.")
410
Option(func = opt_not_yet, future = 1,
411
short = 'e', long = ['environment-overrides'],
412
help = "Environment variables override makefiles.")
419
short = 'f', long = ['file', 'makefile', 'sconstruct'], arg = 'FILE',
420
help = "Read FILE as the top-level SConstruct file.")
422
def opt_help(opt, arg):
425
SCons.Script.SConscript.print_help = 1
427
Option(func = opt_help,
428
short = 'h', long = ['help'],
429
help = "Print defined help message, or this one.")
431
def opt_help_options(opt, arg):
435
Option(func = opt_help_options,
436
short = 'H', long = ['help-options'],
437
help = "Print this message and exit.")
444
short = 'i', long = ['ignore-errors'],
445
help = "Ignore errors from build actions.")
449
include_dirs = include_dirs + [arg]
452
short = 'I', long = ['include-dir'], arg = 'DIRECTORY',
453
help = "Search DIRECTORY for imported Python modules.")
468
short = 'j', long = ['jobs'], arg = 'N',
469
help = "Allow N jobs at once.")
472
global keep_going_on_error
473
keep_going_on_error = 1
476
short = 'k', long = ['keep-going'],
477
help = "Keep going when a target can't be made.")
479
Option(func = opt_not_yet, future = 1,
480
short = 'l', long = ['load-average', 'max-load'], arg = 'N',
481
help = "Don't start multiple jobs unless load is below N.")
483
Option(func = opt_not_yet, future = 1,
484
long = ['list-derived'],
485
help = "Don't build; list files that would be built.")
487
Option(func = opt_not_yet, future = 1,
488
long = ['list-actions'],
489
help = "Don't build; list files and build actions.")
491
Option(func = opt_not_yet, future = 1,
492
long = ['list-where'],
493
help = "Don't build; list files and where defined.")
496
SCons.Action.execute_actions = None
499
short = 'n', long = ['no-exec', 'just-print', 'dry-run', 'recon'],
500
help = "Don't build; just print commands.")
502
Option(func = opt_not_yet, future = 1,
503
short = 'o', long = ['old-file', 'assume-old'], arg = 'FILE',
504
help = "Consider FILE to be old; don't rebuild it.")
506
Option(func = opt_not_yet, future = 1,
507
long = ['override'], arg = 'FILE',
508
help = "Override variables as specified in FILE.")
510
Option(func = opt_not_yet, future = 1,
512
help = "Print internal environments/objects.")
514
def opt_profile(opt, arg):
515
sys.argv = filter(lambda x: x[0:10] != "--profile=", sys.argv)
517
profile.run('SCons.Script.main()', arg)
519
Option(func = opt_profile,
520
long = ['profile'], arg = 'FILE',
521
help = "Profile SCons and put results in FILE.")
525
task_class = QuestionTask
527
Option(func = opt_q, future = 1,
528
short = 'q', long = ['question'],
529
help = "Don't build; exit status says if up to date.")
531
Option(func = opt_not_yet, future = 1,
532
short = 'rR', long = ['no-builtin-rules', 'no-builtin-variables'],
533
help = "Clear default environments and variables.")
535
Option(func = opt_not_yet, future = 1,
537
help = "Build dependencies in random order.")
540
SCons.Action.print_actions = None
543
short = 's', long = ['silent', 'quiet'],
544
help = "Don't print commands.")
551
short = 'u', long = ['up', 'search-up'],
552
help = "Search up directory tree for SConstruct.")
560
help = "Search up directory tree for SConstruct.")
562
def option_v(opt, arg):
564
print "SCons by Steven Knight et al.:"
565
print "\tscript version 0.06"
566
print "\tbuild engine version %s" % SCons.__version__
567
print "Copyright 2001, 2002 Steven Knight"
570
Option(func = option_v,
571
short = 'v', long = ['version'],
572
help = "Print the SCons version number and exit.")
574
Option(func = opt_not_yet, future = 1,
575
short = 'w', long = ['print-directory'],
576
help = "Print the current directory.")
578
Option(func = opt_not_yet, future = 1,
579
long = ['no-print-directory'],
580
help = "Turn off -w, even if it was turned on implicitly.")
582
Option(func = opt_not_yet, future = 1,
583
long = ['write-filenames'], arg = 'FILE',
584
help = "Write all filenames examined into FILE.")
586
Option(func = opt_not_yet, future = 1,
587
short = 'W', long = ['what-if', 'new-file', 'assume-new'], arg = 'FILE',
588
help = "Consider FILE to be changed.")
590
Option(func = opt_not_yet, future = 1,
591
long = ['warn-undefined-variables'],
592
help = "Warn when an undefined variable is referenced.")
594
Option(func = opt_not_yet, future = 1,
595
short = 'Y', long = ['repository'], arg = 'REPOSITORY',
596
help = "Search REPOSITORY for source and target files.")
601
for o in option_list:
605
opt_func['-' + c] = o.func
606
short_opts = short_opts + o.short
608
short_opts = short_opts + ":"
612
opt_func['--' + l] = o.func
614
long_opts = long_opts + map(lambda a: a + "=", o.long)
616
long_opts = long_opts + o.long
394
SCons.Warnings.suppressWarningClass(clazz)
622
396
def _SConstruct_exists(dirname=''):
623
397
"""This function checks that an SConstruct file exists in a directory.
624
398
If so, it returns the path of the file. By default, it checks the
625
399
current directory.
627
402
for file in ['SConstruct', 'Sconstruct', 'sconstruct']:
628
403
sfile = os.path.join(dirname, file)
629
404
if os.path.isfile(sfile):
406
if not os.path.isabs(sfile):
407
for rep in repositories:
408
if os.path.isfile(os.path.join(rep, sfile)):
635
help_opts = filter(lambda x: x.helpline, option_list)
636
s = "Usage: scons [OPTION] [TARGET] ...\n" + "Options:\n" + \
637
string.join(map(lambda x: x.helpline, help_opts), "\n") + "\n"
643
global scripts, num_jobs, task_class, calc, target_top
412
def _set_globals(options):
413
global repositories, keep_going_on_error, ignore_errors
414
global print_count, print_dtree
415
global print_explanations, print_includes
416
global print_objects, print_time, print_tree
417
global memory_outf, memory_stats
419
if options.repository:
420
repositories.extend(options.repository)
421
keep_going_on_error = options.keep_going
424
if options.debug == "count":
426
elif options.debug == "dtree":
428
elif options.debug == "explain":
429
print_explanations = 1
430
elif options.debug == "includes":
432
elif options.debug == "memory":
434
memory_outf = sys.stdout
435
elif options.debug == "objects":
437
elif options.debug == "presub":
438
SCons.Action.print_actions_presub = 1
439
elif options.debug == "time":
441
elif options.debug == "tree":
443
except AttributeError:
445
ignore_errors = options.ignore_errors
447
def _create_path(plist):
453
path = path + '/' + d
457
class OptParser(OptionParser):
461
parts = ["SCons by Steven Knight et al.:\n"]
463
parts.append("\tscript: v%s.%s, %s, by %s on %s\n" % (__main__.__version__,
466
__main__.__developer__,
467
__main__.__buildsys__))
468
except KeyboardInterrupt:
471
# On win32 there is no scons.py, so there is no __main__.__version__,
472
# hence there is no script version.
474
parts.append("\tengine: v%s.%s, %s, by %s on %s\n" % (SCons.__version__,
479
parts.append("Copyright (c) 2001, 2002, 2003, 2004 The SCons Foundation")
480
OptionParser.__init__(self, version=string.join(parts, ''),
481
usage="usage: scons [OPTION] [TARGET] ...")
483
# options ignored for compatibility
484
def opt_ignore(option, opt, value, parser):
485
sys.stderr.write("Warning: ignoring %s option\n" % opt)
486
self.add_option("-b", "-m", "-S", "-t", "--no-keep-going", "--stop",
487
"--touch", action="callback", callback=opt_ignore,
488
help="Ignored for compatibility.")
490
self.add_option('-c', '--clean', '--remove', action="store_true",
492
help="Remove specified targets and dependencies.")
494
self.add_option('-C', '--directory', type="string", action = "append",
496
help="Change to DIR before doing anything.")
498
self.add_option('--cache-disable', '--no-cache',
499
action="store_true", dest='cache_disable', default=0,
500
help="Do not retrieve built targets from CacheDir.")
502
self.add_option('--cache-force', '--cache-populate',
503
action="store_true", dest='cache_force', default=0,
504
help="Copy already-built targets into the CacheDir.")
506
self.add_option('--cache-show',
507
action="store_true", dest='cache_show', default=0,
508
help="Print build actions for files from CacheDir.")
510
def opt_not_yet(option, opt, value, parser):
511
sys.stderr.write("Warning: the %s option is not yet implemented\n" % opt)
513
self.add_option('-d', action="callback",
514
callback=opt_not_yet,
515
help = "Print file dependency information.")
517
self.add_option('-D', action="store_const", const=2, dest="climb_up",
518
help="Search up directory tree for SConstruct, "
519
"build all Default() targets.")
521
debug_options = ["count", "dtree", "explain",
522
"includes", "memory", "objects",
523
"pdb", "presub", "time", "tree"]
525
def opt_debug(option, opt, value, parser, debug_options=debug_options):
526
if value in debug_options:
527
parser.values.debug = value
529
raise OptionValueError("Warning: %s is not a valid debug type" % value)
530
self.add_option('--debug', action="callback", type="string",
531
callback=opt_debug, nargs=1, dest="debug",
533
help="Print various types of debugging information: "
534
"%s." % string.join(debug_options, ", "))
536
def opt_duplicate(option, opt, value, parser):
537
if not value in SCons.Node.FS.Valid_Duplicates:
538
raise OptionValueError("`%s' is not a valid duplication style." % value)
539
parser.values.duplicate = value
540
# Set the duplicate style right away so it can affect linking
541
# of SConscript files.
542
SCons.Node.FS.set_duplicate(value)
543
self.add_option('--duplicate', action="callback", type="string",
544
callback=opt_duplicate, nargs=1, dest="duplicate",
545
help="Set the preferred duplication methods. Must be one of "
546
+ string.join(SCons.Node.FS.Valid_Duplicates, ", "))
548
self.add_option('-f', '--file', '--makefile', '--sconstruct',
549
action="append", nargs=1,
550
help="Read FILE as the top-level SConstruct file.")
552
self.add_option('-h', '--help', action="store_true", default=0,
554
help="Print defined help message, or this one.")
556
self.add_option("-H", "--help-options",
558
help="Print this message and exit.")
560
self.add_option('-i', '--ignore-errors', action="store_true",
561
default=0, dest='ignore_errors',
562
help="Ignore errors from build actions.")
564
self.add_option('-I', '--include-dir', action="append",
565
dest='include_dir', metavar="DIR",
566
help="Search DIR for imported Python modules.")
568
self.add_option('--implicit-cache', action="store_true",
569
dest='implicit_cache',
570
help="Cache implicit dependencies")
572
self.add_option('--implicit-deps-changed', action="store_true",
573
default=0, dest='implicit_deps_changed',
574
help="Ignore cached implicit dependencies.")
575
self.add_option('--implicit-deps-unchanged', action="store_true",
576
default=0, dest='implicit_deps_unchanged',
577
help="Ignore changes in implicit dependencies.")
579
def opt_j(option, opt, value, parser):
581
parser.values.num_jobs = value
582
self.add_option('-j', '--jobs', action="callback", type="int",
583
callback=opt_j, metavar="N",
584
help="Allow N jobs at once.")
586
self.add_option('-k', '--keep-going', action="store_true", default=0,
588
help="Keep going when a target can't be made.")
590
self.add_option('--max-drift', type="int", action="store",
591
dest='max_drift', metavar="N",
592
help="Set maximum system clock drift to N seconds.")
594
self.add_option('-n', '--no-exec', '--just-print', '--dry-run',
595
'--recon', action="store_true", dest='noexec',
596
default=0, help="Don't build; just print commands.")
598
def opt_profile(option, opt, value, parser):
603
profile.run('SCons.Script.main()', value)
604
sys.exit(exit_status)
605
self.add_option('--profile', nargs=1, action="callback",
606
callback=opt_profile, type="string", dest="profile",
608
help="Profile SCons and put results in FILE.")
610
self.add_option('-q', '--question', action="store_true", default=0,
611
help="Don't build; exit status says if up to date.")
613
self.add_option('-Q', dest='no_progress', action="store_true",
615
help="Suppress \"Reading/Building\" progress messages.")
617
self.add_option('--random', dest="random", action="store_true",
618
default=0, help="Build dependencies in random order.")
620
self.add_option('-s', '--silent', '--quiet', action="store_true",
621
default=0, help="Don't print commands.")
623
self.add_option('-u', '--up', '--search-up', action="store_const",
624
dest="climb_up", default=0, const=1,
625
help="Search up directory tree for SConstruct, "
626
"build targets at or below current directory.")
627
self.add_option('-U', action="store_const", dest="climb_up",
629
help="Search up directory tree for SConstruct, "
630
"build Default() targets from local SConscript.")
632
self.add_option("-v", "--version",
634
help="Print the SCons version number and exit.")
636
self.add_option('--warn', '--warning', nargs=1, action="store",
637
metavar="WARNING-SPEC",
638
help="Enable or disable warnings.")
640
self.add_option('-Y', '--repository', nargs=1, action="append",
641
help="Search REPOSITORY for source and target files.")
643
self.add_option('-e', '--environment-overrides', action="callback",
644
callback=opt_not_yet,
645
# help="Environment variables override makefiles."
647
self.add_option('-l', '--load-average', '--max-load', action="callback",
648
callback=opt_not_yet, type="int", dest="load_average",
650
# help="Don't start multiple jobs unless load is below "
654
self.add_option('--list-derived', action="callback",
655
callback=opt_not_yet,
656
# help="Don't build; list files that would be built."
658
self.add_option('--list-actions', action="callback",
659
callback=opt_not_yet,
660
# help="Don't build; list files and build actions."
662
self.add_option('--list-where', action="callback",
663
callback=opt_not_yet,
664
# help="Don't build; list files and where defined."
666
self.add_option('-o', '--old-file', '--assume-old', action="callback",
667
callback=opt_not_yet, type="string", dest="old_file",
668
# help = "Consider FILE to be old; don't rebuild it."
670
self.add_option('--override', action="callback", dest="override",
671
callback=opt_not_yet, type="string",
672
# help="Override variables as specified in FILE."
674
self.add_option('-p', action="callback",
675
callback=opt_not_yet,
676
# help="Print internal environments/objects."
678
self.add_option('-r', '-R', '--no-builtin-rules',
679
'--no-builtin-variables', action="callback",
680
callback=opt_not_yet,
681
# help="Clear default environments and variables."
683
self.add_option('-w', '--print-directory', action="callback",
684
callback=opt_not_yet,
685
# help="Print the current directory."
687
self.add_option('--no-print-directory', action="callback",
688
callback=opt_not_yet,
689
# help="Turn off -w, even if it was turned on implicitly."
691
self.add_option('--write-filenames', action="callback",
692
callback=opt_not_yet, type="string", dest="write_filenames",
693
# help="Write all filenames examined into FILE."
695
self.add_option('-W', '--what-if', '--new-file', '--assume-new',
697
action="callback", callback=opt_not_yet, type="string",
698
# help="Consider FILE to be changed."
700
self.add_option('--warn-undefined-variables', action="callback",
701
callback=opt_not_yet,
702
# help="Warn when an undefined variable is referenced."
705
def parse_args(self, args=None, values=None):
706
opt, arglist = OptionParser.parse_args(self, args, values)
707
if opt.implicit_deps_changed or opt.implicit_deps_unchanged:
708
opt.implicit_cache = 1
711
class SConscriptSettableOptions:
712
"""This class wraps an OptParser instance and provides
713
uniform access to options that can be either set on the command
714
line or from a SConscript file. A value specified on the command
715
line always overrides a value set in a SConscript file.
716
Not all command line options are SConscript settable, and the ones
717
that are must be explicitly added to settable dictionary and optionally
718
validated and coerced in the set() method."""
720
def __init__(self, options):
721
self.options = options
723
# This dictionary stores the defaults for all the SConscript
724
# settable options, as well as indicating which options
725
# are SConscript settable.
726
self.settable = {'num_jobs':1,
727
'max_drift':SCons.Sig.default_max_drift,
730
'duplicate':'hard-soft-copy'}
733
if not self.settable.has_key(name):
734
raise SCons.Error.UserError, "This option is not settable from a SConscript file: %s"%name
735
if hasattr(self.options, name) and getattr(self.options, name) is not None:
736
return getattr(self.options, name)
738
return self.settable[name]
740
def set(self, name, value):
741
if not self.settable.has_key(name):
742
raise SCons.Error.UserError, "This option is not settable from a SConscript file: %s"%name
744
if name == 'num_jobs':
750
raise SCons.Errors.UserError, "A positive integer is required: %s"%repr(value)
751
elif name == 'max_drift':
755
raise SCons.Errors.UserError, "An integer is required: %s"%repr(value)
756
elif name == 'duplicate':
760
raise SCons.Errors.UserError, "A string is required: %s"%repr(value)
761
if not value in SCons.Node.FS.Valid_Duplicates:
762
raise SCons.Errors.UserError, "Not a valid duplication style: %s" % value
763
# Set the duplicate stye right away so it can affect linking
764
# of SConscript files.
765
SCons.Node.FS.set_duplicate(value)
767
self.settable[name] = value
770
def _main(args, parser):
647
# It looks like 2.0 changed the name of the exception class
650
getopt_err = getopt.GetoptError
652
getopt_err = getopt.error
655
cmd_opts, t = getopt.getopt(string.split(os.environ['SCONSFLAGS']),
656
short_opts, long_opts)
658
# It's all right if there's no SCONSFLAGS environment variable.
660
except getopt_err, x:
661
_scons_user_warning("SCONSFLAGS " + str(x))
663
for opt, arg in cmd_opts:
664
opt_func[opt](opt, arg)
667
cmd_opts, args = getopt.getopt(sys.argv[1:], short_opts, long_opts)
668
except getopt_err, x:
671
for opt, arg in cmd_opts:
672
opt_func[opt](opt, arg)
679
SCons.Script.SConscript._scons_add_args(xmit_args)
682
target_top = '' # directory to prepend to targets
772
fs = SCons.Node.FS.default_fs
774
# Enable deprecated warnings by default.
775
SCons.Warnings._warningOut = _scons_internal_warning
776
SCons.Warnings.enableWarningClass(SCons.Warnings.CorruptSConsignWarning)
777
SCons.Warnings.enableWarningClass(SCons.Warnings.DeprecatedWarning)
778
SCons.Warnings.enableWarningClass(SCons.Warnings.DuplicateEnvironmentWarning)
779
SCons.Warnings.enableWarningClass(SCons.Warnings.MissingSConscriptWarning)
780
SCons.Warnings.enableWarningClass(SCons.Warnings.NoParallelSupportWarning)
781
# This is good for newbies, and hopefully most everyone else too.
782
SCons.Warnings.enableWarningClass(SCons.Warnings.MisleadingKeywordsWarning)
785
ssoptions = SConscriptSettableOptions(options)
788
def raisePrintHelp(text):
789
raise PrintHelp, text
790
SCons.Script.SConscript.HelpFunction = raisePrintHelp
792
_set_globals(options)
793
SCons.Node.implicit_cache = options.implicit_cache
794
SCons.Node.implicit_deps_changed = options.implicit_deps_changed
795
SCons.Node.implicit_deps_unchanged = options.implicit_deps_unchanged
797
_setup_warn(options.warn)
799
SCons.SConf.dryrun = 1
800
SCons.Action.execute_actions = None
801
CleanTask.execute = CleanTask.show
803
SCons.SConf.dryrun = 1
805
if options.no_progress or options.silent:
806
progress_display.set_mode(0)
810
SCons.Action.print_actions = None
811
if options.cache_disable:
812
def disable(self): pass
813
fs.CacheDir = disable
814
if options.cache_force:
816
if options.cache_show:
818
if options.directory:
819
cdir = _create_path(options.directory)
823
sys.stderr.write("Could not change directory to %s\n" % cdir)
831
SCons.Script.SConscript._scons_add_args(xmit_args)
832
SCons.Script.SConscript._scons_add_targets(targets)
836
target_top = '.' # directory to prepend to targets
683
837
script_dir = os.getcwd() # location of script
684
838
while script_dir and not _SConstruct_exists(script_dir):
685
839
script_dir, last_part = os.path.split(script_dir)
726
887
sys.stdout = Unbuffered(sys.stdout)
728
sys.path = include_dirs + sys.path
730
for script in scripts:
731
SCons.Script.SConscript.SConscript(script)
733
SCons.Node.FS.default_fs.chdir(SCons.Node.FS.default_fs.Top)
735
if help_option == 'h':
736
# They specified -h, but there was no Help() inside the
737
# SConscript files. Give them the options usage.
742
if climb_up == 2 and not targets:
743
# -U with default targets
889
if options.include_dir:
890
sys.path = options.include_dir + sys.path
893
for rep in repositories:
896
if not memory_stats is None: memory_stats.append(SCons.Debug.memory())
898
progress_display("scons: Reading SConscript files ...")
900
start_time = time.time()
902
for script in scripts:
903
SCons.Script.SConscript._SConscript(fs, script)
904
except SCons.Errors.StopError, e:
905
# We had problems reading an SConscript file, such as it
906
# couldn't be copied in to the BuildDir. Since we're just
907
# reading SConscript files and haven't started building
908
# things yet, stop regardless of whether they used -i or -k
909
# or anything else, but don't say "Stop." on the message.
911
sys.stderr.write("scons: *** %s\n" % e)
913
sys.exit(exit_status)
914
global sconscript_time
915
sconscript_time = time.time() - start_time
916
except PrintHelp, text:
917
progress_display("scons: done reading SConscript files.")
919
print "Use scons -H for help about command-line options."
921
progress_display("scons: done reading SConscript files.")
923
# Tell the Node.FS subsystem that we're all done reading the
924
# SConscript files and calling Repository() and BuildDir() and the
925
# like, so it can go ahead and start memoizing the string values of
927
SCons.Node.FS.save_strings(1)
929
if not memory_stats is None: memory_stats.append(SCons.Debug.memory())
934
# They specified -h, but there was no Help() inside the
935
# SConscript files. Give them the options usage.
936
parser.print_help(sys.stdout)
939
# Now that we've read the SConscripts we can set the options
940
# that are SConscript settable:
941
SCons.Node.implicit_cache = ssoptions.get('implicit_cache')
942
SCons.Node.FS.set_duplicate(ssoptions.get('duplicate'))
946
# They specified targets on the command line, so if they
947
# used -u, -U or -D, we have to look up targets relative
948
# to the top, but we build whatever they specified.
950
lookup_top = fs.Dir(target_top)
744
951
target_top = None
953
# There are no targets specified on the command line,
954
# so if they used -u, -U or -D, we may have to restrict
955
# what actually gets built.
958
if options.climb_up == 1:
959
# -u, local directory and below
960
target_top = fs.Dir(target_top)
961
lookup_top = target_top
962
elif options.climb_up == 2:
963
# -D, all Default() targets
966
elif options.climb_up == 3:
967
# -U, local SConscript Default() targets
968
target_top = fs.Dir(target_top)
969
def check_dir(x, target_top=target_top):
970
if hasattr(x, 'cwd') and not x.cwd is None:
971
cwd = x.cwd.srcnode()
972
return cwd == target_top
974
# x doesn't have a cwd, so it's either not a target,
975
# or not a file, so go ahead and keep it as a default
976
# target and let the engine sort it out:
978
d = filter(check_dir, SCons.Script.SConscript.DefaultTargets)
979
SCons.Script.SConscript.DefaultTargets[:] = d
983
if SCons.Script.SConscript.DefaultCalled:
984
targets = SCons.Script.SConscript.DefaultTargets
746
target_top = SCons.Node.FS.default_fs.Dir(target_top)
749
targets = SCons.Script.SConscript.default_targets
992
sys.stderr.write("scons: *** No targets specified and no Default() targets found. Stop.\n")
751
def Entry(x, top = target_top):
995
def Entry(x, ltop=lookup_top, ttop=target_top, fs=fs):
752
996
if isinstance(x, SCons.Node.Node):
756
node = SCons.Node.Alias.default_ans.lookup(x)
758
node = SCons.Node.FS.default_fs.Entry(x,
762
string = "scons: *** Do not know how to make target `%s'." % x
763
if not keep_going_on_error:
764
sys.stderr.write(string + " Stop.\n")
766
sys.stderr.write(string + "\n")
768
if top and not node.is_under(top):
769
if isinstance(node, SCons.Node.FS.Dir) and top.is_under(node):
999
node = SCons.Node.Alias.default_ans.lookup(x)
1001
node = fs.Entry(x, directory=ltop, create=1)
1002
if ttop and not node.is_under(ttop):
1003
if isinstance(node, SCons.Node.FS.Dir) and ttop.is_under(node):
775
1009
nodes = filter(lambda x: x is not None, map(Entry, targets))
778
calc = SCons.Sig.Calculator(SCons.Sig.MD5)
780
taskmaster = SCons.Taskmaster.Taskmaster(nodes, task_class, calc)
782
jobs = SCons.Job.Jobs(num_jobs, taskmaster)
1011
task_class = BuildTask # default action is to build targets
1012
opening_message = "Building targets ..."
1013
closing_message = "done building targets."
1014
failure_message = "building terminated because of errors."
1015
if options.question:
1016
task_class = QuestionTask
1018
if ssoptions.get('clean'):
1019
task_class = CleanTask
1020
opening_message = "Cleaning targets ..."
1021
closing_message = "done cleaning targets."
1022
failure_message = "cleaning terminated because of errors."
1023
except AttributeError:
1026
SCons.Environment.CalculatorArgs['max_drift'] = ssoptions.get('max_drift')
1029
def order(dependencies):
1030
"""Randomize the dependencies."""
1031
# This is cribbed from the implementation of
1032
# random.shuffle() in Python 2.X.
1034
for i in xrange(len(d)-1, 0, -1):
1035
j = int(random.random() * (i+1))
1036
d[i], d[j] = d[j], d[i]
1039
def order(dependencies):
1040
"""Leave the order of dependencies alone."""
1043
progress_display("scons: " + opening_message)
1044
taskmaster = SCons.Taskmaster.Taskmaster(nodes, task_class, order)
1046
nj = ssoptions.get('num_jobs')
1047
jobs = SCons.Job.Jobs(nj, taskmaster)
1048
if nj > 1 and jobs.num_jobs == 1:
1049
msg = "parallel builds are unsupported by this version of Python;\n" + \
1050
"\tignoring -j or num_jobs option.\n"
1051
SCons.Warnings.warn(SCons.Warnings.NoParallelSupportWarning, msg)
1053
if not memory_stats is None: memory_stats.append(SCons.Debug.memory())
1059
progress_display("scons: " + failure_message)
1061
progress_display("scons: " + closing_message)
1062
if not options.noexec:
1063
SCons.SConsign.write()
1065
if not memory_stats is None:
1066
memory_stats.append(SCons.Debug.memory())
1068
'before SConscript files',
1069
'after SConscript files',
1073
for i in xrange(len(when)):
1074
memory_outf.write('Memory %s: %d\n' % (when[i], memory_stats[i]))
1077
SCons.Debug.countLoggedInstances('*')
1080
SCons.Debug.listLoggedInstances('*')
1081
#SCons.Debug.dumpLoggedInstances('*')
1084
all_args = sys.argv[1:]
1086
all_args = string.split(os.environ['SCONSFLAGS']) + all_args
1088
# it's OK if there's no SCONSFLAGS
1090
parser = OptParser()
1092
options, args = parser.parse_args(all_args)
1093
if options.debug == "pdb":
1095
pdb.Pdb().runcall(_main, args, parser)
1104
except SystemExit, s:
793
1107
except KeyboardInterrupt:
794
1108
print "Build interrupted."
796
1110
except SyntaxError, e:
797
1111
_scons_syntax_error(e)
1112
except SCons.Errors.InternalError:
1113
_scons_internal_error()
1114
except SCons.Errors.UserError, e:
799
1115
_scons_user_error(e)
1116
except SCons.Errors.ConfigureDryRunError, e:
1117
_scons_configure_dryrun_error(e)
801
_scons_other_errors()
1119
# An exception here is likely a builtin Python exception Python
1120
# code in an SConscript file. Show them precisely what the
1121
# problem was and where it happened.
1122
SCons.Script.SConscript.SConscript_exception()
1126
total_time = time.time()-start_time
1127
scons_time = total_time-sconscript_time-command_time
1128
print "Total build time: %f seconds"%total_time
1129
print "Total SConscript file execution time: %f seconds"%sconscript_time
1130
print "Total SCons execution time: %f seconds"%scons_time
1131
print "Total command execution time: %f seconds"%command_time
803
1133
sys.exit(exit_status)