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