1 """SCons.Script
2
3 This file implements the main() function used by the scons script.
4
5 Architecturally, this *is* the scons script, and will likely only be
6 called from the external "scons" wrapper. Consequently, anything here
7 should not be, or be considered, part of the build engine. If it's
8 something that we expect other software to want to use, it should go in
9 some other module. If it's specific to the "scons" script invocation,
10 it goes here.
11 """
12
13 unsupported_python_version = (2, 3, 0)
14 deprecated_python_version = (2, 7, 0)
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 __revision__ = "src/engine/SCons/Script/Main.py 2014/09/27 12:51:43 garyo"
38
39 import SCons.compat
40
41 import os
42 import sys
43 import time
44 import traceback
45
46
47
48
49
50
51
52
53
54
55 import SCons.CacheDir
56 import SCons.Debug
57 import SCons.Defaults
58 import SCons.Environment
59 import SCons.Errors
60 import SCons.Job
61 import SCons.Node
62 import SCons.Node.FS
63 import SCons.Platform
64 import SCons.SConf
65 import SCons.Script
66 import SCons.Taskmaster
67 import SCons.Util
68 import SCons.Warnings
69
70 import SCons.Script.Interactive
71
81
83
84
85
86 sys.stderr = sys.__stderr__
87 sys.stdout = sys.__stdout__
88
91
92 display = SCons.Util.display
93 progress_display = SCons.Util.DisplayEngine()
94
95 first_command_start = None
96 last_command_end = None
97
99 prev = ''
100 count = 0
101 target_string = '$TARGET'
102
103 - def __init__(self, obj, interval=1, file=None, overwrite=False):
104 if file is None:
105 file = sys.stdout
106
107 self.obj = obj
108 self.file = file
109 self.interval = interval
110 self.overwrite = overwrite
111
112 if callable(obj):
113 self.func = obj
114 elif SCons.Util.is_List(obj):
115 self.func = self.spinner
116 elif obj.find(self.target_string) != -1:
117 self.func = self.replace_string
118 else:
119 self.func = self.string
120
125
127 if self.prev:
128 length = len(self.prev)
129 if self.prev[-1] in ('\n', '\r'):
130 length = length - 1
131 self.write(' ' * length + '\r')
132 self.prev = ''
133
135 self.write(self.obj[self.count % len(self.obj)])
136
139
142
149
150 ProgressObject = SCons.Util.Null()
151
155
156
157
158
159 _BuildFailures = []
160
163
164 -class BuildTask(SCons.Taskmaster.OutOfDateTask):
165 """An SCons build task."""
166 progress = ProgressObject
167
170
174
181
196
211
213 t = self.targets[0]
214 if self.top and not t.has_builder() and not t.side_effect:
215 if not t.exists():
216 if t.__class__.__name__ in ('File', 'Dir', 'Entry'):
217 errstr="Do not know how to make %s target `%s' (%s)." % (t.__class__.__name__, t, t.abspath)
218 else:
219 errstr="Do not know how to make %s target `%s'." % (t.__class__.__name__, t)
220 sys.stderr.write("scons: *** " + errstr)
221 if not self.options.keep_going:
222 sys.stderr.write(" Stop.")
223 sys.stderr.write("\n")
224 try:
225 raise SCons.Errors.BuildError(t, errstr)
226 except KeyboardInterrupt:
227 raise
228 except:
229 self.exception_set()
230 self.do_failed()
231 else:
232 print "scons: Nothing to be done for `%s'." % t
233 SCons.Taskmaster.OutOfDateTask.executed(self)
234 else:
235 SCons.Taskmaster.OutOfDateTask.executed(self)
236
238
239
240
241 exc_info = self.exc_info()
242 try:
243 t, e, tb = exc_info
244 except ValueError:
245 t, e = exc_info
246 tb = None
247
248 if t is None:
249
250
251 try:
252 t, e, tb = sys.exc_info()[:]
253 except ValueError:
254 t, e = exc_info
255 tb = None
256
257
258
259 if e is None:
260 e = t
261
262 buildError = SCons.Errors.convert_to_BuildError(e)
263 if not buildError.node:
264 buildError.node = self.node
265
266 node = buildError.node
267 if not SCons.Util.is_List(node):
268 node = [ node ]
269 nodename = ', '.join(map(str, node))
270
271 errfmt = "scons: *** [%s] %s\n"
272 sys.stderr.write(errfmt % (nodename, buildError))
273
274 if (buildError.exc_info[2] and buildError.exc_info[1] and
275 not isinstance(
276 buildError.exc_info[1],
277 (EnvironmentError, SCons.Errors.StopError,
278 SCons.Errors.UserError))):
279 type, value, trace = buildError.exc_info
280 if tb and print_stacktrace:
281 sys.stderr.write("scons: internal stack trace:\n")
282 traceback.print_tb(tb, file=sys.stderr)
283 traceback.print_exception(type, value, trace)
284 elif tb and print_stacktrace:
285 sys.stderr.write("scons: internal stack trace:\n")
286 traceback.print_tb(tb, file=sys.stderr)
287
288 self.exception = (e, buildError, tb)
289 self.do_failed(buildError.exitstatus)
290
291 self.exc_clear()
292
293 - def postprocess(self):
294 if self.top:
295 t = self.targets[0]
296 for tp in self.options.tree_printers:
297 tp.display(t)
298 if self.options.debug_includes:
299 tree = t.render_include_tree()
300 if tree:
301 print
302 print tree
303 SCons.Taskmaster.OutOfDateTask.postprocess(self)
304
306 """Make a task ready for execution"""
307 SCons.Taskmaster.OutOfDateTask.make_ready(self)
308 if self.out_of_date and self.options.debug_explain:
309 explanation = self.out_of_date[0].explain()
310 if explanation:
311 sys.stdout.write("scons: " + explanation)
312
313 -class CleanTask(SCons.Taskmaster.AlwaysTask):
393
395 """An SCons task for the -q (question) option."""
398
407
410
411
413 - def __init__(self, derived=False, prune=False, status=False):
414 self.derived = derived
415 self.prune = prune
416 self.status = status
429
430
432 return sys.version.split()[0]
433
436
439
440
441
442
443 print_objects = 0
444 print_memoizer = 0
445 print_stacktrace = 0
446 print_time = 0
447 sconscript_time = 0
448 cumulative_command_time = 0
449 exit_status = 0
450 this_build_status = 0
451 num_jobs = None
452 delayed_warnings = []
453
455 """
456 A do-nothing option parser, used for the initial OptionsParser variable.
457
458 During normal SCons operation, the OptionsParser is created right
459 away by the main() function. Certain tests scripts however, can
460 introspect on different Tool modules, the initialization of which
461 can try to add a new, local option to an otherwise uninitialized
462 OptionsParser object. This allows that introspection to happen
463 without blowing up.
464
465 """
469 values = FakeOptionValues()
472
473 OptionsParser = FakeOptionParser()
474
480
483
486
487
500
506 stats_table = {}
507 for s in self.stats:
508 for n in [t[0] for t in s]:
509 stats_table[n] = [0, 0, 0, 0]
510 i = 0
511 for s in self.stats:
512 for n, c in s:
513 stats_table[n][i] = c
514 i = i + 1
515 self.outfp.write("Object counts:\n")
516 pre = [" "]
517 post = [" %s\n"]
518 l = len(self.stats)
519 fmt1 = ''.join(pre + [' %7s']*l + post)
520 fmt2 = ''.join(pre + [' %7d']*l + post)
521 labels = self.labels[:l]
522 labels.append(("", "Class"))
523 self.outfp.write(fmt1 % tuple([x[0] for x in labels]))
524 self.outfp.write(fmt1 % tuple([x[1] for x in labels]))
525 for k in sorted(stats_table.keys()):
526 r = stats_table[k][:l] + [k]
527 self.outfp.write(fmt2 % tuple(r))
528
529 count_stats = CountStats()
530
536 fmt = 'Memory %-32s %12d\n'
537 for label, stats in zip(self.labels, self.stats):
538 self.outfp.write(fmt % (label, stats))
539
540 memory_stats = MemStats()
541
542
543
545 """Handle syntax errors. Print out a message and show where the error
546 occurred.
547 """
548 etype, value, tb = sys.exc_info()
549 lines = traceback.format_exception_only(etype, value)
550 for line in lines:
551 sys.stderr.write(line+'\n')
552 sys.exit(2)
553
555 """
556 Find the deepest stack frame that is not part of SCons.
557
558 Input is a "pre-processed" stack trace in the form
559 returned by traceback.extract_tb() or traceback.extract_stack()
560 """
561
562 tb.reverse()
563
564
565
566 for frame in tb:
567 filename = frame[0]
568 if filename.find(os.sep+'SCons'+os.sep) == -1:
569 return frame
570 return tb[0]
571
573 """Handle user errors. Print out a message and a description of the
574 error, along with the line number and routine where it occured.
575 The file and line number will be the deepest stack frame that is
576 not part of SCons itself.
577 """
578 global print_stacktrace
579 etype, value, tb = sys.exc_info()
580 if print_stacktrace:
581 traceback.print_exception(etype, value, tb)
582 filename, lineno, routine, dummy = find_deepest_user_frame(traceback.extract_tb(tb))
583 sys.stderr.write("\nscons: *** %s\n" % value)
584 sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine))
585 sys.exit(2)
586
588 """Handle user warnings. Print out a message and a description of
589 the warning, along with the line number and routine where it occured.
590 The file and line number will be the deepest stack frame that is
591 not part of SCons itself.
592 """
593 etype, value, tb = sys.exc_info()
594 filename, lineno, routine, dummy = find_deepest_user_frame(traceback.extract_tb(tb))
595 sys.stderr.write("\nscons: warning: %s\n" % e)
596 sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine))
597
599 """Slightly different from _scons_user_warning in that we use the
600 *current call stack* rather than sys.exc_info() to get our stack trace.
601 This is used by the warnings framework to print warnings."""
602 filename, lineno, routine, dummy = find_deepest_user_frame(traceback.extract_stack())
603 sys.stderr.write("\nscons: warning: %s\n" % e.args[0])
604 sys.stderr.write('File "%s", line %d, in %s\n' % (filename, lineno, routine))
605
607 """Handle all errors but user errors. Print out a message telling
608 the user what to do in this case and print a normal trace.
609 """
610 print 'internal error'
611 traceback.print_exc()
612 sys.exit(2)
613
615 """This function checks that an SConstruct file exists in a directory.
616 If so, it returns the path of the file. By default, it checks the
617 current directory.
618 """
619 if not filelist:
620 filelist = ['SConstruct', 'Sconstruct', 'sconstruct']
621 for file in filelist:
622 sfile = os.path.join(dirname, file)
623 if os.path.isfile(sfile):
624 return sfile
625 if not os.path.isabs(sfile):
626 for rep in repositories:
627 if os.path.isfile(os.path.join(rep, sfile)):
628 return sfile
629 return None
630
676
685
687 """Load the site_scons dir under topdir.
688 Prepends site_scons to sys.path, imports site_scons/site_init.py,
689 and prepends site_scons/site_tools to default toolpath."""
690 if site_dir_name:
691 err_if_not_found = True
692 else:
693 site_dir_name = "site_scons"
694 err_if_not_found = False
695
696 site_dir = os.path.join(topdir, site_dir_name)
697 if not os.path.exists(site_dir):
698 if err_if_not_found:
699 raise SCons.Errors.UserError("site dir %s not found."%site_dir)
700 return
701
702 site_init_filename = "site_init.py"
703 site_init_modname = "site_init"
704 site_tools_dirname = "site_tools"
705
706 sys.path = [os.path.abspath(site_dir)] + sys.path
707 site_init_file = os.path.join(site_dir, site_init_filename)
708 site_tools_dir = os.path.join(site_dir, site_tools_dirname)
709 if os.path.exists(site_init_file):
710 import imp, re
711
712 try:
713 try:
714 fp, pathname, description = imp.find_module(site_init_modname,
715 [site_dir])
716
717
718
719
720
721
722
723 try:
724 m = sys.modules['SCons.Script']
725 except Exception, e:
726 fmt = 'cannot import site_init.py: missing SCons.Script module %s'
727 raise SCons.Errors.InternalError(fmt % repr(e))
728 try:
729 sfx = description[0]
730 modname = os.path.basename(pathname)[:-len(sfx)]
731 site_m = {"__file__": pathname, "__name__": modname, "__doc__": None}
732 re_special = re.compile("__[^_]+__")
733 for k in m.__dict__.keys():
734 if not re_special.match(k):
735 site_m[k] = m.__dict__[k]
736
737
738 exec fp in site_m
739 except KeyboardInterrupt:
740 raise
741 except Exception, e:
742 fmt = '*** Error loading site_init file %s:\n'
743 sys.stderr.write(fmt % repr(site_init_file))
744 raise
745 else:
746 for k in site_m:
747 if not re_special.match(k):
748 m.__dict__[k] = site_m[k]
749 except KeyboardInterrupt:
750 raise
751 except ImportError, e:
752 fmt = '*** cannot import site init file %s:\n'
753 sys.stderr.write(fmt % repr(site_init_file))
754 raise
755 finally:
756 if fp:
757 fp.close()
758 if os.path.exists(site_tools_dir):
759
760 SCons.Tool.DefaultToolpath.insert(0, os.path.abspath(site_tools_dir))
761
763 """Load all of the predefined site_scons dir.
764 Order is significant; we load them in order from most generic
765 (machine-wide) to most specific (topdir).
766 The verbose argument is only for testing.
767 """
768 platform = SCons.Platform.platform_default()
769
770 def homedir(d):
771 return os.path.expanduser('~/'+d)
772
773 if platform == 'win32' or platform == 'cygwin':
774
775
776
777 sysdirs=[
778 os.path.expandvars('$ALLUSERSPROFILE\\Application Data\\scons'),
779 os.path.expandvars('$USERPROFILE\\Local Settings\\Application Data\\scons')]
780 appdatadir = os.path.expandvars('$APPDATA\\scons')
781 if appdatadir not in sysdirs:
782 sysdirs.append(appdatadir)
783 sysdirs.append(homedir('.scons'))
784
785 elif platform == 'darwin':
786 sysdirs=['/Library/Application Support/SCons',
787 '/opt/local/share/scons',
788 '/sw/share/scons',
789 homedir('Library/Application Support/SCons'),
790 homedir('.scons')]
791 elif platform == 'sunos':
792 sysdirs=['/opt/sfw/scons',
793 '/usr/share/scons',
794 homedir('.scons')]
795 else:
796
797 sysdirs=['/usr/share/scons',
798 homedir('.scons')]
799
800 dirs=sysdirs + [topdir]
801 for d in dirs:
802 if verbose:
803 print "Loading site dir ", d
804 _load_site_scons_dir(d)
805
808
822
824 path = module.__path__
825 return "\t%s path: %s\n"%(label,path)
826
828 global exit_status
829 global this_build_status
830
831 options = parser.values
832
833
834
835
836
837
838
839
840 default_warnings = [ SCons.Warnings.WarningOnByDefault,
841 SCons.Warnings.DeprecatedWarning,
842 ]
843
844 for warning in default_warnings:
845 SCons.Warnings.enableWarningClass(warning)
846 SCons.Warnings._warningOut = _scons_internal_warning
847 SCons.Warnings.process_warn_strings(options.warn)
848
849
850
851
852 try:
853 dw = options.delayed_warnings
854 except AttributeError:
855 pass
856 else:
857 delayed_warnings.extend(dw)
858 for warning_type, message in delayed_warnings:
859 SCons.Warnings.warn(warning_type, message)
860
861 if options.diskcheck:
862 SCons.Node.FS.set_diskcheck(options.diskcheck)
863
864
865
866
867
868
869 if options.directory:
870 script_dir = os.path.abspath(_create_path(options.directory))
871 else:
872 script_dir = os.getcwd()
873
874 target_top = None
875 if options.climb_up:
876 target_top = '.'
877 while script_dir and not _SConstruct_exists(script_dir,
878 options.repository,
879 options.file):
880 script_dir, last_part = os.path.split(script_dir)
881 if last_part:
882 target_top = os.path.join(last_part, target_top)
883 else:
884 script_dir = ''
885
886 if script_dir and script_dir != os.getcwd():
887 if not options.silent:
888 display("scons: Entering directory `%s'" % script_dir)
889 try:
890 os.chdir(script_dir)
891 except OSError:
892 sys.stderr.write("Could not change directory to %s\n" % script_dir)
893
894
895
896
897 fs = SCons.Node.FS.get_default_fs()
898
899 for rep in options.repository:
900 fs.Repository(rep)
901
902
903
904
905 scripts = []
906 if options.file:
907 scripts.extend(options.file)
908 if not scripts:
909 sfile = _SConstruct_exists(repositories=options.repository,
910 filelist=options.file)
911 if sfile:
912 scripts.append(sfile)
913
914 if not scripts:
915 if options.help:
916
917
918
919 raise SConsPrintHelpException
920 raise SCons.Errors.UserError("No SConstruct file found.")
921
922 if scripts[0] == "-":
923 d = fs.getcwd()
924 else:
925 d = fs.File(scripts[0]).dir
926 fs.set_SConstruct_dir(d)
927
928 _set_debug_values(options)
929 SCons.Node.implicit_cache = options.implicit_cache
930 SCons.Node.implicit_deps_changed = options.implicit_deps_changed
931 SCons.Node.implicit_deps_unchanged = options.implicit_deps_unchanged
932
933 if options.no_exec:
934 SCons.SConf.dryrun = 1
935 SCons.Action.execute_actions = None
936 if options.question:
937 SCons.SConf.dryrun = 1
938 if options.clean:
939 SCons.SConf.SetBuildType('clean')
940 if options.help:
941 SCons.SConf.SetBuildType('help')
942 SCons.SConf.SetCacheMode(options.config)
943 SCons.SConf.SetProgressDisplay(progress_display)
944
945 if options.no_progress or options.silent:
946 progress_display.set_mode(0)
947
948 if options.site_dir:
949 _load_site_scons_dir(d.path, options.site_dir)
950 elif not options.no_site_dir:
951 _load_all_site_scons_dirs(d.path)
952
953 if options.include_dir:
954 sys.path = options.include_dir + sys.path
955
956
957
958
959
960
961 if options.interactive:
962 SCons.Node.interactive = True
963
964
965
966
967 targets = []
968 xmit_args = []
969 for a in parser.largs:
970 if a[:1] == '-':
971 continue
972 if '=' in a:
973 xmit_args.append(a)
974 else:
975 targets.append(a)
976 SCons.Script._Add_Targets(targets + parser.rargs)
977 SCons.Script._Add_Arguments(xmit_args)
978
979
980
981
982
983
984
985
986
987 if not hasattr(sys.stdout, 'isatty') or not sys.stdout.isatty():
988 sys.stdout = SCons.Util.Unbuffered(sys.stdout)
989 if not hasattr(sys.stderr, 'isatty') or not sys.stderr.isatty():
990 sys.stderr = SCons.Util.Unbuffered(sys.stderr)
991
992 memory_stats.append('before reading SConscript files:')
993 count_stats.append(('pre-', 'read'))
994
995
996
997 progress_display("scons: Reading SConscript files ...")
998
999 start_time = time.time()
1000 try:
1001 for script in scripts:
1002 SCons.Script._SConscript._SConscript(fs, script)
1003 except SCons.Errors.StopError, e:
1004
1005
1006
1007
1008
1009 revert_io()
1010 sys.stderr.write("scons: *** %s Stop.\n" % e)
1011 sys.exit(2)
1012 global sconscript_time
1013 sconscript_time = time.time() - start_time
1014
1015 progress_display("scons: done reading SConscript files.")
1016
1017 memory_stats.append('after reading SConscript files:')
1018 count_stats.append(('post-', 'read'))
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029 SCons.Warnings.process_warn_strings(options.warn)
1030
1031
1032
1033
1034 if python_version_deprecated():
1035 msg = "Support for pre-%s Python version (%s) is deprecated.\n" + \
1036 " If this will cause hardship, contact scons-dev@scons.org"
1037 deprecated_version_string = ".".join(map(str, deprecated_python_version))
1038 SCons.Warnings.warn(SCons.Warnings.PythonVersionWarning,
1039 msg % (deprecated_version_string, python_version_string()))
1040
1041 if not options.help:
1042
1043
1044
1045 if SCons.SConf.NeedConfigHBuilder():
1046 SCons.SConf.CreateConfigHBuilder(SCons.Defaults.DefaultEnvironment())
1047
1048
1049
1050
1051
1052
1053
1054 parser.preserve_unknown_options = False
1055 parser.parse_args(parser.largs, options)
1056
1057 if options.help:
1058 help_text = SCons.Script.help_text
1059 if help_text is None:
1060
1061
1062 raise SConsPrintHelpException
1063 else:
1064 print help_text
1065 print "Use scons -H for help about command-line options."
1066 exit_status = 0
1067 return
1068
1069
1070
1071
1072
1073
1074
1075 fs.chdir(fs.Top)
1076
1077 SCons.Node.FS.save_strings(1)
1078
1079
1080
1081 SCons.Node.implicit_cache = options.implicit_cache
1082 SCons.Node.FS.set_duplicate(options.duplicate)
1083 fs.set_max_drift(options.max_drift)
1084
1085 SCons.Job.explicit_stack_size = options.stack_size
1086
1087 if options.md5_chunksize:
1088 SCons.Node.FS.File.md5_chunksize = options.md5_chunksize
1089
1090 platform = SCons.Platform.platform_module()
1091
1092 if options.interactive:
1093 SCons.Script.Interactive.interact(fs, OptionsParser, options,
1094 targets, target_top)
1095
1096 else:
1097
1098
1099 nodes = _build_targets(fs, options, targets, target_top)
1100 if not nodes:
1101 revert_io()
1102 print 'Found nothing to build'
1103 exit_status = 2
1104
1169 d = list(filter(check_dir, SCons.Script.DEFAULT_TARGETS))
1170 SCons.Script.DEFAULT_TARGETS[:] = d
1171 target_top = None
1172 lookup_top = None
1173
1174 targets = SCons.Script._Get_Default_Targets(d, fs)
1175
1176 if not targets:
1177 sys.stderr.write("scons: *** No targets specified and no Default() targets found. Stop.\n")
1178 return None
1179
1180 def Entry(x, ltop=lookup_top, ttop=target_top, fs=fs):
1181 if isinstance(x, SCons.Node.Node):
1182 node = x
1183 else:
1184 node = None
1185
1186 if ltop is None: ltop = ''
1187
1188
1189
1190 curdir = os.path.join(os.getcwd(), str(ltop))
1191 for lookup in SCons.Node.arg2nodes_lookups:
1192 node = lookup(x, curdir=curdir)
1193 if node is not None:
1194 break
1195 if node is None:
1196 node = fs.Entry(x, directory=ltop, create=1)
1197 if ttop and not node.is_under(ttop):
1198 if isinstance(node, SCons.Node.FS.Dir) and ttop.is_under(node):
1199 node = ttop
1200 else:
1201 node = None
1202 return node
1203
1204 nodes = [_f for _f in map(Entry, targets) if _f]
1205
1206 task_class = BuildTask
1207 opening_message = "Building targets ..."
1208 closing_message = "done building targets."
1209 if options.keep_going:
1210 failure_message = "done building targets (errors occurred during build)."
1211 else:
1212 failure_message = "building terminated because of errors."
1213 if options.question:
1214 task_class = QuestionTask
1215 try:
1216 if options.clean:
1217 task_class = CleanTask
1218 opening_message = "Cleaning targets ..."
1219 closing_message = "done cleaning targets."
1220 if options.keep_going:
1221 failure_message = "done cleaning targets (errors occurred during clean)."
1222 else:
1223 failure_message = "cleaning terminated because of errors."
1224 except AttributeError:
1225 pass
1226
1227 task_class.progress = ProgressObject
1228
1229 if options.random:
1230 def order(dependencies):
1231 """Randomize the dependencies."""
1232 import random
1233
1234
1235 d = dependencies
1236 for i in range(len(d)-1, 0, -1):
1237 j = int(random.random() * (i+1))
1238 d[i], d[j] = d[j], d[i]
1239 return d
1240 else:
1241 def order(dependencies):
1242 """Leave the order of dependencies alone."""
1243 return dependencies
1244
1245 if options.taskmastertrace_file == '-':
1246 tmtrace = sys.stdout
1247 elif options.taskmastertrace_file:
1248 tmtrace = open(options.taskmastertrace_file, 'wb')
1249 else:
1250 tmtrace = None
1251 taskmaster = SCons.Taskmaster.Taskmaster(nodes, task_class, order, tmtrace)
1252
1253
1254
1255 BuildTask.options = options
1256
1257 global num_jobs
1258 num_jobs = options.num_jobs
1259 jobs = SCons.Job.Jobs(num_jobs, taskmaster)
1260 if num_jobs > 1:
1261 msg = None
1262 if jobs.num_jobs == 1:
1263 msg = "parallel builds are unsupported by this version of Python;\n" + \
1264 "\tignoring -j or num_jobs option.\n"
1265 elif sys.platform == 'win32':
1266 msg = fetch_win32_parallel_msg()
1267 if msg:
1268 SCons.Warnings.warn(SCons.Warnings.NoParallelSupportWarning, msg)
1269
1270 memory_stats.append('before building targets:')
1271 count_stats.append(('pre-', 'build'))
1272
1273 def jobs_postfunc(
1274 jobs=jobs,
1275 options=options,
1276 closing_message=closing_message,
1277 failure_message=failure_message
1278 ):
1279 if jobs.were_interrupted():
1280 if not options.no_progress and not options.silent:
1281 sys.stderr.write("scons: Build interrupted.\n")
1282 global exit_status
1283 global this_build_status
1284 exit_status = 2
1285 this_build_status = 2
1286
1287 if this_build_status:
1288 progress_display("scons: " + failure_message)
1289 else:
1290 progress_display("scons: " + closing_message)
1291 if not options.no_exec:
1292 if jobs.were_interrupted():
1293 progress_display("scons: writing .sconsign file.")
1294 SCons.SConsign.write()
1295
1296 progress_display("scons: " + opening_message)
1297 jobs.run(postfunc = jobs_postfunc)
1298
1299 memory_stats.append('after building targets:')
1300 count_stats.append(('post-', 'build'))
1301
1302 return nodes
1303
1304 -def _exec_main(parser, values):
1305 sconsflags = os.environ.get('SCONSFLAGS', '')
1306 all_args = sconsflags.split() + sys.argv[1:]
1307
1308 options, args = parser.parse_args(all_args, values)
1309
1310 if isinstance(options.debug, list) and "pdb" in options.debug:
1311 import pdb
1312 pdb.Pdb().runcall(_main, parser)
1313 elif options.profile_file:
1314
1315 from profile import Profile
1316
1317
1318
1319
1320
1321
1322 try:
1323 dispatch = Profile.dispatch
1324 except AttributeError:
1325 pass
1326 else:
1327 dispatch['c_exception'] = Profile.trace_dispatch_return
1328
1329 prof = Profile()
1330 try:
1331 prof.runcall(_main, parser)
1332 finally:
1333 prof.dump_stats(options.profile_file)
1334 else:
1335 _main(parser)
1336
1338 global OptionsParser
1339 global exit_status
1340 global first_command_start
1341
1342
1343
1344
1345
1346 if python_version_unsupported():
1347 msg = "scons: *** SCons version %s does not run under Python version %s.\n"
1348 sys.stderr.write(msg % (SCons.__version__, python_version_string()))
1349 sys.exit(1)
1350
1351 parts = ["SCons by Steven Knight et al.:\n"]
1352 try:
1353 import __main__
1354 parts.append(version_string("script", __main__))
1355 except (ImportError, AttributeError):
1356
1357
1358 pass
1359 parts.append(version_string("engine", SCons))
1360 parts.append(path_string("engine", SCons))
1361 parts.append("Copyright (c) 2001 - 2014 The SCons Foundation")
1362 version = ''.join(parts)
1363
1364 import SConsOptions
1365 parser = SConsOptions.Parser(version)
1366 values = SConsOptions.SConsValues(parser.get_default_values())
1367
1368 OptionsParser = parser
1369
1370 try:
1371 try:
1372 _exec_main(parser, values)
1373 finally:
1374 revert_io()
1375 except SystemExit, s:
1376 if s:
1377 exit_status = s
1378 except KeyboardInterrupt:
1379 print("scons: Build interrupted.")
1380 sys.exit(2)
1381 except SyntaxError, e:
1382 _scons_syntax_error(e)
1383 except SCons.Errors.InternalError:
1384 _scons_internal_error()
1385 except SCons.Errors.UserError, e:
1386 _scons_user_error(e)
1387 except SConsPrintHelpException:
1388 parser.print_help()
1389 exit_status = 0
1390 except SCons.Errors.BuildError, e:
1391 print e
1392 exit_status = e.exitstatus
1393 except:
1394
1395
1396
1397 SCons.Script._SConscript.SConscript_exception()
1398 sys.exit(2)
1399
1400 memory_stats.print_stats()
1401 count_stats.print_stats()
1402
1403 if print_objects:
1404 SCons.Debug.listLoggedInstances('*')
1405
1406
1407 if print_memoizer:
1408 SCons.Memoize.Dump("Memoizer (memory cache) hits and misses:")
1409
1410
1411
1412
1413
1414 SCons.Debug.dump_caller_counts()
1415 SCons.Taskmaster.dump_stats()
1416
1417 if print_time:
1418 total_time = time.time() - SCons.Script.start_time
1419 if num_jobs == 1:
1420 ct = cumulative_command_time
1421 else:
1422 if last_command_end is None or first_command_start is None:
1423 ct = 0.0
1424 else:
1425 ct = last_command_end - first_command_start
1426 scons_time = total_time - sconscript_time - ct
1427 print "Total build time: %f seconds"%total_time
1428 print "Total SConscript file execution time: %f seconds"%sconscript_time
1429 print "Total SCons execution time: %f seconds"%scons_time
1430 print "Total command execution time: %f seconds"%ct
1431
1432 sys.exit(exit_status)
1433
1434
1435
1436
1437
1438
1439