]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | # Status: mostly ported. Missing is --out-xml support, 'configure' integration |
2 | # and some FIXME. | |
3 | # Base revision: 64351 | |
4 | ||
5 | # Copyright 2003, 2005 Dave Abrahams | |
6 | # Copyright 2006 Rene Rivera | |
7 | # Copyright 2003, 2004, 2005, 2006, 2007 Vladimir Prus | |
8 | # Distributed under the Boost Software License, Version 1.0. | |
9 | # (See accompanying file LICENSE_1_0.txt or copy at | |
10 | # http://www.boost.org/LICENSE_1_0.txt) | |
11 | import os | |
12 | import sys | |
13 | import re | |
14 | ||
15 | import bjam | |
16 | ||
17 | # set this early on since some of the following modules | |
18 | # require looking at the sys.argv | |
19 | sys.argv = bjam.variable("ARGV") | |
20 | ||
21 | ||
22 | from b2.build.engine import Engine | |
23 | from b2.manager import Manager | |
24 | from b2.util.path import glob | |
25 | from b2.build import feature, property_set | |
26 | import b2.build.virtual_target | |
27 | from b2.build.targets import ProjectTarget | |
28 | import b2.build.build_request | |
29 | from b2.build.errors import ExceptionWithUserContext | |
30 | import b2.tools.common | |
31 | from b2.build.toolset import using | |
32 | ||
33 | import b2.build.virtual_target as virtual_target | |
34 | import b2.build.build_request as build_request | |
35 | ||
36 | import b2.util.regex | |
37 | ||
38 | from b2.manager import get_manager | |
39 | from b2.util import cached | |
40 | from b2.util import option | |
41 | ||
42 | ################################################################################ | |
43 | # | |
44 | # Module global data. | |
45 | # | |
46 | ################################################################################ | |
47 | ||
48 | # Flag indicating we should display additional debugging information related to | |
49 | # locating and loading Boost Build configuration files. | |
50 | debug_config = False | |
51 | ||
52 | # The cleaning is tricky. Say, if user says 'bjam --clean foo' where 'foo' is a | |
53 | # directory, then we want to clean targets which are in 'foo' as well as those | |
54 | # in any children Jamfiles under foo but not in any unrelated Jamfiles. To | |
55 | # achieve this we collect a list of projects under which cleaning is allowed. | |
56 | project_targets = [] | |
57 | ||
58 | # Virtual targets obtained when building main targets references on the command | |
59 | # line. When running 'bjam --clean main_target' we want to clean only files | |
60 | # belonging to that main target so we need to record which targets are produced | |
61 | # for it. | |
62 | results_of_main_targets = [] | |
63 | ||
64 | # Was an XML dump requested? | |
65 | out_xml = False | |
66 | ||
67 | # Default toolset & version to be used in case no other toolset has been used | |
68 | # explicitly by either the loaded configuration files, the loaded project build | |
69 | # scripts or an explicit toolset request on the command line. If not specified, | |
70 | # an arbitrary default will be used based on the current host OS. This value, | |
71 | # while not strictly necessary, has been added to allow testing Boost-Build's | |
72 | # default toolset usage functionality. | |
73 | default_toolset = None | |
74 | default_toolset_version = None | |
75 | ||
76 | ################################################################################ | |
77 | # | |
78 | # Public rules. | |
79 | # | |
80 | ################################################################################ | |
81 | ||
82 | # Returns the property set with the free features from the currently processed | |
83 | # build request. | |
84 | # | |
85 | def command_line_free_features(): | |
86 | return command_line_free_features | |
87 | ||
88 | # Sets the default toolset & version to be used in case no other toolset has | |
89 | # been used explicitly by either the loaded configuration files, the loaded | |
90 | # project build scripts or an explicit toolset request on the command line. For | |
91 | # more detailed information see the comment related to used global variables. | |
92 | # | |
93 | def set_default_toolset(toolset, version=None): | |
94 | default_toolset = toolset | |
95 | default_toolset_version = version | |
96 | ||
97 | ||
98 | pre_build_hook = [] | |
99 | ||
100 | def add_pre_build_hook(callable): | |
101 | pre_build_hook.append(callable) | |
102 | ||
103 | post_build_hook = None | |
104 | ||
105 | def set_post_build_hook(callable): | |
106 | post_build_hook = callable | |
107 | ||
108 | ################################################################################ | |
109 | # | |
110 | # Local rules. | |
111 | # | |
112 | ################################################################################ | |
113 | ||
114 | # Returns actual Jam targets to be used for executing a clean request. | |
115 | # | |
116 | def actual_clean_targets(targets): | |
117 | ||
118 | # Construct a list of projects explicitly detected as targets on this build | |
119 | # system run. These are the projects under which cleaning is allowed. | |
120 | for t in targets: | |
121 | if isinstance(t, b2.build.targets.ProjectTarget): | |
122 | project_targets.append(t.project_module()) | |
123 | ||
124 | # Construct a list of targets explicitly detected on this build system run | |
125 | # as a result of building main targets. | |
126 | targets_to_clean = set() | |
127 | for t in results_of_main_targets: | |
128 | # Do not include roots or sources. | |
129 | targets_to_clean.update(virtual_target.traverse(t)) | |
130 | ||
131 | to_clean = [] | |
132 | for t in get_manager().virtual_targets().all_targets(): | |
133 | ||
134 | # Remove only derived targets. | |
135 | if t.action(): | |
136 | p = t.project() | |
137 | if t in targets_to_clean or should_clean_project(p.project_module()): | |
138 | to_clean.append(t) | |
139 | ||
140 | return [t.actualize() for t in to_clean] | |
141 | ||
142 | _target_id_split = re.compile("(.*)//(.*)") | |
143 | ||
144 | # Given a target id, try to find and return the corresponding target. This is | |
145 | # only invoked when there is no Jamfile in ".". This code somewhat duplicates | |
146 | # code in project-target.find but we can not reuse that code without a | |
147 | # project-targets instance. | |
148 | # | |
149 | def find_target(target_id): | |
150 | ||
151 | projects = get_manager().projects() | |
152 | m = _target_id_split.match(target_id) | |
153 | if m: | |
154 | pm = projects.find(m.group(1), ".") | |
155 | else: | |
156 | pm = projects.find(target_id, ".") | |
157 | ||
158 | if pm: | |
159 | result = projects.target(pm) | |
160 | ||
161 | if m: | |
162 | result = result.find(m.group(2)) | |
163 | ||
164 | return result | |
165 | ||
166 | def initialize_config_module(module_name, location=None): | |
167 | ||
168 | get_manager().projects().initialize(module_name, location) | |
169 | ||
170 | # Helper rule used to load configuration files. Loads the first configuration | |
171 | # file with the given 'filename' at 'path' into module with name 'module-name'. | |
172 | # Not finding the requested file may or may not be treated as an error depending | |
173 | # on the must-find parameter. Returns a normalized path to the loaded | |
174 | # configuration file or nothing if no file was loaded. | |
175 | # | |
176 | def load_config(module_name, filename, paths, must_find=False): | |
177 | ||
178 | if debug_config: | |
179 | print "notice: Searching '%s' for '%s' configuration file '%s." \ | |
180 | % (paths, module_name, filename) | |
181 | ||
182 | where = None | |
183 | for path in paths: | |
184 | t = os.path.join(path, filename) | |
185 | if os.path.exists(t): | |
186 | where = t | |
187 | break | |
188 | ||
189 | if where: | |
190 | where = os.path.realpath(where) | |
191 | ||
192 | if debug_config: | |
193 | print "notice: Loading '%s' configuration file '%s' from '%s'." \ | |
194 | % (module_name, filename, where) | |
195 | ||
196 | # Set source location so that path-constant in config files | |
197 | # with relative paths work. This is of most importance | |
198 | # for project-config.jam, but may be used in other | |
199 | # config files as well. | |
200 | attributes = get_manager().projects().attributes(module_name) ; | |
201 | attributes.set('source-location', os.path.dirname(where), True) | |
202 | get_manager().projects().load_standalone(module_name, where) | |
203 | ||
204 | else: | |
205 | msg = "Configuration file '%s' not found in '%s'." % (filename, path) | |
206 | if must_find: | |
207 | get_manager().errors()(msg) | |
208 | ||
209 | elif debug_config: | |
210 | print msg | |
211 | ||
212 | return where | |
213 | ||
214 | # Loads all the configuration files used by Boost Build in the following order: | |
215 | # | |
216 | # -- test-config -- | |
217 | # Loaded only if specified on the command-line using the --test-config | |
218 | # command-line parameter. It is ok for this file not to exist even if | |
219 | # specified. If this configuration file is loaded, regular site and user | |
220 | # configuration files will not be. If a relative path is specified, file is | |
221 | # searched for in the current folder. | |
222 | # | |
223 | # -- site-config -- | |
224 | # Always named site-config.jam. Will only be found if located on the system | |
225 | # root path (Windows), /etc (non-Windows), user's home folder or the Boost | |
226 | # Build path, in that order. Not loaded in case the test-config configuration | |
227 | # file is loaded or the --ignore-site-config command-line option is specified. | |
228 | # | |
229 | # -- user-config -- | |
230 | # Named user-config.jam by default or may be named explicitly using the | |
231 | # --user-config command-line option or the BOOST_BUILD_USER_CONFIG environment | |
232 | # variable. If named explicitly the file is looked for from the current working | |
233 | # directory and if the default one is used then it is searched for in the | |
234 | # user's home directory and the Boost Build path, in that order. Not loaded in | |
235 | # case either the test-config configuration file is loaded or an empty file | |
236 | # name is explicitly specified. If the file name has been given explicitly then | |
237 | # the file must exist. | |
238 | # | |
239 | # Test configurations have been added primarily for use by Boost Build's | |
240 | # internal unit testing system but may be used freely in other places as well. | |
241 | # | |
242 | def load_configuration_files(): | |
243 | ||
244 | # Flag indicating that site configuration should not be loaded. | |
245 | ignore_site_config = "--ignore-site-config" in sys.argv | |
246 | ||
247 | initialize_config_module("test-config") | |
248 | test_config = None | |
249 | for a in sys.argv: | |
250 | m = re.match("--test-config=(.*)$", a) | |
251 | if m: | |
252 | test_config = b2.util.unquote(m.group(1)) | |
253 | break | |
254 | ||
255 | if test_config: | |
256 | where = load_config("test-config", os.path.basename(test_config), [os.path.dirname(test_config)]) | |
257 | if where: | |
258 | if debug_config: | |
259 | print "notice: Regular site and user configuration files will" | |
260 | print "notice: be ignored due to the test configuration being loaded." | |
261 | ||
262 | user_path = [os.path.expanduser("~")] + bjam.variable("BOOST_BUILD_PATH") | |
263 | site_path = ["/etc"] + user_path | |
264 | if os.name in ["nt"]: | |
265 | site_path = [os.getenv("SystemRoot")] + user_path | |
266 | ||
267 | if debug_config and not test_config and ignore_site_config: | |
268 | print "notice: Site configuration files will be ignored due to the" | |
269 | print "notice: --ignore-site-config command-line option." | |
270 | ||
271 | initialize_config_module("site-config") | |
272 | if not test_config and not ignore_site_config: | |
273 | load_config('site-config', 'site-config.jam', site_path) | |
274 | ||
275 | initialize_config_module('user-config') | |
276 | if not test_config: | |
277 | ||
278 | # Here, user_config has value of None if nothing is explicitly | |
279 | # specified, and value of '' if user explicitly does not want | |
280 | # to load any user config. | |
281 | user_config = None | |
282 | for a in sys.argv: | |
283 | m = re.match("--user-config=(.*)$", a) | |
284 | if m: | |
285 | user_config = m.group(1) | |
286 | break | |
287 | ||
288 | if user_config is None: | |
289 | user_config = os.getenv("BOOST_BUILD_USER_CONFIG") | |
290 | ||
291 | # Special handling for the case when the OS does not strip the quotes | |
292 | # around the file name, as is the case when using Cygwin bash. | |
293 | user_config = b2.util.unquote(user_config) | |
294 | explicitly_requested = user_config | |
295 | ||
296 | if user_config is None: | |
297 | user_config = "user-config.jam" | |
298 | ||
299 | if user_config: | |
300 | if explicitly_requested: | |
301 | ||
302 | user_config = os.path.abspath(user_config) | |
303 | ||
304 | if debug_config: | |
305 | print "notice: Loading explicitly specified user configuration file:" | |
306 | print " " + user_config | |
307 | ||
308 | load_config('user-config', os.path.basename(user_config), [os.path.dirname(user_config)], True) | |
309 | else: | |
310 | load_config('user-config', os.path.basename(user_config), user_path) | |
311 | else: | |
312 | if debug_config: | |
313 | print "notice: User configuration file loading explicitly disabled." | |
314 | ||
315 | # We look for project-config.jam from "." upward. I am not sure this is | |
316 | # 100% right decision, we might as well check for it only alongside the | |
317 | # Jamroot file. However: | |
318 | # - We need to load project-config.jam before Jamroot | |
319 | # - We probably need to load project-config.jam even if there is no Jamroot | |
320 | # - e.g. to implement automake-style out-of-tree builds. | |
321 | if os.path.exists("project-config.jam"): | |
322 | file = ["project-config.jam"] | |
323 | else: | |
324 | file = b2.util.path.glob_in_parents(".", ["project-config.jam"]) | |
325 | ||
326 | if file: | |
327 | initialize_config_module('project-config', os.path.dirname(file[0])) | |
328 | load_config('project-config', "project-config.jam", [os.path.dirname(file[0])], True) | |
329 | ||
330 | get_manager().projects().end_load() | |
331 | ||
332 | ||
333 | # Autoconfigure toolsets based on any instances of --toolset=xx,yy,...zz or | |
334 | # toolset=xx,yy,...zz in the command line. May return additional properties to | |
335 | # be processed as if they had been specified by the user. | |
336 | # | |
337 | def process_explicit_toolset_requests(): | |
338 | ||
339 | extra_properties = [] | |
340 | ||
341 | option_toolsets = [e for option in b2.util.regex.transform(sys.argv, "^--toolset=(.*)$") | |
342 | for e in option.split(',')] | |
343 | feature_toolsets = [e for option in b2.util.regex.transform(sys.argv, "^toolset=(.*)$") | |
344 | for e in option.split(',')] | |
345 | ||
346 | for t in option_toolsets + feature_toolsets: | |
347 | ||
348 | # Parse toolset-version/properties. | |
349 | (toolset_version, toolset, version) = re.match("(([^-/]+)-?([^/]+)?)/?.*", t).groups() | |
350 | ||
351 | if debug_config: | |
352 | print "notice: [cmdline-cfg] Detected command-line request for '%s': toolset= %s version=%s" \ | |
353 | % (toolset_version, toolset, version) | |
354 | ||
355 | # If the toolset is not known, configure it now. | |
356 | known = False | |
357 | if toolset in feature.values("toolset"): | |
358 | known = True | |
359 | ||
360 | if known and version and not feature.is_subvalue("toolset", toolset, "version", version): | |
361 | known = False | |
362 | # TODO: we should do 'using $(toolset)' in case no version has been | |
363 | # specified and there are no versions defined for the given toolset to | |
364 | # allow the toolset to configure its default version. For this we need | |
365 | # to know how to detect whether a given toolset has any versions | |
366 | # defined. An alternative would be to do this whenever version is not | |
367 | # specified but that would require that toolsets correctly handle the | |
368 | # case when their default version is configured multiple times which | |
369 | # should be checked for all existing toolsets first. | |
370 | ||
371 | if not known: | |
372 | ||
373 | if debug_config: | |
374 | print "notice: [cmdline-cfg] toolset '%s' not previously configured; attempting to auto-configure now" % toolset_version | |
375 | if version is not None: | |
376 | using(toolset, version) | |
377 | else: | |
378 | using(toolset) | |
379 | ||
380 | else: | |
381 | ||
382 | if debug_config: | |
383 | ||
384 | print "notice: [cmdline-cfg] toolset '%s' already configured" % toolset_version | |
385 | ||
386 | # Make sure we get an appropriate property into the build request in | |
387 | # case toolset has been specified using the "--toolset=..." command-line | |
388 | # option form. | |
389 | if not t in sys.argv and not t in feature_toolsets: | |
390 | ||
391 | if debug_config: | |
392 | print "notice: [cmdline-cfg] adding toolset=%s) to the build request." % t ; | |
393 | extra_properties += "toolset=%s" % t | |
394 | ||
395 | return extra_properties | |
396 | ||
397 | ||
398 | ||
399 | # Returns 'true' if the given 'project' is equal to or is a (possibly indirect) | |
400 | # child to any of the projects requested to be cleaned in this build system run. | |
401 | # Returns 'false' otherwise. Expects the .project-targets list to have already | |
402 | # been constructed. | |
403 | # | |
404 | @cached | |
405 | def should_clean_project(project): | |
406 | ||
407 | if project in project_targets: | |
408 | return True | |
409 | else: | |
410 | ||
411 | parent = get_manager().projects().attribute(project, "parent-module") | |
412 | if parent and parent != "user-config": | |
413 | return should_clean_project(parent) | |
414 | else: | |
415 | return False | |
416 | ||
417 | ################################################################################ | |
418 | # | |
419 | # main() | |
420 | # ------ | |
421 | # | |
422 | ################################################################################ | |
423 | ||
424 | def main(): | |
425 | ||
426 | # FIXME: document this option. | |
427 | if "--profiling" in sys.argv: | |
428 | import cProfile | |
429 | r = cProfile.runctx('main_real()', globals(), locals(), "stones.prof") | |
430 | ||
431 | import pstats | |
432 | stats = pstats.Stats("stones.prof") | |
433 | stats.strip_dirs() | |
434 | stats.sort_stats('time', 'calls') | |
435 | stats.print_callers(20) | |
436 | return r | |
437 | else: | |
438 | try: | |
439 | return main_real() | |
440 | except ExceptionWithUserContext, e: | |
441 | e.report() | |
442 | ||
443 | def main_real(): | |
444 | ||
445 | global debug_config, out_xml | |
446 | ||
447 | debug_config = "--debug-configuration" in sys.argv | |
448 | out_xml = any(re.match("^--out-xml=(.*)$", a) for a in sys.argv) | |
449 | ||
450 | engine = Engine() | |
451 | ||
452 | global_build_dir = option.get("build-dir") | |
453 | manager = Manager(engine, global_build_dir) | |
454 | ||
455 | import b2.build.configure as configure | |
456 | ||
457 | if "--version" in sys.argv: | |
458 | from b2.build import version | |
459 | version.report() | |
460 | return | |
461 | ||
462 | # This module defines types and generator and what not, | |
463 | # and depends on manager's existence | |
464 | import b2.tools.builtin | |
465 | ||
466 | b2.tools.common.init(manager) | |
467 | ||
468 | load_configuration_files() | |
469 | ||
470 | # Load explicitly specified toolset modules. | |
471 | extra_properties = process_explicit_toolset_requests() | |
472 | ||
473 | # Load the actual project build script modules. We always load the project | |
474 | # in the current folder so 'use-project' directives have any chance of | |
475 | # being seen. Otherwise, we would not be able to refer to subprojects using | |
476 | # target ids. | |
477 | current_project = None | |
478 | projects = get_manager().projects() | |
479 | if projects.find(".", "."): | |
480 | current_project = projects.target(projects.load(".")) | |
481 | ||
482 | # Load the default toolset module if no other has already been specified. | |
483 | if not feature.values("toolset"): | |
484 | ||
485 | dt = default_toolset | |
486 | dtv = None | |
487 | if default_toolset: | |
488 | dtv = default_toolset_version | |
489 | else: | |
490 | dt = "gcc" | |
491 | if os.name == 'nt': | |
492 | dt = "msvc" | |
493 | # FIXME: | |
494 | #else if [ os.name ] = MACOSX | |
495 | #{ | |
496 | # default-toolset = darwin ; | |
497 | #} | |
498 | ||
499 | print "warning: No toolsets are configured." | |
500 | print "warning: Configuring default toolset '%s'." % dt | |
501 | print "warning: If the default is wrong, your build may not work correctly." | |
502 | print "warning: Use the \"toolset=xxxxx\" option to override our guess." | |
503 | print "warning: For more configuration options, please consult" | |
504 | print "warning: http://boost.org/boost-build2/doc/html/bbv2/advanced/configuration.html" | |
505 | ||
506 | using(dt, dtv) | |
507 | ||
508 | # Parse command line for targets and properties. Note that this requires | |
509 | # that all project files already be loaded. | |
510 | (target_ids, properties) = build_request.from_command_line(sys.argv[1:] + extra_properties) | |
511 | ||
512 | # Check that we actually found something to build. | |
513 | if not current_project and not target_ids: | |
514 | get_manager().errors()("no Jamfile in current directory found, and no target references specified.") | |
515 | # FIXME: | |
516 | # EXIT | |
517 | ||
518 | # Flags indicating that this build system run has been started in order to | |
519 | # clean existing instead of create new targets. Note that these are not the | |
520 | # final flag values as they may get changed later on due to some special | |
521 | # targets being specified on the command line. | |
522 | clean = "--clean" in sys.argv | |
523 | cleanall = "--clean-all" in sys.argv | |
524 | ||
525 | # List of explicitly requested files to build. Any target references read | |
526 | # from the command line parameter not recognized as one of the targets | |
527 | # defined in the loaded Jamfiles will be interpreted as an explicitly | |
528 | # requested file to build. If any such files are explicitly requested then | |
529 | # only those files and the targets they depend on will be built and they | |
530 | # will be searched for among targets that would have been built had there | |
531 | # been no explicitly requested files. | |
532 | explicitly_requested_files = [] | |
533 | ||
534 | # List of Boost Build meta-targets, virtual-targets and actual Jam targets | |
535 | # constructed in this build system run. | |
536 | targets = [] | |
537 | virtual_targets = [] | |
538 | actual_targets = [] | |
539 | ||
540 | explicitly_requested_files = [] | |
541 | ||
542 | # Process each target specified on the command-line and convert it into | |
543 | # internal Boost Build target objects. Detect special clean target. If no | |
92f5a8d4 | 544 | # main Boost Build targets were explicitly requested use the current project |
7c673cae FG |
545 | # as the target. |
546 | for id in target_ids: | |
547 | if id == "clean": | |
548 | clean = 1 | |
549 | else: | |
550 | t = None | |
551 | if current_project: | |
552 | t = current_project.find(id, no_error=1) | |
553 | else: | |
554 | t = find_target(id) | |
555 | ||
556 | if not t: | |
557 | print "notice: could not find main target '%s'" % id | |
558 | print "notice: assuming it's a name of file to create " ; | |
559 | explicitly_requested_files.append(id) | |
560 | else: | |
561 | targets.append(t) | |
562 | ||
563 | if not targets: | |
564 | targets = [projects.target(projects.module_name("."))] | |
565 | ||
566 | # FIXME: put this BACK. | |
567 | ||
568 | ## if [ option.get dump-generators : : true ] | |
569 | ## { | |
570 | ## generators.dump ; | |
571 | ## } | |
572 | ||
573 | ||
574 | # We wish to put config.log in the build directory corresponding | |
575 | # to Jamroot, so that the location does not differ depending on | |
576 | # directory where we do build. The amount of indirection necessary | |
577 | # here is scary. | |
578 | first_project = targets[0].project() | |
579 | first_project_root_location = first_project.get('project-root') | |
580 | first_project_root_module = manager.projects().load(first_project_root_location) | |
581 | first_project_root = manager.projects().target(first_project_root_module) | |
582 | first_build_build_dir = first_project_root.build_dir() | |
583 | configure.set_log_file(os.path.join(first_build_build_dir, "config.log")) | |
584 | ||
585 | virtual_targets = [] | |
586 | ||
587 | global results_of_main_targets | |
588 | ||
589 | # Expand properties specified on the command line into multiple property | |
590 | # sets consisting of all legal property combinations. Each expanded property | |
591 | # set will be used for a single build run. E.g. if multiple toolsets are | |
592 | # specified then requested targets will be built with each of them. | |
593 | # The expansion is being performed as late as possible so that the feature | |
594 | # validation is performed after all necessary modules (including project targets | |
595 | # on the command line) have been loaded. | |
596 | if properties: | |
597 | expanded = [] | |
598 | for p in properties: | |
599 | expanded.extend(build_request.convert_command_line_element(p)) | |
600 | ||
601 | expanded = build_request.expand_no_defaults(expanded) | |
602 | else: | |
603 | expanded = [property_set.empty()] | |
604 | ||
605 | # Now that we have a set of targets to build and a set of property sets to | |
606 | # build the targets with, we can start the main build process by using each | |
607 | # property set to generate virtual targets from all of our listed targets | |
608 | # and any of their dependants. | |
609 | for p in expanded: | |
610 | manager.set_command_line_free_features(property_set.create(p.free())) | |
611 | ||
612 | for t in targets: | |
613 | try: | |
614 | g = t.generate(p) | |
615 | if not isinstance(t, ProjectTarget): | |
616 | results_of_main_targets.extend(g.targets()) | |
617 | virtual_targets.extend(g.targets()) | |
618 | except ExceptionWithUserContext, e: | |
619 | e.report() | |
620 | except Exception: | |
621 | raise | |
622 | ||
623 | # Convert collected virtual targets into actual raw Jam targets. | |
624 | for t in virtual_targets: | |
625 | actual_targets.append(t.actualize()) | |
626 | ||
627 | j = option.get("jobs") | |
628 | if j: | |
629 | bjam.call("set-variable", 'PARALLELISM', j) | |
630 | ||
631 | k = option.get("keep-going", "true", "true") | |
632 | if k in ["on", "yes", "true"]: | |
633 | bjam.call("set-variable", "KEEP_GOING", "1") | |
634 | elif k in ["off", "no", "false"]: | |
635 | bjam.call("set-variable", "KEEP_GOING", "0") | |
636 | else: | |
637 | print "error: Invalid value for the --keep-going option" | |
638 | sys.exit() | |
639 | ||
640 | # The 'all' pseudo target is not strictly needed expect in the case when we | |
641 | # use it below but people often assume they always have this target | |
642 | # available and do not declare it themselves before use which may cause | |
643 | # build failures with an error message about not being able to build the | |
644 | # 'all' target. | |
645 | bjam.call("NOTFILE", "all") | |
646 | ||
647 | # And now that all the actual raw Jam targets and all the dependencies | |
648 | # between them have been prepared all that is left is to tell Jam to update | |
649 | # those targets. | |
650 | if explicitly_requested_files: | |
651 | # Note that this case can not be joined with the regular one when only | |
652 | # exact Boost Build targets are requested as here we do not build those | |
653 | # requested targets but only use them to construct the dependency tree | |
654 | # needed to build the explicitly requested files. | |
655 | # FIXME: add $(.out-xml) | |
656 | bjam.call("UPDATE", ["<e>%s" % x for x in explicitly_requested_files]) | |
657 | elif cleanall: | |
658 | bjam.call("UPDATE", "clean-all") | |
659 | elif clean: | |
660 | manager.engine().set_update_action("common.Clean", "clean", | |
661 | actual_clean_targets(targets)) | |
662 | bjam.call("UPDATE", "clean") | |
663 | else: | |
664 | # FIXME: | |
665 | #configure.print-configure-checks-summary ; | |
666 | ||
667 | if pre_build_hook: | |
668 | for h in pre_build_hook: | |
669 | h() | |
670 | ||
671 | bjam.call("DEPENDS", "all", actual_targets) | |
672 | ok = bjam.call("UPDATE_NOW", "all") # FIXME: add out-xml | |
673 | if post_build_hook: | |
674 | post_build_hook(ok) | |
675 | # Prevent automatic update of the 'all' target, now that | |
676 | # we have explicitly updated what we wanted. | |
677 | bjam.call("UPDATE") | |
678 | ||
679 | if manager.errors().count() == 0: | |
680 | return ["ok"] | |
681 | else: | |
682 | return [] |