1 # Copyright (c) 2010 Vladimir Prus.
2 # Copyright 2017-2021 Rene Ferdinand Rivera Morell
4 # Use, modification and distribution is subject to the Boost Software
5 # License Version 1.0. (See accompanying file LICENSE.txt or
6 # https://www.bfgroup.xyz/b2/LICENSE.txt)
8 # This module defines function to help with two main tasks:
10 # - Discovering build-time configuration for the purposes of adjusting the build
12 # - Reporting what is built, and how it is configured.
14 import "class" : new ;
27 import virtual-target ;
37 rule set-width ( width )
43 # Declare that the components specified by the parameter exist.
45 rule register-components ( components * )
47 .components += $(components) ;
51 # Declare that the components specified by the parameters will be built.
53 rule components-building ( components * )
55 .built-components += $(components) ;
59 # Report something about component configuration that the user should better
62 rule log-component-configuration ( component : message )
64 # FIXME: Implement per-property-set logs.
65 .component-logs.$(component) += $(message) ;
74 rule log-check-result ( result variant ? )
76 if ! $(.announced-checks)
78 ECHO "Performing configuration checks\n" ;
79 .announced-checks = 1 ;
84 if $(.variant_index.$(variant))
86 result = "$(result) [$(.variant_index.$(variant))]" ;
90 .variant_index = [ CALC $(.variant_index) + 1 ] ;
91 .variant_index.$(variant) = $(.variant_index) ;
92 result = "$(result) [$(.variant_index.$(variant))]" ;
93 .check_notes += "[$(.variant_index.$(variant))] $(variant)" ;
98 # result = "$(result) [?]" ;
102 # FIXME: Unfinished code. Nothing seems to set .check-results at the moment.
103 #.check-results += $(result) ;
107 rule log-library-search-result ( library : result variant ? )
109 local x = [ PAD " - $(library)" : $(.width) ] ;
110 log-check-result "$(x) : $(result)" $(variant) ;
114 rule print-component-configuration ( )
116 # FIXME: See what was intended with this initial assignment.
117 # local c = [ sequence.unique $(.components) ] ;
119 ECHO "\nComponent configuration:\n" ;
121 for c in $(.components)
124 if $(c) in $(.built-components)
132 ECHO [ PAD " - $(c)" : $(.width) ] ": $(s)" ;
133 for local m in $(.component-logs.$(c))
142 rule print-configure-checks-summary ( )
147 for local l in $(.check_notes) { ECHO $(l) ; }
150 # FIXME: The problem with this approach is that the user sees the checks
151 # summary when all checks are done, and has no progress reporting while the
152 # checks are being executed.
155 ECHO "Configuration checks summary\n" ;
156 for local r in $(.check-results)
164 if --reconfigure in [ modules.peek : ARGV ]
166 .reconfigure = true ;
169 # Handle the --reconfigure option
170 rule maybe-force-rebuild ( targets * )
175 for local t in $(targets)
177 all-targets += [ virtual-target.traverse $(t) ] ;
179 for local t in [ sequence.unique $(all-targets) ]
186 # Attempts to build a set of virtual targets
187 rule try-build ( targets * : ps : what : retry ? )
189 local cache-props = [ $(ps).raw ] ;
190 local cache-name = $(what) $(cache-props) ;
191 cache-name = $(cache-name:J=-) ;
192 local value = [ config-cache.get $(cache-name) ] ;
193 local cache-min = [ property.as-path [ SORT [ feature.minimize $(cache-props) ] ] ] ;
198 maybe-force-rebuild $(targets) ;
200 for local t in $(targets)
202 jam-targets += [ $(t).actualize ] ;
208 x = [ PAD " - $(what)" : $(.width) ] ;
211 .$(what)-supported.$(ps) = yes ;
213 x = "$(x) : yes (cached)" ;
217 x = "$(x) : no (cached)" ;
220 else if ! UPDATE_NOW in [ RULENAMES ]
222 # Cannot determine. Assume existence.
226 x = [ PAD " - $(what)" : $(.width) ] ;
227 if [ UPDATE_NOW $(jam-targets) :
228 $(.log-fd) : ignore-minus-n : ignore-minus-q ]
230 .$(what)-supported.$(ps) = yes ;
241 log-check-result "$(x)" "$(cache-min:J= )" ;
247 config-cache.set $(cache-name) : true ;
251 config-cache.set $(cache-name) : false ;
257 # Attempts to build several sets of virtual targets. Returns the
258 # the index of the first set that builds.
259 rule try-find-build ( ps : what : * )
261 local args = 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ;
262 # The outer layer only needs to check $(what), but we
263 # also need to check the individual elements, in case
264 # the set of targets has changed since the last build.
265 local cache-props = [ $(ps).raw ] ;
266 local cache-name = $(what) $($(args)[1]) $(cache-props) ;
267 cache-name = $(cache-name:J=-) ;
268 local value = [ config-cache.get $(cache-name) ] ;
269 local cache-min = [ property.as-path [ SORT [ feature.minimize $(cache-props) ] ] ] ;
274 maybe-force-rebuild $($(args)[2-]) ;
276 # Make sure that the targets are always actualized,
277 # even if the result is cached. This is needed to
278 # allow clean-all to find them and also to avoid
279 # unintentional behavior changes.
280 for local t in $($(args)[2-])
287 local none = none ; # What to show when the argument
288 local name = $(value) ;
291 name = [ CALC $(name) + 2 ] ;
293 local x = [ PAD " - $(what)" : $(.width) ] ;
294 local y = [ PAD $($(name)[1]) : 3 ] ;
296 log-check-result "$(x) : $(y) (cached)" "$(cache-min:J= )" ;
300 local x = [ PAD " - $(what)" : $(.width) ] ;
301 for local i in $(args)
308 for local t in $($(i)[2-])
310 jam-targets += [ $(t).actualize ] ;
312 if [ UPDATE_NOW $(jam-targets) :
313 $(.log-fd) : ignore-minus-n : ignore-minus-q ]
315 result = [ CALC $(i) - 2 ] ;
316 log-check-result "$(x) : $($(i)[1])" "$(cache-min:J= )" ;
322 log-check-result "$(x) : none" "$(cache-min:J= )" ;
330 config-cache.set $(cache-name) : $(result) ;
334 config-cache.set $(cache-name) : $(result) ;
343 # Attempt to build a metatarget named by 'metatarget-reference'
344 # in context of 'project' with properties 'ps'.
345 # Returns non-empty value if build is OK.
346 rule builds-raw ( metatarget-reference : project : ps : what : retry ? )
350 if ! $(retry) && ! $(.$(what)-tested.$(ps))
352 .$(what)-tested.$(ps) = true ;
354 local targets = [ targets.generate-from-reference
355 $(metatarget-reference) : $(project) : $(ps) ] ;
357 result = [ try-build $(targets[2-]) : $(ps) : $(what) : $(retry) ] ;
358 .$(what)-supported.$(ps) = $(result) ;
365 return $(.$(what)-supported.$(ps)) ;
369 # Attempt to build a metatarget named by 'metatarget-reference'
370 # in context of 'project' with properties 'ps'.
371 # Returns the 1-based index of the first target
373 rule find-builds-raw ( project : ps : what : * )
376 local args = 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ;
378 if ! $(.$(what)-tested.$(ps))
380 .$(what)-tested.$(ps) = true ;
381 local targets.$(i) what.$(i) ;
382 for local i in $(args)
388 targets.$(i) = [ targets.generate-from-reference
389 $($(i)[1]) : $(project) : $(ps) ] ;
390 # ignore usage requirements
391 targets.$(i) = $(targets.$(i)[2-]) ;
394 what.$(i) = $($(i)[2]) ;
398 local t = [ targets.resolve-reference
399 $($(i)[1]) : $(project) ] ;
400 what.$(i) = [ $(t[1]).name ] ;
404 result = [ try-find-build $(ps) : $(what)
405 : $(what.4) $(targets.4)
406 : $(what.5) $(targets.5)
407 : $(what.6) $(targets.6)
408 : $(what.7) $(targets.7)
409 : $(what.8) $(targets.8)
410 : $(what.9) $(targets.9)
411 : $(what.10) $(targets.10)
412 : $(what.11) $(targets.11)
413 : $(what.12) $(targets.12)
414 : $(what.13) $(targets.13)
415 : $(what.14) $(targets.14)
416 : $(what.15) $(targets.15)
417 : $(what.16) $(targets.16)
418 : $(what.17) $(targets.17)
419 : $(what.18) $(targets.18)
420 : $(what.19) $(targets.19) ] ;
421 .$(what)-result.$(ps) = $(result) ;
427 return $(.$(what)-result.$(ps)) ;
431 rule get-relevant-features ( properties * )
433 local ps-full = [ property-set.create $(properties) ] ;
434 local ps-base = [ property-set.create [ $(ps-full).base ] ] ;
435 local ps-min = [ feature.expand-subfeatures [ feature.minimize
436 [ $(ps-base).raw ] ] ] ;
437 local ps-relevant = [ property-set.create $(ps-min) ] ;
439 return [ $(ps-relevant).raw ] ;
442 rule builds ( metatarget-reference : properties * : what ? : retry ? )
444 local relevant = [ get-relevant-features $(properties) ] ;
445 local ps = [ property-set.create $(relevant) ] ;
446 local t = [ targets.current ] ;
447 local p = [ $(t).project ] ;
451 local resolved = [ targets.resolve-reference $(metatarget-reference) : $(p) ] ;
452 local name = [ $(resolved[1]).name ] ;
453 what = "$(name) builds" ;
456 return [ builds-raw $(metatarget-reference) : $(p) : $(ps) : $(what) :
460 rule find-builds ( what : properties * : * )
462 local relevant = [ get-relevant-features $(properties) ] ;
463 local ps = [ property-set.create $(relevant) ] ;
464 local t = [ targets.current ] ;
465 local p = [ $(t).project ] ;
467 return [ find-builds-raw $(p) : $(ps) : $(what) :
468 $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) :
469 $(10) : $(11) : $(12) : $(13) : $(14) : $(15) :
470 $(16) : $(17) : $(18) ] ;
474 # Called by B2 startup code to specify the file to receive the
475 # configuration check results. Should never be called by user code.
477 rule set-log-file ( log-file )
479 path.makedirs [ path.parent $(log-file) ] ;
480 .log-fd = [ FILE_OPEN [ path.native $(log-file) ] : "w" ] ;
483 ECHO "warning:" failed to open log file $(log-file) for writing ;
490 class check-target-builds-worker
493 import property-set ;
498 rule __init__ ( target message ? : true-properties * : false-properties * )
500 local project = [ project.current ] ;
501 self.target = $(target) ;
502 self.message = $(message) ;
503 self.true-properties =
504 [ configure.translate-properties $(true-properties) : $(project) ] ;
505 self.false-properties =
506 [ configure.translate-properties $(false-properties) : $(project) ] ;
509 rule check ( properties * )
512 if [ configure.builds $(self.target) : $(properties) : $(self.message) ]
514 choosen = $(self.true-properties) ;
518 choosen = $(self.false-properties) ;
520 return [ property.evaluate-conditionals-in-context $(choosen) :
525 class configure-choose-worker
530 rule __init__ ( message : * )
532 local project = [ project.current ] ;
533 self.message = $(message) ;
534 for i in 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
536 local name = [ CALC $(i) - 1 ] ;
537 self.targets.$(name) = $($(i)[1]) ;
538 if ! $($(i)[2]:G) # Check whether the second argument is a property
540 self.what.$(name) = $($(i)[2]) ;
541 self.props.$(name) = $($(i)[3-]) ;
545 self.props.$(name) = $($(i)[2-]) ;
547 self.props.$(name) = [ configure.translate-properties
548 $(self.props.$(name)) : $(project) ] ;
551 rule all-properties ( )
553 local i = 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ;
554 return $(self.props.$(i)) ;
556 rule check ( properties * )
558 local i = [ configure.find-builds $(self.message) : $(properties)
559 : $(self.targets.1) $(self.what.1)
560 : $(self.targets.2) $(self.what.2)
561 : $(self.targets.3) $(self.what.3)
562 : $(self.targets.4) $(self.what.4)
563 : $(self.targets.5) $(self.what.5)
564 : $(self.targets.6) $(self.what.6)
565 : $(self.targets.7) $(self.what.7)
566 : $(self.targets.8) $(self.what.8)
567 : $(self.targets.9) $(self.what.9)
568 : $(self.targets.10) $(self.what.10)
569 : $(self.targets.11) $(self.what.11)
570 : $(self.targets.12) $(self.what.12)
571 : $(self.targets.13) $(self.what.13)
572 : $(self.targets.14) $(self.what.14)
573 : $(self.targets.15) $(self.what.15)
574 : $(self.targets.16) $(self.what.16)
575 : $(self.targets.17) $(self.what.17) ] ;
576 if $(self.props.$(i))
578 return [ property.evaluate-conditionals-in-context $(self.props.$(i)) : $(properties) ] ;
583 rule translate-properties ( properties * : project ? )
585 if $(project) && [ $(project).location ]
587 local location = [ $(project).location ] ;
588 local m = [ $(project).project-module ] ;
589 local project-id = [ project.attribute $(m) id ] ;
590 project-id ?= [ path.root $(location) [ path.pwd ] ] ;
591 return [ property.translate $(properties)
592 : $(project-id) : $(location) : $(m) ] ;
596 return $(properties) ;
600 rule check-target-builds ( target message ? : true-properties * :
603 local instance = [ new check-target-builds-worker $(target) $(message) :
604 $(true-properties) : $(false-properties) ] ;
605 local rulename = [ indirect.make check : $(instance) ] ;
606 return <conditional>@$(rulename)
607 [ property.evaluate-conditional-relevance
608 $(true-properties) $(false-properties) ] ;
612 # [ configure.choose "architecture"
613 # : /config//x86 x86 <architecture>x86
614 # : /config//mips mips <architecture>mips
616 rule choose ( message : * )
618 local instance = [ new configure-choose-worker $(message)
619 : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9)
620 : $(10) : $(11) : $(12) : $(13) : $(14) : $(15) : $(16)
621 : $(17) : $(18) : $(19) ] ;
622 local rulename = [ indirect.make check : $(instance) ] ;
623 return <conditional>@$(rulename)
624 [ property.evaluate-conditional-relevance
625 [ $(instance).all-properties ] ] ;
629 IMPORT $(__name__) : check-target-builds : : check-target-builds ;