Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(288)

Side by Side Diff: scons-2.0.1/script/scons-time

Issue 6711079: Added an unmodified copy of SCons to third_party. (Closed) Base URL: svn://svn.chromium.org/native_client/trunk/src/third_party/
Patch Set: '' Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « scons-2.0.1/script/scons.bat ('k') | scons-2.0.1/script/sconsign » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:executable
+ *
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 #
3 # scons-time - run SCons timings and collect statistics
4 #
5 # A script for running a configuration through SCons with a standard
6 # set of invocations to collect timing and memory statistics and to
7 # capture the results in a consistent set of output files for display
8 # and analysis.
9 #
10
11 #
12 # Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 The S Cons Foundation
13 #
14 # Permission is hereby granted, free of charge, to any person obtaining
15 # a copy of this software and associated documentation files (the
16 # "Software"), to deal in the Software without restriction, including
17 # without limitation the rights to use, copy, modify, merge, publish,
18 # distribute, sublicense, and/or sell copies of the Software, and to
19 # permit persons to whom the Software is furnished to do so, subject to
20 # the following conditions:
21 #
22 # The above copyright notice and this permission notice shall be included
23 # in all copies or substantial portions of the Software.
24 #
25 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
26 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
27 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 from __future__ import division
33 from __future__ import nested_scopes
34
35 __revision__ = "src/script/scons-time.py 5134 2010/08/16 23:02:40 bdeegan"
36
37 import getopt
38 import glob
39 import os
40 import re
41 import shutil
42 import sys
43 import tempfile
44 import time
45
46 try:
47 sorted
48 except NameError:
49 # Pre-2.4 Python has no sorted() function.
50 #
51 # The pre-2.4 Python list.sort() method does not support
52 # list.sort(key=) nor list.sort(reverse=) keyword arguments, so
53 # we must implement the functionality of those keyword arguments
54 # by hand instead of passing them to list.sort().
55 def sorted(iterable, cmp=None, key=None, reverse=False):
56 if key is not None:
57 result = [(key(x), x) for x in iterable]
58 else:
59 result = iterable[:]
60 if cmp is None:
61 # Pre-2.3 Python does not support list.sort(None).
62 result.sort()
63 else:
64 result.sort(cmp)
65 if key is not None:
66 result = [t1 for t0,t1 in result]
67 if reverse:
68 result.reverse()
69 return result
70
71 if os.environ.get('SCONS_HORRIBLE_REGRESSION_TEST_HACK') is not None:
72 # We can't apply the 'callable' fixer until the floor is 2.6, but the
73 # '-3' option to Python 2.6 and 2.7 generates almost ten thousand
74 # warnings. This hack allows us to run regression tests with the '-3'
75 # option by replacing the callable() built-in function with a hack
76 # that performs the same function but doesn't generate the warning.
77 # Note that this hack is ONLY intended to be used for regression
78 # testing, and should NEVER be used for real runs.
79 from types import ClassType
80 def callable(obj):
81 if hasattr(obj, '__call__'): return True
82 if isinstance(obj, (ClassType, type)): return True
83 return False
84
85 def make_temp_file(**kw):
86 try:
87 result = tempfile.mktemp(**kw)
88 try:
89 result = os.path.realpath(result)
90 except AttributeError:
91 # Python 2.1 has no os.path.realpath() method.
92 pass
93 except TypeError:
94 try:
95 save_template = tempfile.template
96 prefix = kw['prefix']
97 del kw['prefix']
98 tempfile.template = prefix
99 result = tempfile.mktemp(**kw)
100 finally:
101 tempfile.template = save_template
102 return result
103
104 def HACK_for_exec(cmd, *args):
105 '''
106 For some reason, Python won't allow an exec() within a function
107 that also declares an internal function (including lambda functions).
108 This function is a hack that calls exec() in a function with no
109 internal functions.
110 '''
111 if not args: exec(cmd)
112 elif len(args) == 1: exec cmd in args[0]
113 else: exec cmd in args[0], args[1]
114
115 class Plotter(object):
116 def increment_size(self, largest):
117 """
118 Return the size of each horizontal increment line for a specified
119 maximum value. This returns a value that will provide somewhere
120 between 5 and 9 horizontal lines on the graph, on some set of
121 boundaries that are multiples of 10/100/1000/etc.
122 """
123 i = largest // 5
124 if not i:
125 return largest
126 multiplier = 1
127 while i >= 10:
128 i = i // 10
129 multiplier = multiplier * 10
130 return i * multiplier
131
132 def max_graph_value(self, largest):
133 # Round up to next integer.
134 largest = int(largest) + 1
135 increment = self.increment_size(largest)
136 return ((largest + increment - 1) // increment) * increment
137
138 class Line(object):
139 def __init__(self, points, type, title, label, comment, fmt="%s %s"):
140 self.points = points
141 self.type = type
142 self.title = title
143 self.label = label
144 self.comment = comment
145 self.fmt = fmt
146
147 def print_label(self, inx, x, y):
148 if self.label:
149 print 'set label %s "%s" at %s,%s right' % (inx, self.label, x, y)
150
151 def plot_string(self):
152 if self.title:
153 title_string = 'title "%s"' % self.title
154 else:
155 title_string = 'notitle'
156 return "'-' %s with lines lt %s" % (title_string, self.type)
157
158 def print_points(self, fmt=None):
159 if fmt is None:
160 fmt = self.fmt
161 if self.comment:
162 print '# %s' % self.comment
163 for x, y in self.points:
164 # If y is None, it usually represents some kind of break
165 # in the line's index number. We might want to represent
166 # this some way rather than just drawing the line straight
167 # between the two points on either side.
168 if not y is None:
169 print fmt % (x, y)
170 print 'e'
171
172 def get_x_values(self):
173 return [ p[0] for p in self.points ]
174
175 def get_y_values(self):
176 return [ p[1] for p in self.points ]
177
178 class Gnuplotter(Plotter):
179
180 def __init__(self, title, key_location):
181 self.lines = []
182 self.title = title
183 self.key_location = key_location
184
185 def line(self, points, type, title=None, label=None, comment=None, fmt='%s % s'):
186 if points:
187 line = Line(points, type, title, label, comment, fmt)
188 self.lines.append(line)
189
190 def plot_string(self, line):
191 return line.plot_string()
192
193 def vertical_bar(self, x, type, label, comment):
194 if self.get_min_x() <= x and x <= self.get_max_x():
195 points = [(x, 0), (x, self.max_graph_value(self.get_max_y()))]
196 self.line(points, type, label, comment)
197
198 def get_all_x_values(self):
199 result = []
200 for line in self.lines:
201 result.extend(line.get_x_values())
202 return [r for r in result if not r is None]
203
204 def get_all_y_values(self):
205 result = []
206 for line in self.lines:
207 result.extend(line.get_y_values())
208 return [r for r in result if not r is None]
209
210 def get_min_x(self):
211 try:
212 return self.min_x
213 except AttributeError:
214 try:
215 self.min_x = min(self.get_all_x_values())
216 except ValueError:
217 self.min_x = 0
218 return self.min_x
219
220 def get_max_x(self):
221 try:
222 return self.max_x
223 except AttributeError:
224 try:
225 self.max_x = max(self.get_all_x_values())
226 except ValueError:
227 self.max_x = 0
228 return self.max_x
229
230 def get_min_y(self):
231 try:
232 return self.min_y
233 except AttributeError:
234 try:
235 self.min_y = min(self.get_all_y_values())
236 except ValueError:
237 self.min_y = 0
238 return self.min_y
239
240 def get_max_y(self):
241 try:
242 return self.max_y
243 except AttributeError:
244 try:
245 self.max_y = max(self.get_all_y_values())
246 except ValueError:
247 self.max_y = 0
248 return self.max_y
249
250 def draw(self):
251
252 if not self.lines:
253 return
254
255 if self.title:
256 print 'set title "%s"' % self.title
257 print 'set key %s' % self.key_location
258
259 min_y = self.get_min_y()
260 max_y = self.max_graph_value(self.get_max_y())
261 incr = (max_y - min_y) / 10.0
262 start = min_y + (max_y / 2.0) + (2.0 * incr)
263 position = [ start - (i * incr) for i in range(5) ]
264
265 inx = 1
266 for line in self.lines:
267 line.print_label(inx, line.points[0][0]-1,
268 position[(inx-1) % len(position)])
269 inx += 1
270
271 plot_strings = [ self.plot_string(l) for l in self.lines ]
272 print 'plot ' + ', \\\n '.join(plot_strings)
273
274 for line in self.lines:
275 line.print_points()
276
277
278
279 def untar(fname):
280 import tarfile
281 tar = tarfile.open(name=fname, mode='r')
282 for tarinfo in tar:
283 tar.extract(tarinfo)
284 tar.close()
285
286 def unzip(fname):
287 import zipfile
288 zf = zipfile.ZipFile(fname, 'r')
289 for name in zf.namelist():
290 dir = os.path.dirname(name)
291 try:
292 os.makedirs(dir)
293 except:
294 pass
295 open(name, 'w').write(zf.read(name))
296
297 def read_tree(dir):
298 for dirpath, dirnames, filenames in os.walk(dir):
299 for fn in filenames:
300 fn = os.path.join(dirpath, fn)
301 if os.path.isfile(fn):
302 open(fn, 'rb').read()
303
304 def redirect_to_file(command, log):
305 return '%s > %s 2>&1' % (command, log)
306
307 def tee_to_file(command, log):
308 return '%s 2>&1 | tee %s' % (command, log)
309
310
311
312 class SConsTimer(object):
313 """
314 Usage: scons-time SUBCOMMAND [ARGUMENTS]
315 Type "scons-time help SUBCOMMAND" for help on a specific subcommand.
316
317 Available subcommands:
318 func Extract test-run data for a function
319 help Provides help
320 mem Extract --debug=memory data from test runs
321 obj Extract --debug=count data from test runs
322 time Extract --debug=time data from test runs
323 run Runs a test configuration
324 """
325
326 name = 'scons-time'
327 name_spaces = ' '*len(name)
328
329 def makedict(**kw):
330 return kw
331
332 default_settings = makedict(
333 aegis = 'aegis',
334 aegis_project = None,
335 chdir = None,
336 config_file = None,
337 initial_commands = [],
338 key_location = 'bottom left',
339 orig_cwd = os.getcwd(),
340 outdir = None,
341 prefix = '',
342 python = '"%s"' % sys.executable,
343 redirect = redirect_to_file,
344 scons = None,
345 scons_flags = '--debug=count --debug=memory --debug=time --debug =memoizer',
346 scons_lib_dir = None,
347 scons_wrapper = None,
348 startup_targets = '--help',
349 subdir = None,
350 subversion_url = None,
351 svn = 'svn',
352 svn_co_flag = '-q',
353 tar = 'tar',
354 targets = '',
355 targets0 = None,
356 targets1 = None,
357 targets2 = None,
358 title = None,
359 unzip = 'unzip',
360 verbose = False,
361 vertical_bars = [],
362
363 unpack_map = {
364 '.tar.gz' : (untar, '%(tar)s xzf %%s'),
365 '.tgz' : (untar, '%(tar)s xzf %%s'),
366 '.tar' : (untar, '%(tar)s xf %%s'),
367 '.zip' : (unzip, '%(unzip)s %%s'),
368 },
369 )
370
371 run_titles = [
372 'Startup',
373 'Full build',
374 'Up-to-date build',
375 ]
376
377 run_commands = [
378 '%(python)s %(scons_wrapper)s %(scons_flags)s --profile=%(prof0)s %(targ ets0)s',
379 '%(python)s %(scons_wrapper)s %(scons_flags)s --profile=%(prof1)s %(targ ets1)s',
380 '%(python)s %(scons_wrapper)s %(scons_flags)s --profile=%(prof2)s %(targ ets2)s',
381 ]
382
383 stages = [
384 'pre-read',
385 'post-read',
386 'pre-build',
387 'post-build',
388 ]
389
390 stage_strings = {
391 'pre-read' : 'Memory before reading SConscript files:',
392 'post-read' : 'Memory after reading SConscript files:',
393 'pre-build' : 'Memory before building targets:',
394 'post-build' : 'Memory after building targets:',
395 }
396
397 memory_string_all = 'Memory '
398
399 default_stage = stages[-1]
400
401 time_strings = {
402 'total' : 'Total build time',
403 'SConscripts' : 'Total SConscript file execution time',
404 'SCons' : 'Total SCons execution time',
405 'commands' : 'Total command execution time',
406 }
407
408 time_string_all = 'Total .* time'
409
410 #
411
412 def __init__(self):
413 self.__dict__.update(self.default_settings)
414
415 # Functions for displaying and executing commands.
416
417 def subst(self, x, dictionary):
418 try:
419 return x % dictionary
420 except TypeError:
421 # x isn't a string (it's probably a Python function),
422 # so just return it.
423 return x
424
425 def subst_variables(self, command, dictionary):
426 """
427 Substitutes (via the format operator) the values in the specified
428 dictionary into the specified command.
429
430 The command can be an (action, string) tuple. In all cases, we
431 perform substitution on strings and don't worry if something isn't
432 a string. (It's probably a Python function to be executed.)
433 """
434 try:
435 command + ''
436 except TypeError:
437 action = command[0]
438 string = command[1]
439 args = command[2:]
440 else:
441 action = command
442 string = action
443 args = (())
444 action = self.subst(action, dictionary)
445 string = self.subst(string, dictionary)
446 return (action, string, args)
447
448 def _do_not_display(self, msg, *args):
449 pass
450
451 def display(self, msg, *args):
452 """
453 Displays the specified message.
454
455 Each message is prepended with a standard prefix of our name
456 plus the time.
457 """
458 if callable(msg):
459 msg = msg(*args)
460 else:
461 msg = msg % args
462 if msg is None:
463 return
464 fmt = '%s[%s]: %s\n'
465 sys.stdout.write(fmt % (self.name, time.strftime('%H:%M:%S'), msg))
466
467 def _do_not_execute(self, action, *args):
468 pass
469
470 def execute(self, action, *args):
471 """
472 Executes the specified action.
473
474 The action is called if it's a callable Python function, and
475 otherwise passed to os.system().
476 """
477 if callable(action):
478 action(*args)
479 else:
480 os.system(action % args)
481
482 def run_command_list(self, commands, dict):
483 """
484 Executes a list of commands, substituting values from the
485 specified dictionary.
486 """
487 commands = [ self.subst_variables(c, dict) for c in commands ]
488 for action, string, args in commands:
489 self.display(string, *args)
490 sys.stdout.flush()
491 status = self.execute(action, *args)
492 if status:
493 sys.exit(status)
494
495 def log_display(self, command, log):
496 command = self.subst(command, self.__dict__)
497 if log:
498 command = self.redirect(command, log)
499 return command
500
501 def log_execute(self, command, log):
502 command = self.subst(command, self.__dict__)
503 output = os.popen(command).read()
504 if self.verbose:
505 sys.stdout.write(output)
506 open(log, 'wb').write(output)
507
508 #
509
510 def archive_splitext(self, path):
511 """
512 Splits an archive name into a filename base and extension.
513
514 This is like os.path.splitext() (which it calls) except that it
515 also looks for '.tar.gz' and treats it as an atomic extensions.
516 """
517 if path.endswith('.tar.gz'):
518 return path[:-7], path[-7:]
519 else:
520 return os.path.splitext(path)
521
522 def args_to_files(self, args, tail=None):
523 """
524 Takes a list of arguments, expands any glob patterns, and
525 returns the last "tail" files from the list.
526 """
527 files = []
528 for a in args:
529 files.extend(sorted(glob.glob(a)))
530
531 if tail:
532 files = files[-tail:]
533
534 return files
535
536 def ascii_table(self, files, columns,
537 line_function, file_function=lambda x: x,
538 *args, **kw):
539
540 header_fmt = ' '.join(['%12s'] * len(columns))
541 line_fmt = header_fmt + ' %s'
542
543 print header_fmt % columns
544
545 for file in files:
546 t = line_function(file, *args, **kw)
547 if t is None:
548 t = []
549 diff = len(columns) - len(t)
550 if diff > 0:
551 t += [''] * diff
552 t.append(file_function(file))
553 print line_fmt % tuple(t)
554
555 def collect_results(self, files, function, *args, **kw):
556 results = {}
557
558 for file in files:
559 base = os.path.splitext(file)[0]
560 run, index = base.split('-')[-2:]
561
562 run = int(run)
563 index = int(index)
564
565 value = function(file, *args, **kw)
566
567 try:
568 r = results[index]
569 except KeyError:
570 r = []
571 results[index] = r
572 r.append((run, value))
573
574 return results
575
576 def doc_to_help(self, obj):
577 """
578 Translates an object's __doc__ string into help text.
579
580 This strips a consistent number of spaces from each line in the
581 help text, essentially "outdenting" the text to the left-most
582 column.
583 """
584 doc = obj.__doc__
585 if doc is None:
586 return ''
587 return self.outdent(doc)
588
589 def find_next_run_number(self, dir, prefix):
590 """
591 Returns the next run number in a directory for the specified prefix.
592
593 Examines the contents the specified directory for files with the
594 specified prefix, extracts the run numbers from each file name,
595 and returns the next run number after the largest it finds.
596 """
597 x = re.compile(re.escape(prefix) + '-([0-9]+).*')
598 matches = [x.match(e) for e in os.listdir(dir)]
599 matches = [_f for _f in matches if _f]
600 if not matches:
601 return 0
602 run_numbers = [int(m.group(1)) for m in matches]
603 return int(max(run_numbers)) + 1
604
605 def gnuplot_results(self, results, fmt='%s %.3f'):
606 """
607 Prints out a set of results in Gnuplot format.
608 """
609 gp = Gnuplotter(self.title, self.key_location)
610
611 for i in sorted(results.keys()):
612 try:
613 t = self.run_titles[i]
614 except IndexError:
615 t = '??? %s ???' % i
616 results[i].sort()
617 gp.line(results[i], i+1, t, None, t, fmt=fmt)
618
619 for bar_tuple in self.vertical_bars:
620 try:
621 x, type, label, comment = bar_tuple
622 except ValueError:
623 x, type, label = bar_tuple
624 comment = label
625 gp.vertical_bar(x, type, label, comment)
626
627 gp.draw()
628
629 def logfile_name(self, invocation):
630 """
631 Returns the absolute path of a log file for the specificed
632 invocation number.
633 """
634 name = self.prefix_run + '-%d.log' % invocation
635 return os.path.join(self.outdir, name)
636
637 def outdent(self, s):
638 """
639 Strip as many spaces from each line as are found at the beginning
640 of the first line in the list.
641 """
642 lines = s.split('\n')
643 if lines[0] == '':
644 lines = lines[1:]
645 spaces = re.match(' *', lines[0]).group(0)
646 def strip_initial_spaces(l, s=spaces):
647 if l.startswith(spaces):
648 l = l[len(spaces):]
649 return l
650 return '\n'.join([ strip_initial_spaces(l) for l in lines ]) + '\n'
651
652 def profile_name(self, invocation):
653 """
654 Returns the absolute path of a profile file for the specified
655 invocation number.
656 """
657 name = self.prefix_run + '-%d.prof' % invocation
658 return os.path.join(self.outdir, name)
659
660 def set_env(self, key, value):
661 os.environ[key] = value
662
663 #
664
665 def get_debug_times(self, file, time_string=None):
666 """
667 Fetch times from the --debug=time strings in the specified file.
668 """
669 if time_string is None:
670 search_string = self.time_string_all
671 else:
672 search_string = time_string
673 contents = open(file).read()
674 if not contents:
675 sys.stderr.write('file %s has no contents!\n' % repr(file))
676 return None
677 result = re.findall(r'%s: ([\d\.]*)' % search_string, contents)[-4:]
678 result = [ float(r) for r in result ]
679 if not time_string is None:
680 try:
681 result = result[0]
682 except IndexError:
683 sys.stderr.write('file %s has no results!\n' % repr(file))
684 return None
685 return result
686
687 def get_function_profile(self, file, function):
688 """
689 Returns the file, line number, function name, and cumulative time.
690 """
691 try:
692 import pstats
693 except ImportError, e:
694 sys.stderr.write('%s: func: %s\n' % (self.name, e))
695 sys.stderr.write('%s This version of Python is missing the profiler .\n' % self.name_spaces)
696 sys.stderr.write('%s Cannot use the "func" subcommand.\n' % self.na me_spaces)
697 sys.exit(1)
698 statistics = pstats.Stats(file).stats
699 matches = [ e for e in statistics.items() if e[0][2] == function ]
700 r = matches[0]
701 return r[0][0], r[0][1], r[0][2], r[1][3]
702
703 def get_function_time(self, file, function):
704 """
705 Returns just the cumulative time for the specified function.
706 """
707 return self.get_function_profile(file, function)[3]
708
709 def get_memory(self, file, memory_string=None):
710 """
711 Returns a list of integers of the amount of memory used. The
712 default behavior is to return all the stages.
713 """
714 if memory_string is None:
715 search_string = self.memory_string_all
716 else:
717 search_string = memory_string
718 lines = open(file).readlines()
719 lines = [ l for l in lines if l.startswith(search_string) ][-4:]
720 result = [ int(l.split()[-1]) for l in lines[-4:] ]
721 if len(result) == 1:
722 result = result[0]
723 return result
724
725 def get_object_counts(self, file, object_name, index=None):
726 """
727 Returns the counts of the specified object_name.
728 """
729 object_string = ' ' + object_name + '\n'
730 lines = open(file).readlines()
731 line = [ l for l in lines if l.endswith(object_string) ][0]
732 result = [ int(field) for field in line.split()[:4] ]
733 if index is not None:
734 result = result[index]
735 return result
736
737 #
738
739 command_alias = {}
740
741 def execute_subcommand(self, argv):
742 """
743 Executes the do_*() function for the specified subcommand (argv[0]).
744 """
745 if not argv:
746 return
747 cmdName = self.command_alias.get(argv[0], argv[0])
748 try:
749 func = getattr(self, 'do_' + cmdName)
750 except AttributeError:
751 return self.default(argv)
752 try:
753 return func(argv)
754 except TypeError, e:
755 sys.stderr.write("%s %s: %s\n" % (self.name, cmdName, e))
756 import traceback
757 traceback.print_exc(file=sys.stderr)
758 sys.stderr.write("Try '%s help %s'\n" % (self.name, cmdName))
759
760 def default(self, argv):
761 """
762 The default behavior for an unknown subcommand. Prints an
763 error message and exits.
764 """
765 sys.stderr.write('%s: Unknown subcommand "%s".\n' % (self.name, argv[0]) )
766 sys.stderr.write('Type "%s help" for usage.\n' % self.name)
767 sys.exit(1)
768
769 #
770
771 def do_help(self, argv):
772 """
773 """
774 if argv[1:]:
775 for arg in argv[1:]:
776 try:
777 func = getattr(self, 'do_' + arg)
778 except AttributeError:
779 sys.stderr.write('%s: No help for "%s"\n' % (self.name, arg) )
780 else:
781 try:
782 help = getattr(self, 'help_' + arg)
783 except AttributeError:
784 sys.stdout.write(self.doc_to_help(func))
785 sys.stdout.flush()
786 else:
787 help()
788 else:
789 doc = self.doc_to_help(self.__class__)
790 if doc:
791 sys.stdout.write(doc)
792 sys.stdout.flush()
793 return None
794
795 #
796
797 def help_func(self):
798 help = """\
799 Usage: scons-time func [OPTIONS] FILE [...]
800
801 -C DIR, --chdir=DIR Change to DIR before looking for files
802 -f FILE, --file=FILE Read configuration from specified FILE
803 --fmt=FORMAT, --format=FORMAT Print data in specified FORMAT
804 --func=NAME, --function=NAME Report time for function NAME
805 -h, --help Print this help and exit
806 -p STRING, --prefix=STRING Use STRING as log file/profile prefix
807 -t NUMBER, --tail=NUMBER Only report the last NUMBER files
808 --title=TITLE Specify the output plot TITLE
809 """
810 sys.stdout.write(self.outdent(help))
811 sys.stdout.flush()
812
813 def do_func(self, argv):
814 """
815 """
816 format = 'ascii'
817 function_name = '_main'
818 tail = None
819
820 short_opts = '?C:f:hp:t:'
821
822 long_opts = [
823 'chdir=',
824 'file=',
825 'fmt=',
826 'format=',
827 'func=',
828 'function=',
829 'help',
830 'prefix=',
831 'tail=',
832 'title=',
833 ]
834
835 opts, args = getopt.getopt(argv[1:], short_opts, long_opts)
836
837 for o, a in opts:
838 if o in ('-C', '--chdir'):
839 self.chdir = a
840 elif o in ('-f', '--file'):
841 self.config_file = a
842 elif o in ('--fmt', '--format'):
843 format = a
844 elif o in ('--func', '--function'):
845 function_name = a
846 elif o in ('-?', '-h', '--help'):
847 self.do_help(['help', 'func'])
848 sys.exit(0)
849 elif o in ('--max',):
850 max_time = int(a)
851 elif o in ('-p', '--prefix'):
852 self.prefix = a
853 elif o in ('-t', '--tail'):
854 tail = int(a)
855 elif o in ('--title',):
856 self.title = a
857
858 if self.config_file:
859 exec open(self.config_file, 'rU').read() in self.__dict__
860
861 if self.chdir:
862 os.chdir(self.chdir)
863
864 if not args:
865
866 pattern = '%s*.prof' % self.prefix
867 args = self.args_to_files([pattern], tail)
868
869 if not args:
870 if self.chdir:
871 directory = self.chdir
872 else:
873 directory = os.getcwd()
874
875 sys.stderr.write('%s: func: No arguments specified.\n' % self.na me)
876 sys.stderr.write('%s No %s*.prof files found in "%s".\n' % (sel f.name_spaces, self.prefix, directory))
877 sys.stderr.write('%s Type "%s help func" for help.\n' % (self.n ame_spaces, self.name))
878 sys.exit(1)
879
880 else:
881
882 args = self.args_to_files(args, tail)
883
884 cwd_ = os.getcwd() + os.sep
885
886 if format == 'ascii':
887
888 for file in args:
889 try:
890 f, line, func, time = \
891 self.get_function_profile(file, function_name)
892 except ValueError, e:
893 sys.stderr.write("%s: func: %s: %s\n" %
894 (self.name, file, e))
895 else:
896 if f.startswith(cwd_):
897 f = f[len(cwd_):]
898 print "%.3f %s:%d(%s)" % (time, f, line, func)
899
900 elif format == 'gnuplot':
901
902 results = self.collect_results(args, self.get_function_time,
903 function_name)
904
905 self.gnuplot_results(results)
906
907 else:
908
909 sys.stderr.write('%s: func: Unknown format "%s".\n' % (self.name, fo rmat))
910 sys.exit(1)
911
912 #
913
914 def help_mem(self):
915 help = """\
916 Usage: scons-time mem [OPTIONS] FILE [...]
917
918 -C DIR, --chdir=DIR Change to DIR before looking for files
919 -f FILE, --file=FILE Read configuration from specified FILE
920 --fmt=FORMAT, --format=FORMAT Print data in specified FORMAT
921 -h, --help Print this help and exit
922 -p STRING, --prefix=STRING Use STRING as log file/profile prefix
923 --stage=STAGE Plot memory at the specified stage:
924 pre-read, post-read, pre-build,
925 post-build (default: post-build)
926 -t NUMBER, --tail=NUMBER Only report the last NUMBER files
927 --title=TITLE Specify the output plot TITLE
928 """
929 sys.stdout.write(self.outdent(help))
930 sys.stdout.flush()
931
932 def do_mem(self, argv):
933
934 format = 'ascii'
935 logfile_path = lambda x: x
936 stage = self.default_stage
937 tail = None
938
939 short_opts = '?C:f:hp:t:'
940
941 long_opts = [
942 'chdir=',
943 'file=',
944 'fmt=',
945 'format=',
946 'help',
947 'prefix=',
948 'stage=',
949 'tail=',
950 'title=',
951 ]
952
953 opts, args = getopt.getopt(argv[1:], short_opts, long_opts)
954
955 for o, a in opts:
956 if o in ('-C', '--chdir'):
957 self.chdir = a
958 elif o in ('-f', '--file'):
959 self.config_file = a
960 elif o in ('--fmt', '--format'):
961 format = a
962 elif o in ('-?', '-h', '--help'):
963 self.do_help(['help', 'mem'])
964 sys.exit(0)
965 elif o in ('-p', '--prefix'):
966 self.prefix = a
967 elif o in ('--stage',):
968 if not a in self.stages:
969 sys.stderr.write('%s: mem: Unrecognized stage "%s".\n' % (se lf.name, a))
970 sys.exit(1)
971 stage = a
972 elif o in ('-t', '--tail'):
973 tail = int(a)
974 elif o in ('--title',):
975 self.title = a
976
977 if self.config_file:
978 HACK_for_exec(open(self.config_file, 'rU').read(), self.__dict__)
979
980 if self.chdir:
981 os.chdir(self.chdir)
982 logfile_path = lambda x: os.path.join(self.chdir, x)
983
984 if not args:
985
986 pattern = '%s*.log' % self.prefix
987 args = self.args_to_files([pattern], tail)
988
989 if not args:
990 if self.chdir:
991 directory = self.chdir
992 else:
993 directory = os.getcwd()
994
995 sys.stderr.write('%s: mem: No arguments specified.\n' % self.nam e)
996 sys.stderr.write('%s No %s*.log files found in "%s".\n' % (self .name_spaces, self.prefix, directory))
997 sys.stderr.write('%s Type "%s help mem" for help.\n' % (self.na me_spaces, self.name))
998 sys.exit(1)
999
1000 else:
1001
1002 args = self.args_to_files(args, tail)
1003
1004 cwd_ = os.getcwd() + os.sep
1005
1006 if format == 'ascii':
1007
1008 self.ascii_table(args, tuple(self.stages), self.get_memory, logfile_ path)
1009
1010 elif format == 'gnuplot':
1011
1012 results = self.collect_results(args, self.get_memory,
1013 self.stage_strings[stage])
1014
1015 self.gnuplot_results(results)
1016
1017 else:
1018
1019 sys.stderr.write('%s: mem: Unknown format "%s".\n' % (self.name, for mat))
1020 sys.exit(1)
1021
1022 return 0
1023
1024 #
1025
1026 def help_obj(self):
1027 help = """\
1028 Usage: scons-time obj [OPTIONS] OBJECT FILE [...]
1029
1030 -C DIR, --chdir=DIR Change to DIR before looking for files
1031 -f FILE, --file=FILE Read configuration from specified FILE
1032 --fmt=FORMAT, --format=FORMAT Print data in specified FORMAT
1033 -h, --help Print this help and exit
1034 -p STRING, --prefix=STRING Use STRING as log file/profile prefix
1035 --stage=STAGE Plot memory at the specified stage:
1036 pre-read, post-read, pre-build,
1037 post-build (default: post-build)
1038 -t NUMBER, --tail=NUMBER Only report the last NUMBER files
1039 --title=TITLE Specify the output plot TITLE
1040 """
1041 sys.stdout.write(self.outdent(help))
1042 sys.stdout.flush()
1043
1044 def do_obj(self, argv):
1045
1046 format = 'ascii'
1047 logfile_path = lambda x: x
1048 stage = self.default_stage
1049 tail = None
1050
1051 short_opts = '?C:f:hp:t:'
1052
1053 long_opts = [
1054 'chdir=',
1055 'file=',
1056 'fmt=',
1057 'format=',
1058 'help',
1059 'prefix=',
1060 'stage=',
1061 'tail=',
1062 'title=',
1063 ]
1064
1065 opts, args = getopt.getopt(argv[1:], short_opts, long_opts)
1066
1067 for o, a in opts:
1068 if o in ('-C', '--chdir'):
1069 self.chdir = a
1070 elif o in ('-f', '--file'):
1071 self.config_file = a
1072 elif o in ('--fmt', '--format'):
1073 format = a
1074 elif o in ('-?', '-h', '--help'):
1075 self.do_help(['help', 'obj'])
1076 sys.exit(0)
1077 elif o in ('-p', '--prefix'):
1078 self.prefix = a
1079 elif o in ('--stage',):
1080 if not a in self.stages:
1081 sys.stderr.write('%s: obj: Unrecognized stage "%s".\n' % (se lf.name, a))
1082 sys.stderr.write('%s Type "%s help obj" for help.\n' % (self.name_spaces, self.name))
1083 sys.exit(1)
1084 stage = a
1085 elif o in ('-t', '--tail'):
1086 tail = int(a)
1087 elif o in ('--title',):
1088 self.title = a
1089
1090 if not args:
1091 sys.stderr.write('%s: obj: Must specify an object name.\n' % self.na me)
1092 sys.stderr.write('%s Type "%s help obj" for help.\n' % (self.n ame_spaces, self.name))
1093 sys.exit(1)
1094
1095 object_name = args.pop(0)
1096
1097 if self.config_file:
1098 HACK_for_exec(open(self.config_file, 'rU').read(), self.__dict__)
1099
1100 if self.chdir:
1101 os.chdir(self.chdir)
1102 logfile_path = lambda x: os.path.join(self.chdir, x)
1103
1104 if not args:
1105
1106 pattern = '%s*.log' % self.prefix
1107 args = self.args_to_files([pattern], tail)
1108
1109 if not args:
1110 if self.chdir:
1111 directory = self.chdir
1112 else:
1113 directory = os.getcwd()
1114
1115 sys.stderr.write('%s: obj: No arguments specified.\n' % self.nam e)
1116 sys.stderr.write('%s No %s*.log files found in "%s".\n' % (self .name_spaces, self.prefix, directory))
1117 sys.stderr.write('%s Type "%s help obj" for help.\n' % (self.na me_spaces, self.name))
1118 sys.exit(1)
1119
1120 else:
1121
1122 args = self.args_to_files(args, tail)
1123
1124 cwd_ = os.getcwd() + os.sep
1125
1126 if format == 'ascii':
1127
1128 self.ascii_table(args, tuple(self.stages), self.get_object_counts, l ogfile_path, object_name)
1129
1130 elif format == 'gnuplot':
1131
1132 stage_index = 0
1133 for s in self.stages:
1134 if stage == s:
1135 break
1136 stage_index = stage_index + 1
1137
1138 results = self.collect_results(args, self.get_object_counts,
1139 object_name, stage_index)
1140
1141 self.gnuplot_results(results)
1142
1143 else:
1144
1145 sys.stderr.write('%s: obj: Unknown format "%s".\n' % (self.name, for mat))
1146 sys.exit(1)
1147
1148 return 0
1149
1150 #
1151
1152 def help_run(self):
1153 help = """\
1154 Usage: scons-time run [OPTIONS] [FILE ...]
1155
1156 --aegis=PROJECT Use SCons from the Aegis PROJECT
1157 --chdir=DIR Name of unpacked directory for chdir
1158 -f FILE, --file=FILE Read configuration from specified FILE
1159 -h, --help Print this help and exit
1160 -n, --no-exec No execute, just print command lines
1161 --number=NUMBER Put output in files for run NUMBER
1162 --outdir=OUTDIR Put output files in OUTDIR
1163 -p STRING, --prefix=STRING Use STRING as log file/profile prefix
1164 --python=PYTHON Time using the specified PYTHON
1165 -q, --quiet Don't print command lines
1166 --scons=SCONS Time using the specified SCONS
1167 --svn=URL, --subversion=URL Use SCons from Subversion URL
1168 -v, --verbose Display output of commands
1169 """
1170 sys.stdout.write(self.outdent(help))
1171 sys.stdout.flush()
1172
1173 def do_run(self, argv):
1174 """
1175 """
1176 run_number_list = [None]
1177
1178 short_opts = '?f:hnp:qs:v'
1179
1180 long_opts = [
1181 'aegis=',
1182 'file=',
1183 'help',
1184 'no-exec',
1185 'number=',
1186 'outdir=',
1187 'prefix=',
1188 'python=',
1189 'quiet',
1190 'scons=',
1191 'svn=',
1192 'subdir=',
1193 'subversion=',
1194 'verbose',
1195 ]
1196
1197 opts, args = getopt.getopt(argv[1:], short_opts, long_opts)
1198
1199 for o, a in opts:
1200 if o in ('--aegis',):
1201 self.aegis_project = a
1202 elif o in ('-f', '--file'):
1203 self.config_file = a
1204 elif o in ('-?', '-h', '--help'):
1205 self.do_help(['help', 'run'])
1206 sys.exit(0)
1207 elif o in ('-n', '--no-exec'):
1208 self.execute = self._do_not_execute
1209 elif o in ('--number',):
1210 run_number_list = self.split_run_numbers(a)
1211 elif o in ('--outdir',):
1212 self.outdir = a
1213 elif o in ('-p', '--prefix'):
1214 self.prefix = a
1215 elif o in ('--python',):
1216 self.python = a
1217 elif o in ('-q', '--quiet'):
1218 self.display = self._do_not_display
1219 elif o in ('-s', '--subdir'):
1220 self.subdir = a
1221 elif o in ('--scons',):
1222 self.scons = a
1223 elif o in ('--svn', '--subversion'):
1224 self.subversion_url = a
1225 elif o in ('-v', '--verbose'):
1226 self.redirect = tee_to_file
1227 self.verbose = True
1228 self.svn_co_flag = ''
1229
1230 if not args and not self.config_file:
1231 sys.stderr.write('%s: run: No arguments or -f config file specified. \n' % self.name)
1232 sys.stderr.write('%s Type "%s help run" for help.\n' % (self.name_s paces, self.name))
1233 sys.exit(1)
1234
1235 if self.config_file:
1236 exec open(self.config_file, 'rU').read() in self.__dict__
1237
1238 if args:
1239 self.archive_list = args
1240
1241 archive_file_name = os.path.split(self.archive_list[0])[1]
1242
1243 if not self.subdir:
1244 self.subdir = self.archive_splitext(archive_file_name)[0]
1245
1246 if not self.prefix:
1247 self.prefix = self.archive_splitext(archive_file_name)[0]
1248
1249 prepare = None
1250 if self.subversion_url:
1251 prepare = self.prep_subversion_run
1252 elif self.aegis_project:
1253 prepare = self.prep_aegis_run
1254
1255 for run_number in run_number_list:
1256 self.individual_run(run_number, self.archive_list, prepare)
1257
1258 def split_run_numbers(self, s):
1259 result = []
1260 for n in s.split(','):
1261 try:
1262 x, y = n.split('-')
1263 except ValueError:
1264 result.append(int(n))
1265 else:
1266 result.extend(list(range(int(x), int(y)+1)))
1267 return result
1268
1269 def scons_path(self, dir):
1270 return os.path.join(dir, 'src', 'script', 'scons.py')
1271
1272 def scons_lib_dir_path(self, dir):
1273 return os.path.join(dir, 'src', 'engine')
1274
1275 def prep_aegis_run(self, commands, removals):
1276 self.aegis_tmpdir = make_temp_file(prefix = self.name + '-aegis-')
1277 removals.append((shutil.rmtree, 'rm -rf %%s', self.aegis_tmpdir))
1278
1279 self.aegis_parent_project = os.path.splitext(self.aegis_project)[0]
1280 self.scons = self.scons_path(self.aegis_tmpdir)
1281 self.scons_lib_dir = self.scons_lib_dir_path(self.aegis_tmpdir)
1282
1283 commands.extend([
1284 'mkdir %(aegis_tmpdir)s',
1285 (lambda: os.chdir(self.aegis_tmpdir), 'cd %(aegis_tmpdir)s'),
1286 '%(aegis)s -cp -ind -p %(aegis_parent_project)s .',
1287 '%(aegis)s -cp -ind -p %(aegis_project)s -delta %(run_number)s .',
1288 ])
1289
1290 def prep_subversion_run(self, commands, removals):
1291 self.svn_tmpdir = make_temp_file(prefix = self.name + '-svn-')
1292 removals.append((shutil.rmtree, 'rm -rf %%s', self.svn_tmpdir))
1293
1294 self.scons = self.scons_path(self.svn_tmpdir)
1295 self.scons_lib_dir = self.scons_lib_dir_path(self.svn_tmpdir)
1296
1297 commands.extend([
1298 'mkdir %(svn_tmpdir)s',
1299 '%(svn)s co %(svn_co_flag)s -r %(run_number)s %(subversion_url)s %(s vn_tmpdir)s',
1300 ])
1301
1302 def individual_run(self, run_number, archive_list, prepare=None):
1303 """
1304 Performs an individual run of the default SCons invocations.
1305 """
1306
1307 commands = []
1308 removals = []
1309
1310 if prepare:
1311 prepare(commands, removals)
1312
1313 save_scons = self.scons
1314 save_scons_wrapper = self.scons_wrapper
1315 save_scons_lib_dir = self.scons_lib_dir
1316
1317 if self.outdir is None:
1318 self.outdir = self.orig_cwd
1319 elif not os.path.isabs(self.outdir):
1320 self.outdir = os.path.join(self.orig_cwd, self.outdir)
1321
1322 if self.scons is None:
1323 self.scons = self.scons_path(self.orig_cwd)
1324
1325 if self.scons_lib_dir is None:
1326 self.scons_lib_dir = self.scons_lib_dir_path(self.orig_cwd)
1327
1328 if self.scons_wrapper is None:
1329 self.scons_wrapper = self.scons
1330
1331 if not run_number:
1332 run_number = self.find_next_run_number(self.outdir, self.prefix)
1333
1334 self.run_number = str(run_number)
1335
1336 self.prefix_run = self.prefix + '-%03d' % run_number
1337
1338 if self.targets0 is None:
1339 self.targets0 = self.startup_targets
1340 if self.targets1 is None:
1341 self.targets1 = self.targets
1342 if self.targets2 is None:
1343 self.targets2 = self.targets
1344
1345 self.tmpdir = make_temp_file(prefix = self.name + '-')
1346
1347 commands.extend([
1348 'mkdir %(tmpdir)s',
1349
1350 (os.chdir, 'cd %%s', self.tmpdir),
1351 ])
1352
1353 for archive in archive_list:
1354 if not os.path.isabs(archive):
1355 archive = os.path.join(self.orig_cwd, archive)
1356 if os.path.isdir(archive):
1357 dest = os.path.split(archive)[1]
1358 commands.append((shutil.copytree, 'cp -r %%s %%s', archive, dest ))
1359 else:
1360 suffix = self.archive_splitext(archive)[1]
1361 unpack_command = self.unpack_map.get(suffix)
1362 if not unpack_command:
1363 dest = os.path.split(archive)[1]
1364 commands.append((shutil.copyfile, 'cp %%s %%s', archive, des t))
1365 else:
1366 commands.append(unpack_command + (archive,))
1367
1368 commands.extend([
1369 (os.chdir, 'cd %%s', self.subdir),
1370 ])
1371
1372 commands.extend(self.initial_commands)
1373
1374 commands.extend([
1375 (lambda: read_tree('.'),
1376 'find * -type f | xargs cat > /dev/null'),
1377
1378 (self.set_env, 'export %%s=%%s',
1379 'SCONS_LIB_DIR', self.scons_lib_dir),
1380
1381 '%(python)s %(scons_wrapper)s --version',
1382 ])
1383
1384 index = 0
1385 for run_command in self.run_commands:
1386 setattr(self, 'prof%d' % index, self.profile_name(index))
1387 c = (
1388 self.log_execute,
1389 self.log_display,
1390 run_command,
1391 self.logfile_name(index),
1392 )
1393 commands.append(c)
1394 index = index + 1
1395
1396 commands.extend([
1397 (os.chdir, 'cd %%s', self.orig_cwd),
1398 ])
1399
1400 if not os.environ.get('PRESERVE'):
1401 commands.extend(removals)
1402
1403 commands.append((shutil.rmtree, 'rm -rf %%s', self.tmpdir))
1404
1405 self.run_command_list(commands, self.__dict__)
1406
1407 self.scons = save_scons
1408 self.scons_lib_dir = save_scons_lib_dir
1409 self.scons_wrapper = save_scons_wrapper
1410
1411 #
1412
1413 def help_time(self):
1414 help = """\
1415 Usage: scons-time time [OPTIONS] FILE [...]
1416
1417 -C DIR, --chdir=DIR Change to DIR before looking for files
1418 -f FILE, --file=FILE Read configuration from specified FILE
1419 --fmt=FORMAT, --format=FORMAT Print data in specified FORMAT
1420 -h, --help Print this help and exit
1421 -p STRING, --prefix=STRING Use STRING as log file/profile prefix
1422 -t NUMBER, --tail=NUMBER Only report the last NUMBER files
1423 --which=TIMER Plot timings for TIMER: total,
1424 SConscripts, SCons, commands.
1425 """
1426 sys.stdout.write(self.outdent(help))
1427 sys.stdout.flush()
1428
1429 def do_time(self, argv):
1430
1431 format = 'ascii'
1432 logfile_path = lambda x: x
1433 tail = None
1434 which = 'total'
1435
1436 short_opts = '?C:f:hp:t:'
1437
1438 long_opts = [
1439 'chdir=',
1440 'file=',
1441 'fmt=',
1442 'format=',
1443 'help',
1444 'prefix=',
1445 'tail=',
1446 'title=',
1447 'which=',
1448 ]
1449
1450 opts, args = getopt.getopt(argv[1:], short_opts, long_opts)
1451
1452 for o, a in opts:
1453 if o in ('-C', '--chdir'):
1454 self.chdir = a
1455 elif o in ('-f', '--file'):
1456 self.config_file = a
1457 elif o in ('--fmt', '--format'):
1458 format = a
1459 elif o in ('-?', '-h', '--help'):
1460 self.do_help(['help', 'time'])
1461 sys.exit(0)
1462 elif o in ('-p', '--prefix'):
1463 self.prefix = a
1464 elif o in ('-t', '--tail'):
1465 tail = int(a)
1466 elif o in ('--title',):
1467 self.title = a
1468 elif o in ('--which',):
1469 if not a in self.time_strings.keys():
1470 sys.stderr.write('%s: time: Unrecognized timer "%s".\n' % (s elf.name, a))
1471 sys.stderr.write('%s Type "%s help time" for help.\n' % (se lf.name_spaces, self.name))
1472 sys.exit(1)
1473 which = a
1474
1475 if self.config_file:
1476 HACK_for_exec(open(self.config_file, 'rU').read(), self.__dict__)
1477
1478 if self.chdir:
1479 os.chdir(self.chdir)
1480 logfile_path = lambda x: os.path.join(self.chdir, x)
1481
1482 if not args:
1483
1484 pattern = '%s*.log' % self.prefix
1485 args = self.args_to_files([pattern], tail)
1486
1487 if not args:
1488 if self.chdir:
1489 directory = self.chdir
1490 else:
1491 directory = os.getcwd()
1492
1493 sys.stderr.write('%s: time: No arguments specified.\n' % self.na me)
1494 sys.stderr.write('%s No %s*.log files found in "%s".\n' % (self .name_spaces, self.prefix, directory))
1495 sys.stderr.write('%s Type "%s help time" for help.\n' % (self.n ame_spaces, self.name))
1496 sys.exit(1)
1497
1498 else:
1499
1500 args = self.args_to_files(args, tail)
1501
1502 cwd_ = os.getcwd() + os.sep
1503
1504 if format == 'ascii':
1505
1506 columns = ("Total", "SConscripts", "SCons", "commands")
1507 self.ascii_table(args, columns, self.get_debug_times, logfile_path)
1508
1509 elif format == 'gnuplot':
1510
1511 results = self.collect_results(args, self.get_debug_times,
1512 self.time_strings[which])
1513
1514 self.gnuplot_results(results, fmt='%s %.6f')
1515
1516 else:
1517
1518 sys.stderr.write('%s: time: Unknown format "%s".\n' % (self.name, fo rmat))
1519 sys.exit(1)
1520
1521 if __name__ == '__main__':
1522 opts, args = getopt.getopt(sys.argv[1:], 'h?V', ['help', 'version'])
1523
1524 ST = SConsTimer()
1525
1526 for o, a in opts:
1527 if o in ('-?', '-h', '--help'):
1528 ST.do_help(['help'])
1529 sys.exit(0)
1530 elif o in ('-V', '--version'):
1531 sys.stdout.write('scons-time version\n')
1532 sys.exit(0)
1533
1534 if not args:
1535 sys.stderr.write('Type "%s help" for usage.\n' % ST.name)
1536 sys.exit(1)
1537
1538 ST.execute_subcommand(args)
1539
1540 # Local Variables:
1541 # tab-width:4
1542 # indent-tabs-mode:nil
1543 # End:
1544 # vim: set expandtab tabstop=4 shiftwidth=4:
OLDNEW
« no previous file with comments | « scons-2.0.1/script/scons.bat ('k') | scons-2.0.1/script/sconsign » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698