Subject: Re: [Boost-build] feature, properties, variants, and all the rest
From: Steven Watanabe (watanabesj_at_[hidden])
Date: 2017-08-05 23:44:37
On 08/05/2017 04:46 PM, Stefan Seefeld via Boost-build wrote:
> On 08/05/2017 05:14 PM, Steven Watanabe via Boost-build wrote:
>> On 08/04/2017 10:09 AM, Stefan Seefeld via Boost-build wrote:
>>> I have outlined the workflow of such a build with three different
>>> snapshots of the dependency graph:
>>> * one as it is encoded in the fabscript,
>>> * one has faber would see it once it has completed parsing the fabscript
>>> (and any other input, including command-line options), and
>>> * one some time later, once the dependency graph related to the "C"
>>> artefact has been expanded by the assembly.
>>> This corresponds to my own (mental) model, as well as how it is
>>> implemented in faber (some of which is still work in progress).
>>> So now I would like to understand whether you see any design flaws (or
>>> bugs) in this approach, and how that maps to b2's model.
>> I think that trying to represent both C and C.exe in
>> the same hierarchy is a bit tricky.
>> - Anything that depends on C should ultimately see C.exe.
> Yeah, good point.
>> - Similarly, this
>> alias sources : 1.cpp 2.cpp 3.cpp ;
>> exe C : sources ;
> Hmm, not sure. I think what you *want* to do is make "sources" literally
> a reference to these three files. But an "alias" in b2 (and likewise in
> faber) is a reference to a target / artefact, which can be used in the
> dependency graph, but not to alias / reference any related features /
An alias in Boost.Build can have both usage-requirements
>> is a bit harder to deal with if you have an
>> intermediate `sources` that exists along side 1.cpp etc.
>> In Boost.Build, sources is a main target, but it
>> completely disappears at the virtual-target layer.
>> (This is definitely solvable. It just makes things
>> a bit more complicated.)
> Yeah. As I'm using Python, I can of course simply define
> sources = ['1.cpp', '2.cpp', '3.cpp']
> and then pass that (list) object to the 'rule' call
> C = binary('C', sources)
> without 'sources' having to become an artefact. Likewise, I can imagine
> the Jam language to allow these kind of references without 'sources'
> having to become a 'target' (which the line
> alias sources : 1.cpp 2.cpp 3.cpp ;
> seems to suggest.
Of course, you can do it the same way in Jam:
local sources = 1.cpp 2.cpp 3.cpp ;
The reason for using a target is polymorphism.
The person using it doesn't have to care whether
it's a list of sources, some object files, a library,
or whatever. Also, this is only the simplest
use of alias. For example, choose sources based
alias sources : 1.cpp : <variant>debug ;
alias sources : 2.cpp : <variant>release ;
Create a standardized name for a target:
run test.cpp /boost//unit_test_framework ;
# /boost//unit_test_framework is actually an
# alias for path/to/boost/libs/test/build//unit_test_framework
A header only library:
alias mylib : : : <include>./include ;
>> In addition, I don't know if you have something akin to
>> propagated features, but if you do, then config checks
>> that set such features *must* be evaluated before building
>> dependencies and *may* force config checks to be evaluated
>> multiple times with different feature sets. This makes
>> them very different from normal dependencies.
> Yeah. I haven't run into the need for "propagated" features yet. In
> fact, I was wondering whether "propagated" really is an attribute of a
> feature (which as far as I understand it, is a "class" of properties),
> rather than a specific property. In other word, if I define a feature
> such as "define", I may not want to associate a "propagate" attribute to
> all instances of that feature, but rather specific ones. Anyhow, I
> haven't encountered a need for those yet. (Can you describe a use-case
> for "propagate" feature ?)
The need for propagated features stems from the fact that
Boost.Build allows multiple build configurations to be
handled simultaneously. They're basically used for anything
that would be global in other build systems, such as the toolset,
debug vs. release, static vs. shared, etc.
>>> (Note that I found a simple way to run the config checks without
>>> requiring synchronization: the outcome of an action is fed back into the
>>> associated artefact, from which it is available when the next action is
>>> performed. So the only call to "update_now" is the global one performed
>>> to update the goals from the command line...)
>> I think this is a good idea, but you'll need
>> to consider very carefully what artifacts should
>> be updated when a file is touched.
> Well, I think we agree that the dependency graph needs to be a directed
> acyclic graph. No cycles, so I don't really see how the "on-the-fly
> update" complicates anything, rather than simplifies the overall logic.
Do you try to issue an error for cycles, or do
you just hope for the best? Also, I don't know
how you handle #include scanning, but the way Jam
handles scanners causes cyclic #includes to create
a cyclic dependency in the internal nodes, which
is a total nightmare in the face of a dependency
graph that changes dynamically.
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