From 3ae87ff4966b433dc916c13bbc64b57e42d74df6 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Tue, 19 Dec 2017 13:30:09 -0700 Subject: [PATCH] Add a new rule configure.choose that adds properties associated with the first target from a list that successfully builds. --- src/build/configure.jam | 223 ++++++++++++++++++++++++++++++++++++++++ test/configure.py | 55 +++++++++- 2 files changed, 276 insertions(+), 2 deletions(-) diff --git a/src/build/configure.jam b/src/build/configure.jam index ff0f2b561..34ddc70b5 100644 --- a/src/build/configure.jam +++ b/src/build/configure.jam @@ -222,6 +222,89 @@ rule try-build ( targets * : ps : what : retry ? ) return $(result) ; } +# Attempts to build several sets of virtual targets. Returns the +# the index of the first set that builds. +rule try-find-build ( ps : what : * ) +{ + local args = 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; + # The outer layer only needs to check $(what), but we + # also need to check the individual elements, in case + # the set of targets has changed since the last build. + local cache-name = $(what) $($(args)[1]) [ $(ps).raw ] ; + cache-name = $(cache-name:J=-) ; + local value = [ config-cache.get $(cache-name) ] ; + + local result ; + local jam-targets ; + + + # Check whether we need to force rebuild configure targets + if --reconfigure in [ modules.peek : ARGV ] + { + local all-targets ; + for local t in $($(args)[2-]) + { + all-targets += [ virtual-target.traverse $(t) ] ; + } + for local t in [ sequence.unique $(all-targets) ] + { + $(t).always ; + } + } + + if $(value) + { + local none = none ; # What to show when the argument + local name = $(value) ; + if $(name) != none + { + name = [ CALC $(name) + 2 ] ; + } + local x = [ PAD " - $(what)" : $(.width) ] ; + local y = [ PAD $($(name)[1]) : 3 ] ; + result = $(value) ; + log-check-result "$(x) : $(y) (cached)" ; + } + else + { + local x = [ PAD " - $(what)" : $(.width) ] ; + for local i in $(args) + { + local jam-targets ; + for local t in $($(i)[2-]) + { + jam-targets += [ $(t).actualize ] ; + } + if [ UPDATE_NOW $(jam-targets) : + $(.log-fd) : ignore-minus-n : ignore-minus-q ] + { + result = [ CALC $(i) - 2 ] ; + log-check-result "$(x) : $($(i)[1])" ; + break ; + } + } + if ! $(result) + { + result = none ; + } + } + if ! $(value) + { + if $(result) + { + config-cache.set $(cache-name) : $(result) ; + } + else + { + config-cache.set $(cache-name) : $(result) ; + } + } + if $(result) != none + { + return $(result) ; + } +} + # Attempt to build a metatarget named by 'metatarget-reference' # in context of 'project' with properties 'ps'. # Returns non-empty value if build is OK. @@ -248,6 +331,68 @@ rule builds-raw ( metatarget-reference : project : ps : what : retry ? ) } } +# Attempt to build a metatarget named by 'metatarget-reference' +# in context of 'project' with properties 'ps'. +# Returns the 1-based index of the first target +# that builds. +rule find-builds-raw ( project : ps : what : * ) +{ + local result ; + local args = 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ; + + if ! $(.$(what)-tested.$(ps)) + { + .$(what)-tested.$(ps) = true ; + local targets.$(i) what.$(i) ; + for local i in $(args) + { + if ! $($(i)) + { + break ; + } + targets.$(i) = [ targets.generate-from-reference + $($(i)[1]) : $(project) : $(ps) ] ; + # ignore usage requirements + targets.$(i) = $(targets.$(i)[2-]) ; + if $($(i)[2]) + { + what.$(i) = $($(i)[2]) ; + } + else + { + local t = [ targets.resolve-reference + $($(i)[1]) : $(project) ] ; + what.$(i) = [ $(t[1]).name ] ; + } + } + + result = [ try-find-build $(ps) : $(what) + : $(what.4) $(targets.4) + : $(what.5) $(targets.5) + : $(what.6) $(targets.6) + : $(what.7) $(targets.7) + : $(what.8) $(targets.8) + : $(what.9) $(targets.9) + : $(what.10) $(targets.10) + : $(what.11) $(targets.11) + : $(what.12) $(targets.12) + : $(what.13) $(targets.13) + : $(what.14) $(targets.14) + : $(what.15) $(targets.15) + : $(what.16) $(targets.16) + : $(what.17) $(targets.17) + : $(what.18) $(targets.18) + : $(what.19) $(targets.19) ] ; + .$(what)-result.$(ps) = $(result) ; + + return $(result) ; + } + else + { + return $(.$(what)-result.$(ps)) ; + } +} + local rule get-relevant-features ( ) { local relevant = [ feature.expand ] ; @@ -286,6 +431,19 @@ rule builds ( metatarget-reference : properties * : what ? : retry ? ) $(retry) ] ; } +rule find-builds ( what : properties * : * ) +{ + local relevant = [ property.select [ get-relevant-features ] : $(properties) ] ; + local ps = [ property-set.create $(relevant) ] ; + local t = [ targets.current ] ; + local p = [ $(t).project ] ; + + return [ find-builds-raw $(p) : $(ps) : $(what) : + $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) : + $(10) : $(11) : $(12) : $(13) : $(14) : $(15) : + $(16) : $(17) : $(18) : $(19) ] ; +} + # Called by Boost.Build startup code to specify the file to receive the # configuration check results. Should never be called by user code. @@ -330,6 +488,57 @@ class check-target-builds-worker } } +class configure-choose-worker +{ + import configure ; + import property ; + rule __init__ ( message : * ) + { + self.message = $(message) ; + for i in 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 + { + local name = [ CALC $(i) - 1 ] ; + self.targets.$(name) = $($(i)[1]) ; + if ! $($(i)[2]:G) # Check whether the second argument is a property + { + self.what.$(name) = $($(i)[2]) ; + self.props.$(name) = $($(i)[3-]) ; + } + else + { + self.props.$(name) = $($(i)[2-]) ; + } + } + } + rule check ( properties * ) + { + local i = [ configure.find-builds $(self.message) : $(properties) + : $(self.targets.1) $(self.what.1) + : $(self.targets.2) $(self.what.2) + : $(self.targets.3) $(self.what.3) + : $(self.targets.4) $(self.what.4) + : $(self.targets.5) $(self.what.5) + : $(self.targets.6) $(self.what.6) + : $(self.targets.7) $(self.what.7) + : $(self.targets.8) $(self.what.8) + : $(self.targets.9) $(self.what.9) + : $(self.targets.10) $(self.what.10) + : $(self.targets.11) $(self.what.11) + : $(self.targets.12) $(self.what.12) + : $(self.targets.13) $(self.what.13) + : $(self.targets.14) $(self.what.14) + : $(self.targets.15) $(self.what.15) + : $(self.targets.16) $(self.what.16) + : $(self.targets.17) $(self.what.17) + : $(self.targets.18) $(self.what.18) + : $(self.targets.19) $(self.what.19) ] ; + if $(self.props.$(i)) + { + return [ property.evaluate-conditionals-in-context $(self.props.$(i)) : $(properties) ] ; + } + } +} + rule check-target-builds ( target message ? : true-properties * : false-properties * ) @@ -339,5 +548,19 @@ rule check-target-builds ( target message ? : true-properties * : return @$(instance).check ; } +# Usage: +# [ configure.choose "architecture" +# : /config//x86 x86 x86 +# : /config//mips mips mips +# ] +rule choose ( message : * ) +{ + local instance = [ new configure-choose-worker $(message) + : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) + : $(10) : $(11) : $(12) : $(13) : $(14) : $(15) : $(16) + : $(17) : $(18) : $(19) ] ; + return @$(instance).check ; +} + IMPORT $(__name__) : check-target-builds : : check-target-builds ; diff --git a/test/configure.py b/test/configure.py index 00b007ac2..73b39e9db 100644 --- a/test/configure.py +++ b/test/configure.py @@ -9,7 +9,7 @@ import BoostBuild -def test_basic(): +def test_check_target_builds(): t = BoostBuild.Tester(use_test_config=0) t.write("Jamroot", """ import configure ; @@ -67,4 +67,55 @@ obj bar : foo.cpp : t.cleanup() -test_basic() +def test_choose(): + t = BoostBuild.Tester(use_test_config=0) + t.write("Jamroot", """ +import configure ; +obj pass : pass.cpp ; +obj fail : fail.cpp ; +explicit pass fail ; +obj foo : foo.cpp : + [ configure.choose "which one?" : fail FAIL : pass PASS ] ; +""") + t.write("pass.cpp", "void f() {}\n") + t.write("fail.cpp", "#error fail.cpp\n") + t.write("foo.cpp", """ +#ifndef PASS +#error PASS not defined +#endif +#ifdef FAIL +#error FAIL is defined +#endif +""") + t.run_build_system() + t.expect_output_lines([ + " - which one? : pass"]) + t.expect_addition("bin/$toolset/debug*/pass.obj") + t.expect_addition("bin/$toolset/debug*/foo.obj") + t.expect_nothing_more() + + # An up-to-date build should use the cache + t.run_build_system() + t.expect_output_lines([ + " - which one? : pass (cached)"]) + t.expect_nothing_more() + + # -a should re-run everything, including configuration checks + t.run_build_system(["-a"]) + t.expect_output_lines([ + " - which one? : pass"]) + t.expect_touch("bin/$toolset/debug*/pass.obj") + t.expect_touch("bin/$toolset/debug*/foo.obj") + t.expect_nothing_more() + + # --reconfigure should re-run configuration checks only + t.run_build_system(["--reconfigure"]) + t.expect_output_lines([ + " - which one? : pass"]) + t.expect_touch("bin/$toolset/debug*/pass.obj") + t.expect_nothing_more() + + t.cleanup() + +test_check_target_builds() +test_choose()