wiki:AlternativeSelection

Version 13 (modified by Dave Abrahams, 19 years ago) ( diff )

--

Proposal for "Do the Right Thing" Alternative Selection

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 : <debug-symbols>off ;                   # alternative 1
lib a : a-dbg.cpp : <debug-symbols>on <profiling>on ;  # alternative 2

In response to

bjam debug-symbols=on

the result is

error: No best alternative for ./a
    next alternative: required properties: <debug-symbols>off
        not matched
    next alternative: required properties: <debug-symbols>on <profiling>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 <profiling> feature is "off". Boost.Build combines that default value with the explicit build request to get <debug-symbols>on <profiling>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 : <debug-symbols>off ;
lib c : c.cpp : <debug-symbols>on <profiling>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 : : <name>test <toolset>gcc <threading>multi ;
lib test : : <name>test.lib <toolset>msvc <threading>multi ;

a simple "bjam toolset=gcc" currently yields:

error: No best alternative for ./test
    next alternative: required properties: <threading>multi <toolset>gcc
        not matched
    next alternative: required properties: <threading>multi <toolset>msvc
        not matched

Here Boost.Build complains because the <threading>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, <toolset> 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 : <threading>multi <debug-symbols>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 : <threading>multi/<debug-symbols>on ;  # 2nd alternative

In this case, the 2nd alternative would only be selected if both <threading>multi and <debug-symbols>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.

Note: See TracWiki for help on using the wiki.