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