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 03:26:49

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 ?

> Even so, targets are not bound to specific filesystem
> paths until quite late. Processing the usage
> requirements of B happens long before we try find
> a sequence of generators that can create an executable
> from a .cpp file.

>> My point simply was that, at the time `b2 C` is invoked, nothing is
>> known yet about .../C.exe. It's the generator action associated with
>> C-gen that will inject a new target for .../C.exe, and make it a
>> prerequisite of C to tell b2 to build that as part of building C.
> C and C.exe exist at different layers of Boost.Build.
> calling [ targets.generate-from-reference C :
> $(project) : $(property-set) ]
> will give you back a virtual-target representing C.exe.
> It sounds like you're thinking that there's a
> dependency of C on C.exe, but there's no such thing,
> because they're totally different things.
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` ?)
>>>> <snip>
>>>>> main-target.construct(properties) returns a list of virtual targets.
>>>>> virtual-target.actualize() returns a Jam target.
>>>> OK. But given that at least in my earlier case with config checks
>>>> affecting the properties passed down to main-target.construct(),
>>> That's not quite correct. main-target.generate
>>> (I got the name wrong. The top-level interface
>>> that builds the dependency graph is called generate
>>> not construct.) processes conditional properties,
>>> including config checks.
>> That's exactly my point. main-target.generate would be invoked as part
>> of the "C-gen" update above (in my model), no ?
> I'm lost.

Sorry. I'm trying hard to match my mental model (which also happens to
be what I'm in the process of encoding in Faber) against yours (and thus
what b2 does). It seems I still need to work a bit to understand the b2
model. But I'm making progress, and I'm *really* grateful for all your
help and assistance.
>> I know. But as far as I understand, this is only needed as the only way
>> to get back the status of the target (i.e., whether it was built
>> successfully or not).
>> My whole question gravitates around the entire build process (including
>> the injection of new intermediate targets) being done in a single stage,
>> rather than requiring multiple distinct "config; make; test" stages.
> Saying that the build process only has a single
> stage is somewhat misleading. Originally, Boost.Build
> was separated into distinct phases, but configure checks,
> which were added later on, call back to the top level
> recursively somewhat muddying the waters.

I can see that.

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

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. 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.

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


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

Boost-Build list run by bdawes at, david.abrahams at, gregod at, cpdaniel at, john at