diff --git a/boost_build_v2.html b/boost_build_v2.html index 0bae4791f..8bce989c5 100644 --- a/boost_build_v2.html +++ b/boost_build_v2.html @@ -22,12 +22,12 @@ div.alert { color: red } table { align: center; border: thin; } - + + - build request, build request expansion and directly requested targets + - conditional properties + -->
It is slighly better way is to copy new/user-config.jam + into one of the locations where it can be found (given in this table). This prevent you from + accidentally overwriting your config when updating.
--> @@ -740,8 +747,8 @@ boost-build /path/to/boost.build ; Each call to the 'exe' rule defines a new main target alternative for the main target a. In this case, the first alternative will be used for the gcc toolset, while the second - alternative will be used in other cases. TODO: document the exact - selection method under "Build process" below. + alternative will be used in other cases. See below for details.Sometime a main target is really needed only by some other main target. E.g. a rule that declared test-suite uses a main target that @@ -1029,17 +1036,17 @@ boost-build /path/to/boost.build ;
When there are several alternatives, one of them must be selected. The + process is as follows:
+ +Usually, Boost.Build handles implicit dependendies completely
diff --git a/src/build/targets.jam b/src/build/targets.jam
index 4641991ce..adf069c10 100644
--- a/src/build/targets.jam
+++ b/src/build/targets.jam
@@ -366,26 +366,65 @@ class main-target : abstract-target
self.alternatives += $(target) ;
}
+ # Returns the best viable alternative for this property-set
+ # See the documentation for selection rules.
local rule select-alternatives ( property-set )
{
- local viable ; # alternatives that may be used
- local ranks ; # ranks for viable alternatives
- for local v in $(self.alternatives)
+ # The algorithm: we keep the current best viable alternative.
+ # When we've got new best viable alternative, we compare it
+ # with the current one.
+
+ local best ;
+ local best-properties ;
+
+ if $(self.alternatives[2-])
{
- # For now, alternative should be derived from 'basic-target'.
- # We'll see if this restriction if reasonable.
- assert.equal [ is-a $(v) : basic-target ] : true ;
- local m = [ $(v).match-rank $(property-set) ] ;
-
- if $(m)
+ local bad ;
+ local worklist = $(self.alternatives) ;
+ while $(worklist) && ! $(bad)
{
- viable += $(v) ;
- ranks += $(m) ;
+ local v = $(worklist[1]) ;
+ local properties = [ $(v).match $(property-set) ] ;
+
+ if $(properties) != no-match
+ {
+ if ! $(best)
+ {
+ best = $(v) ;
+ best-properties = $(properties) ;
+ }
+ else
+ {
+ if $(properties) = $(best-properties)
+ {
+ bad = true ;
+ }
+ else if $(properties) in $(best-properties)
+ {
+ # Do nothing, this alternative is worse
+ }
+ else if $(best-properties) in $(properties)
+ {
+ best = $(v) ;
+ best-properties = $(properties) ;
+ }
+ else
+ {
+ bad = true ;
+ }
+ }
+ }
+ worklist = $(worklist[2-]) ;
}
+ if ! $(bad)
+ {
+ return $(best) ;
+ }
}
-
- local best = [ sequence.select-highest-ranked $(viable) : $(ranks) ] ;
- return $(best) ;
+ else
+ {
+ return $(self.alternatives) ;
+ }
}
@@ -486,20 +525,13 @@ class main-target : abstract-target
local best-alternatives = [ select-alternatives $(property-set) ] ;
if ! $(best-alternatives)
{
- # TODO: probably, should explain, for each alternative,
- # why it can't be build.
- print.wrapped-text
- "warning: skipped build of" [ full-name ]
+ errors.error
+ "skipped build of" [ full-name ]
"with properties" [ $(property-set).raw ]
"because no best-matching alternative could be found"
;
return [ property-set.empty ] ;
}
- else if $(best-alternatives[2])
- {
- # TODO: again, a better error message in in order.
- errors.error "Ambiguous alternatives for main target" [ full-name ] ;
- }
else
{
local result = [ $(best-alternatives).generate $(property-set) ] ;
@@ -781,32 +813,20 @@ class basic-target : abstract-target
return $(self.default-build) ;
}
- # Returns a number which estimates this targets's suitability for
- # building with the given 'property-set'. Among several alternatives
- # for a main target, the one with greatest match-rank will be used
- # to do actual generation. Return of empty value mean this target
- # can't be built with the given 'property-set'.
- rule match-rank ( property-set )
+ # Returns the alternative condition for this alternative, if
+ # the condition is satisfied by 'property-set'.
+ rule match ( property-set )
{
- # First check if our requirements can be satisfied.
- local rproperties = [ $(property-set).refine $(self.requirements) ] ;
-
- # Kluge: previously, link-incompatible alternatives were skipped
- # completely. Until a better alternative selection algorithm is
- # in place, treat such alternatives as having rank of zero.
- # As another kluge, add 1 to all other ranks so that zero is worse that
- # anything.
- if [ $(rproperties).link-incompatible-with $(property-set) ]
+ local condition = [ $(self.requirements).base ] ;
+ # Weed out conditional properties.
+ condition = [ MATCH ^([^:]*)\$ : $(condition) ] ;
+ if $(condition) in [ $(property-set).raw ]
{
- return 0 ;
+ return $(condition) ;
}
else
- {
- # Returns the number of properties common to requirements
- # and build request.
- return [ sequence.length "fake" [ set.intersection
- [ $(self.requirements).base ] :
- [ $(property-set).raw ] ] ] ;
+ {
+ return no-match ;
}
}
diff --git a/test/alternatives.py b/test/alternatives.py
index 7e8473be5..e4ced2c24 100644
--- a/test/alternatives.py
+++ b/test/alternatives.py
@@ -19,6 +19,29 @@ t.write("a.cpp", "int main() { return 0; }\n")
t.run_build_system("release")
t.expect_addition("bin/$toolset/release/a.exe")
+# Test that alternative selection works for ordinary
+# properties, in particular user-defined.
+t.write("project-root.jam", " ")
+t.write("Jamfile", """
+
+import feature ;
+feature.feature X : off on : propagated ;
+
+exe a : b.cpp ;
+exe a : a.cpp :