6 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
17 from SCons.Errors import *
22 # Modules and classes that we don't use directly in this script, but
23 # which we want available for use in SConstruct and SConscript files.
25 from SCons.Environment import Environment
26 from SCons.Builder import Builder
29 "XXX: this is here only until the build engine is implemented"
31 def __init__(self, target):
38 sys.stderr.write("scons: *** [%s] Error %d\n" % (e.node, e.stat))
44 "XXX: this is here only until the build engine is implemented"
46 def __init__(self, targets, calc):
47 self.targets = targets
53 while self.num_iterated < len(self.targets):
54 t = self.targets[self.num_iterated]
55 self.num_iterated = self.num_iterated + 1
56 if self.calc.current(t):
57 print 'scons: "%s" is up to date.' % t
65 def executed(self, task):
68 def failed(self, task):
69 self.num_iterated = len(self.targets)
82 def _scons_syntax_error(e):
83 """Handle syntax errors. Print out a message and show where the error
86 etype, value, tb = sys.exc_info()
87 lines = traceback.format_exception_only(etype, value)
89 sys.stderr.write(line+'\n')
91 def _scons_user_error(e):
92 """Handle user errors. Print out a message and a description of the
93 error, along with the line number and routine where it occured.
95 etype, value, tb = sys.exc_info()
96 while tb.tb_next is not None:
98 lineno = traceback.tb_lineno(tb)
99 filename = tb.tb_frame.f_code.co_filename
100 routine = tb.tb_frame.f_code.co_name
101 sys.stderr.write("\nSCons error: %s\n" % value)
102 sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine))
104 def _scons_user_warning(e):
105 """Handle user warnings. Print out a message and a description of
106 the warning, along with the line number and routine where it occured.
108 etype, value, tb = sys.exc_info()
109 while tb.tb_next is not None:
111 lineno = traceback.tb_lineno(tb)
112 filename = tb.tb_frame.f_code.co_filename
113 routine = tb.tb_frame.f_code.co_name
114 sys.stderr.write("\nSCons warning: %s\n" % e)
115 sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine))
117 def _scons_other_errors():
118 """Handle all errors but user errors. Print out a message telling
119 the user what to do in this case and print a normal trace.
122 traceback.print_exc()
126 def Conscript(filename):
128 scripts.append(filename)
130 def Default(*targets):
132 for s in string.split(t):
133 default_targets.append(s)
137 if help_option == 'h':
139 print "Use scons -H for help about command-line options."
145 # After options are initialized, the following variables are
148 option_list = [] # list of Option objects
149 short_opts = "" # string of short (single-character) options
150 long_opts = [] # array of long (--) options
151 opt_func = {} # mapping of option strings to functions
154 """Initialize command-line options processing.
156 This is in a subroutine mainly so we can easily single-step over
161 """Class for command-line option information.
163 This exists to provide a central location for everything
164 describing a command-line option, so that we can change
165 options without having to update the code to handle the
166 option in one place, the -h help message in another place,
167 etc. There are no methods here, only attributes.
169 You can initialize an Option with the following:
171 func The function that will be called when this
172 option is processed on the command line.
177 If there is no func, then this Option probably
178 stores an optstring to be printed.
181 The string to be printed in -h output. If no
182 helpline is specified but a help string is
183 specified (the usual case), a helpline will be
184 constructed automatically from the short, long,
185 arg, and help attributes. (In practice, then,
186 setting helpline without setting func allows you
187 to print arbitrary lines of text in the -h
190 short The string for short, single-hyphen
191 command-line options.
192 Do not include the hyphen:
194 'a' for -a, 'xy' for -x and -y, etc.
196 long An array of strings for long, double-hyphen
197 command-line options. Do not include
200 ['my-option', 'verbose']
202 arg If this option takes an argument, this string
203 specifies how you want it to appear in the
204 -h output ('DIRECTORY', 'FILE', etc.).
206 help The help string that will be printed for
207 this option in the -h output. Must be
208 49 characters or fewer.
210 future If non-zero, this indicates that this feature
211 will be supported in a future release, not
212 the currently planned one. SCons will
213 recognize the option, but it won't show up
216 The following attribute is derived from the supplied attributes:
219 A string, with hyphens, describing the flags
220 for this option, as constructed from the
221 specified short, long and arg attributes.
223 All Option objects are stored in the global option_list list,
224 in the order in which they're created. This is the list
225 that's used to generate -h output, so the order in which the
226 objects are created is the order in which they're printed.
228 The upshot is that specifying a command-line option and having
229 everything work correctly is a matter of defining a function to
230 process its command-line argument (set the right flag, update
231 the right value), and then creating an appropriate Option object
232 at the correct point in the code below.
235 def __init__(self, func = None, helpline = None,
236 short = None, long = None, arg = None,
237 help = None, future = None):
248 opts = opts + ['-' + c]
252 l = map(lambda x,a=arg: x + "=" + a, self.long)
253 opts = opts + map(lambda x: '--' + x, l)
254 self.optstring = string.join(opts, ', ')
256 self.helpline = helpline
257 elif help and not future:
258 if len(self.optstring) <= 26:
259 sep = " " * (28 - len(self.optstring))
261 sep = self.helpstring = "\n" + " " * 30
262 self.helpline = " " + self.optstring + sep + self.help
266 option_list.append(self)
268 # Generic routine for to-be-written options, used by multiple
271 def opt_not_yet(opt, arg):
272 sys.stderr.write("Warning: the %s option is not yet implemented\n"
275 # In the following instantiations, the help string should be no
276 # longer than 49 characters. Use the following as a guide:
277 # help = "1234567890123456789012345678901234567890123456789"
279 def opt_ignore(opt, arg):
280 sys.stderr.write("Warning: ignoring %s option\n" % opt)
282 Option(func = opt_ignore,
283 short = 'bmSt', long = ['no-keep-going', 'stop', 'touch'],
284 help = "Ignored for compatibility.")
286 Option(func = opt_not_yet,
287 short = 'c', long = ['clean', 'remove'],
288 help = "Remove specified targets and dependencies.")
290 Option(func = opt_not_yet, future = 1,
291 long = ['cache-disable', 'no-cache'],
292 help = "Do not retrieve built targets from Cache.")
294 Option(func = opt_not_yet, future = 1,
295 long = ['cache-force', 'cache-populate'],
296 help = "Copy already-built targets into the Cache.")
298 Option(func = opt_not_yet, future = 1,
299 long = ['cache-show'],
300 help = "Print what would have built Cached targets.")
306 sys.stderr.write("Could not change directory to 'arg'\n")
309 short = 'C', long = ['directory'], arg = 'DIRECTORY',
310 help = "Change to DIRECTORY before doing anything.")
312 Option(func = opt_not_yet,
314 help = "Print file dependency information.")
316 Option(func = opt_not_yet, future = 1,
317 long = ['debug'], arg = 'FLAGS',
318 help = "Print various types of debugging information.")
320 Option(func = opt_not_yet, future = 1,
321 short = 'e', long = ['environment-overrides'],
322 help = "Environment variables override makefiles.")
329 short = 'f', long = ['file', 'makefile', 'sconstruct'], arg = 'FILE',
330 help = "Read FILE as the top-level SConstruct file.")
332 def opt_help(opt, arg):
336 Option(func = opt_help,
337 short = 'h', long = ['help'],
338 help = "Print defined help message, or this one.")
340 def opt_help_options(opt, arg):
344 Option(func = opt_help_options,
345 short = 'H', long = ['help-options'],
346 help = "Print this message and exit.")
348 Option(func = opt_not_yet,
349 short = 'i', long = ['ignore-errors'],
350 help = "Ignore errors from build actions.")
354 include_dirs = include_dirs + [arg]
357 short = 'I', long = ['include-dir'], arg = 'DIRECTORY',
358 help = "Search DIRECTORY for imported Python modules.")
373 short = 'j', long = ['jobs'], arg = 'N',
374 help = "Allow N jobs at once.")
376 Option(func = opt_not_yet,
377 short = 'k', long = ['keep-going'],
378 help = "Keep going when a target can't be made.")
380 Option(func = opt_not_yet, future = 1,
381 short = 'l', long = ['load-average', 'max-load'], arg = 'N',
382 help = "Don't start multiple jobs unless load is below N.")
384 Option(func = opt_not_yet, future = 1,
385 long = ['list-derived'],
386 help = "Don't build; list files that would be built.")
388 Option(func = opt_not_yet, future = 1,
389 long = ['list-actions'],
390 help = "Don't build; list files and build actions.")
392 Option(func = opt_not_yet, future = 1,
393 long = ['list-where'],
394 help = "Don't build; list files and where defined.")
397 SCons.Builder.execute_actions = None
400 short = 'n', long = ['no-exec', 'just-print', 'dry-run', 'recon'],
401 help = "Don't build; just print commands.")
403 Option(func = opt_not_yet, future = 1,
404 short = 'o', long = ['old-file', 'assume-old'], arg = 'FILE',
405 help = "Consider FILE to be old; don't rebuild it.")
407 Option(func = opt_not_yet, future = 1,
408 long = ['override'], arg = 'FILE',
409 help = "Override variables as specified in FILE.")
411 Option(func = opt_not_yet, future = 1,
413 help = "Print internal environments/objects.")
415 Option(func = opt_not_yet, future = 1,
416 short = 'q', long = ['question'],
417 help = "Don't build; exit status says if up to date.")
419 Option(func = opt_not_yet, future = 1,
420 short = 'rR', long = ['no-builtin-rules', 'no-builtin-variables'],
421 help = "Clear default environments and variables.")
423 Option(func = opt_not_yet, future = 1,
425 help = "Build dependencies in random order.")
428 SCons.Builder.print_actions = None
431 short = 's', long = ['silent', 'quiet'],
432 help = "Don't print commands.")
434 Option(func = opt_not_yet, future = 1,
435 short = 'u', long = ['up', 'search-up'],
436 help = "Search up directory tree for SConstruct.")
438 def option_v(opt, arg):
439 print "SCons version __VERSION__, by Steven Knight et al."
440 print "Copyright 2001 Steven Knight"
443 Option(func = option_v,
444 short = 'v', long = ['version'],
445 help = "Print the SCons version number and exit.")
447 Option(func = opt_not_yet, future = 1,
448 short = 'w', long = ['print-directory'],
449 help = "Print the current directory.")
451 Option(func = opt_not_yet, future = 1,
452 long = ['no-print-directory'],
453 help = "Turn off -w, even if it was turned on implicitly.")
455 Option(func = opt_not_yet, future = 1,
456 long = ['write-filenames'], arg = 'FILE',
457 help = "Write all filenames examined into FILE.")
459 Option(func = opt_not_yet, future = 1,
460 short = 'W', long = ['what-if', 'new-file', 'assume-new'], arg = 'FILE',
461 help = "Consider FILE to be changed.")
463 Option(func = opt_not_yet, future = 1,
464 long = ['warn-undefined-variables'],
465 help = "Warn when an undefined variable is referenced.")
467 Option(func = opt_not_yet, future = 1,
468 short = 'Y', long = ['repository'], arg = 'REPOSITORY',
469 help = "Search REPOSITORY for source and target files.")
474 for o in option_list:
478 opt_func['-' + c] = o.func
479 short_opts = short_opts + o.short
481 short_opts = short_opts + ":"
485 opt_func['--' + l] = o.func
487 long_opts = long_opts + map(lambda a: a + "=", o.long)
489 long_opts = long_opts + o.long
496 help_opts = filter(lambda x: x.helpline, option_list)
497 s = "Usage: scons [OPTION] [TARGET] ...\n" + "Options:\n" + \
498 string.join(map(lambda x: x.helpline, help_opts), "\n") + "\n"
504 global scripts, help_option, num_jobs
508 # It looks like 2.0 changed the name of the exception class
511 getopt_err = getopt.GetoptError
513 getopt_err = getopt.error
516 cmd_opts, t = getopt.getopt(string.split(os.environ['SCONSFLAGS']),
517 short_opts, long_opts)
519 # It's all right if there's no SCONSFLAGS environment variable.
521 except getopt_err, x:
522 _scons_user_warning("SCONSFLAGS " + x)
524 for opt, arg in cmd_opts:
525 opt_func[opt](opt, arg)
528 cmd_opts, targets = getopt.getopt(sys.argv[1:], short_opts, long_opts)
529 except getopt_err, x:
532 for opt, arg in cmd_opts:
533 opt_func[opt](opt, arg)
536 for file in ['SConstruct', 'Sconstruct', 'sconstruct']:
537 if os.path.isfile(file):
541 if help_option == 'H':
546 if help_option == 'h':
547 # There's no SConstruct, but they specified either -h or
548 # -H. Give them the options usage now, before we fail
549 # trying to read a non-existent SConstruct file.
553 raise UserError, "No SConstruct file found."
555 # XXX The commented-out code here adds any "scons" subdirs in anything
556 # along sys.path to sys.path. This was an attempt at setting up things
557 # so we can import "node.FS" instead of "SCons.Node.FS". This doesn't
558 # quite fit our testing methodology, though, so save it for now until
559 # the right solutions pops up.
562 #for dir in sys.path:
563 # scons = os.path.join(dir, 'scons')
564 # if os.path.isdir(scons):
565 # dirlist = dirlist + [scons]
566 # dirlist = dirlist + [dir]
570 sys.path = include_dirs + sys.path
573 file, scripts = scripts[0], scripts[1:]
575 exec sys.stdin in globals()
580 sys.stderr.write("Ignoring missing script '%s'\n" % file)
584 if help_option == 'h':
585 # They specified -h, but there was no Help() inside the
586 # SConscript files. Give them the options usage.
591 targets = default_targets
593 nodes = map(lambda x: SCons.Node.FS.default_fs.File(x), targets)
594 calc = SCons.Sig.Calculator(SCons.Sig.MD5)
596 taskmaster = Taskmaster(nodes, calc)
598 jobs = SCons.Job.Jobs(num_jobs, taskmaster)
604 if __name__ == "__main__":
609 except KeyboardInterrupt:
610 print "Build interrupted."
611 except SyntaxError, e:
612 _scons_syntax_error(e)
616 _scons_other_errors()