Boost logo

Boost-Build :

Subject: Re: [Boost-build] feature, properties, variants, and all the rest
From: Stefan Seefeld (stefan_at_[hidden])
Date: 2017-08-04 12:22:01


On 04.08.2017 00:41, Steven Watanabe via Boost-build wrote:
> AMDG
>
> On 08/03/2017 09:26 PM, Stefan Seefeld via Boost-build wrote:
>> On 03.08.2017 20:37, Steven Watanabe via Boost-build wrote:
>>> On 08/03/2017 03:57 PM, Stefan Seefeld via Boost-build wrote:
>>>> Consider again my earlier example, where the target "C" depends on some
>>>> config checks "A" and "B", during the update of which some properties
>>>> will be set that are used to build C.
>>>> I think the spelling was
>>>>
>>>> exe C : C.cpp : [ check-target-builds B : <use>B ] ;
>>>>
>>>> So, let's assume that one of the usage requirements of "B" affects the
>>>> choice of the toolset, or some other essential property that influences
>>>> the qualified filename .../C.exe.
>>> That's not allowed. Only free features can be
>>> used in usage-requirements. The appending
>>> behavior of free features is necessary. If
>>> usage requirements can override properties, then
>>> it's essentially impossible to maintain consistency.
>> Can you give an example of a scenario giving rise to inconsistency,
>> would this be allowed ?
>>
> There's no clear priority for usage-requirements
> from two different dependencies. As a result,
> if two dependencies have contradictory usage
> requirements, it can only be a hard error, as
> neither one can override the other. Propagated
> features are even more problematic because they
> are supposed to be passed on to dependencies.
> Therefore propagated usage requirements would
> have to spread out to the entire dependency graph,
> which is completely impractical.

Yeah, I can see that.
>> <snip>
>> Can you elaborate ? (I believe I understand the distinction between
>> "main targets", "virtual targets", and "jam targets". However, from an
>> operational POV, I wonder what happens: If I invoke `b2 C`, "C" is
>> recognized as a target, so needs to correspond to something the
>> scheduler knows, right ? Similarly, if I want `b2 C` to actually build
>> some .../C.exe, I need to make that .../C.exe a prerequisite of C, no ?
>> (If not, can you please outline to logic leading to the making of
>> .../C.exe from the invocation of `b2 C` ?)
> It's pretty simple. The list of main targets is
> lowered to a list of virtual-targets. These virtual-targets
> are then lowered to Jam targets which are passed to
> the engine.

When does this lowering happen in b2 ? I thought this was managed by the
engine itself (i.e. would happen after the Jamfiles are read in, and
even after the configure checks have been run, which - in my model -
would mean that these steps could be represented by some synthetic
intermediate targets (such as that "C-gen" step I invented for the
purpose of the discussion).
>> In Faber, I was able to do the multi-stage thing, i.e. have a first
>> "config" phase (done in-sync while the "fabscripts" - the equivalent of
>> Jamfiles - were read in), which resulted in a fully constructed
>> dependency graph. Then, the actual build would simply execute that
>> dependency graph (or parts of it expressed by the goals from the
>> command-line).
>>
>> But I came to the conclusion that this results in a messy encoding of
>> dependencies (and an equally in-elegant process), so I'm now rewriting
>> the necessary logic to make the dependency graph dynamic, i.e. add to it
>> while it is being executed.
> I think I understand where you're coming from now.
> Boost.Build makes no attempt to model configure
> checks explicitly in the dependency graph, which
> seems to be what you're trying to achieve. In b2,
> configure checks just take advantage of the ability
> to inject arbitrary code into the target generation
> phase. The main advantages and disadvantages of
> this approach are:
> + It's easy to retrofit into an existing system
> + The dependency graph has a fairly simple representation.
> I honestly have no idea how to represent configure
> checks, as they behave quite differently from normal
> dependencies.
> - Running configure checks in parallel is difficult to impossible

How so ? At least the typical autoconf-style configure checks do little
more than running compilation and linking steps. The main difference is
that the results are fed back into the dependency graph.

> - The implicit dependency on the configure check means
> that the actual dependency graph is incomplete, which
> gets in the way if you want to process it in some way
> other than just updating.

Well, yeah, the dependency graph becomes dynamic, which prevents static
analyses.
>> As it is my understanding that b2 does at
>> least most of it, too, I want to understand how it does it, and what
>> requirement and restrictions it puts on the input.
>>
> The main restriction on modifying the dependency graph
> at the low level is that no out-edges can be added to
> a target after it has been updated. This is easy to
> guarantee as long as you have declarative target definitions.
What do you mean by "out-edge" ?

>
>> Again, many thanks for all your help. I hope this will be useful not
>> just for my own understanding, but for others, too.
>>

Thanks,
        Stefan

-- 
      ...ich hab' noch einen Koffer in Berlin...

Boost-Build list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk