= Proposal for "Do the Right Thing" Alternative Selection = [[PageOutline(1-6, Contents)]] This page describes a proposal for a change to the way target alternatives are selected. == Motivation == It seems there are a significant number of {{{bjam}}} invocations for which there is a sensible interpretation, but for which Boost.Build currently generates an error instead and refuses to build. === Example 1 === Given the following Jamfile: {{{ lib a : a.cpp : off ; # alternative 1 lib a : a-dbg.cpp : on on ; # alternative 2 }}} In response to {{{ bjam debug-symbols=on }}} the result is {{{ error: No best alternative for ./a next alternative: required properties: off not matched next alternative: required properties: on on not matched }}} My claim is that it would be more appropriate to build the 2nd alternative because it is a better match for the explicit build request. Boost.Build generates an error because the default value of the {{{}}} feature is "{{{off}}}". Boost.Build combines that default value with the explicit build request to get {{{on off}}}, which does not match the 2nd alternative. === Example 2 === I know at this point you're probably saying "that makes sense; you asked for something for which there's no alternative with matching requirements." However, "no matching requirements" is currently ''not'' an error when there's only one alternative declared: {{{ # b and c both have only one alternative. lib b : b.cpp : off ; lib c : c.cpp : on on ; }}} in this case, {{{bjam debug-symbols=on}}} happily builds both {{{b}}} (with debug-symbols off) and {{{c}}} (with profiling on) despite the fact that the requirements for {{{b}}} directly contradict the explicit build request and that the requirements for {{{c}}} contradicts the default for {{{profiling}}}, which is implicitly {{{off}}}. The behavior in example 2 may seem counterintuitive, but it is widely regarded as desirable to succeed in building ''something'', even if it doesn't exactly match what the user asked for, than to cause an error. I'm not challenging that premise in this proposal. In fact, the point of this proposal is to make the case where there are multiple alternatives more consistent with that principle. === Definition of "Best" === Indeed, the error message didn't say "there's no matching alternative;" it said there's "no ''best'' alternative." Whether or not we accept this proposal turns on how we define "best." I propose that in example 1, the fact that alternative 2 matches an ''explicitly specified'' build property should make it "better" than alternative 1. === Example 3 === This example is a simplified, but equivalent, version of the example in ticket #16: {{{ lib test : : test gcc multi ; lib test : : test.lib msvc multi ; }}} a simple "{{{bjam toolset=gcc}}}" currently yields: {{{ error: No best alternative for ./test next alternative: required properties: multi gcc not matched next alternative: required properties: multi msvc not matched }}} Here Boost.Build complains because the {{{single}}} is the default. If you read ticket #16, you can see that the intended result was that Boost.Build choose the first alternative. My proposed change would accomplish that with no change in the Jamfile. We would lose the capability of specifying these alternatives in such a way that the build request {{{bjam toolset=gcc}}} causes an error. == Details of Proposed Semantics == The semantics I'm proposing depend on the notion of "explicitly-requested" build properties. '''Definition:''' a top-level target's explicitly-requested build properties are those that are specified on the command line, e.g. {{{bjam }}} '''{{{threading=multi}}}'''. A dependency target's explicitly-requested build properties are those that are propagated from its dependent target(s). As a special case, {{{}}} is always considered to be explicitly requested, even when not explicitly specified on the command line. When choosing among target alternatives, the one with the greatest number of requirements matching its explicitly-requested properties is selected. An ambiguity error is only reported when two alternatives match the same number of requirements. When searching for dependency targets, the dependent's requirements are combined with its explicitly-requested build properties to form a new set of explicitly-requested properties, to be applied to its dependencies. During combination, where a non-free feature in the dependent's requirements conflicts with its explicitly-requested properties, the requirement is selected over the the explicitly-requested value of that feature. == Not A Pure Extension == This is almost a pure extension (i.e. one that does not change the semantics of any currently-working cases) but not quite. One case that it would change is as follows ('''Example 3'''): {{{ lib a : a.cpp ; # 1st alternative lib a : a-dbg.cpp : multi on ; # 2nd alternative }}} Today, {{{ bjam debug-symbols=on }}} will select the first alternative. Under my proposal, it would select the 2nd. That leaves these questions: #. Is that an important difference? That is for you to answer. #. How would we get the current semantics? Read on... == Optional Extension to this Proposal == Currently, selecting a target alternative (when it's not the only alternative) requires that ''all'' its requirements be matched. It's not yet clear that the "require all requirements" is actually useful in real-world scenarios (I admit that not requiring requirements is a bit weird, but remember that we already don't require them for the single-alternative case, so maybe "requirements" is a misnomer anyway). If we decide it is important to support alternatives where all requirements are actually required in order to be selected, we would need a new notation. I suggest: {{{ lib a : a.cpp ; # 1st alternative lib a : a-dbg.cpp : multi/on ; # 2nd alternative }}} In this case, the 2nd alternative would only be selected if ''both'' {{{multi}}} and {{{on}}} were in the explicitly-requested properties. The exact way the matching algorithm should be changed to handle this capability, and especially what it would do with multiple slash-separated elements in the requirements, is a topic for discussion and research. We may decide it isn't important to handle this case, so it's not worth investing in a solution at this point.