|
Boost-Build : |
Subject: Re: [Boost-build] feature, properties, variants, and all the rest
From: Steven Watanabe (watanabesj_at_[hidden])
Date: 2017-08-03 21:38:36
AMDG
On 08/03/2017 03:08 PM, Stefan Seefeld via Boost-build wrote:
> On 03.08.2017 16:47, Steven Watanabe via Boost-build wrote:
>>
>> On 08/03/2017 02:11 PM, Stefan Seefeld via Boost-build wrote:
>>> Yes, figured. Can you draw out the dependency graph in more detail (or
>>> just the bits involved in making 'C') ? If I request `b2 C`, what are
>>> the steps involved, leading up to some file
>>> "bin/gcc-7.1.1/release/.../C.exe" being generated ? I expect something
>>> like this:
>>>
>>> * C is declared in the Jamfile, as being depend on C-gen (a generator
>>> rule that will actually instantiate some further dependency graph for C)
>> I'm not quite sure what you mean by a generator rule.
>> generators are based on target type. So with C as
>> a typed-target{EXE}, we get:
>>
>> construct EXE from CPP:
>> - composing generator gcc.link OBJ -> EXE
>> (required properties <toolset>gcc-7.1.1) is viable
>> - Need OBJ, trying to construct OBJ from CPP
>> gcc.compile.c++ is viable
>
> I was referring to the fact that, as you confirmed in a previous reply,
> "building C means to generate the dependency graph [for C]", so I called
> that step that does that the "generator rule".
>
> My question really was this: Once the Jamfile is read in, the target "C"
> has to be registered, but the filename ".../C.exe" isn't, as it falls
> out of the generation of the dependency graph, which will determine what
> toolset to use, which in turn affects the qualified filename of C.exe.
Yep.
> Thus, I wondered how it is possible to submit to the engine a request to
> build "C", and have .../C.exe being made in the process even though at
> the time when the request is made nothing is known about it yet.
I don't follow. When you build C, you have to specify
the properties, which gives enough information to calculate
the file path.
> I thus imagined that one way to implement this was by making C dependent
> on C-gen, then let C-gen as it is being made inject other dependencies
> for C, notably all those that are concerned with the compilation from
> C.cpp into C.exe.
>
>>> * Thus, after reading the Jamfile, b2 does this:
>>>
>>> - considering C (to be built from C.cpp)
>>> - building C-gen (as C's "static" prerequisite)
>>> * this will determine g++-7.1.1 as the tool to build C.exe from
>>> C.cpp via C.o
>>> * thus, C.exe is injected as a new prerequisite target for C, C.o
>>> as dependency for C.exe
>>> - building C.o from C.cpp
>>> - building C.exe from C.o
>>> - building C (nothing left to do, it's just an alias for C.exe)
>>>
>>> Does this make sense, and more importantly, does it capture the logic in
>>> b2 ? (By "Static prerequisite" above I'm referring to the fact that the
>>> dependency from C to C-gen needs to be known before the engine is
>>> started, as otherwise it wouldn't find any prerequisites for C at all,
>>> and thus just make nothing in order for C to be considered up-to-date.)
>>>
>> It's no quite correct to say that C is an alias for
>> C.exe. There are actually three levels of targets.
>> - A main target (such as C) is what is defined in the Jamfile
>> - A virtual target is an intermediate layer representing
>> a specific file. There can be multiple virtual targets
>> for the same file as long as only one is actualized.
>> (This mainly exists to allow backtracking in generators.
>> Unlike a Jam target, creating a virtual-target doesn't
>> affect global state, so it's safe to create and discard
>> virtual-targets.)
>> - A Jam target is the thing that gets passed to the
>> build engine for processing.
>>
>> 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.
> the
> call to "main-target.construct" needs itself to happen in a rule that is
> invoked by the engine, after the config checks have been run, no ? So
> Your last statement above ("main-target.construct(properties) returns a
> list of virtual targets. virtual-target.actualize() returns a Jam
> target.") thus needs to be performed in chunks executed by the engine,
> rather than while the Jamfile is being processed. Right ?
There's one more rule:
UPDATE_NOW $(targets) ;
Calls into the engine to cause a list of Jam targets to
be updated immediately. Config checks use this to
update targets earlier than normal.
> And so it sounds like this transformation from main target over virtual
> targets to jam targets is the equivalent of my above workflow from C
> over C-gen to C.exe. Correct ?
>
It's sort of similar, but a single virtual-target represents
a specific file, not a group files.
In Christ,
Steven Watanabe
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