Boost logo

Boost-Build :

Subject: Re: [Boost-build] feature, properties, variants, and all the rest
From: Steven Watanabe (watanabesj_at_[hidden])
Date: 2017-09-29 18:20:36


On 09/29/2017 09:13 AM, Stefan Seefeld via Boost-build wrote:
> On 25.09.2017 19:49, Steven Watanabe via Boost-build wrote:
>> The interaction between SEARCH and LOCATE requires
>> the boundname of targets with an explicit LOCATE to
>> be set early.
>> SEARCH on <x>file1 = /path1 /path2 ;
>> LOCATE on <x/path1>file1 = /path1 ;
>> The boundname of <x>file1 is /path1/file1
>> and it gets a hard dependency on <x/path1>file1
> This reminds me of a (slightly) tangential question: how are header
> dependencies handled by bjam ? In particular:
> * it appears as if source code is scanned without any true
> pre-processing. Doesn't this lead to false positives (such as
> conditional include directives) ?

Yes. It also causes false negatives (#include through a macro).

> * how are include directives mapped (bound) to actual files ? Do you
> interact with the selected compiler to determine the absolute path ?

They're found using the include path.
(Headers in the compiler's default include
path will not be found)

> * it seems to me that letting the compiler itself do this work (the
> typical "make depend" idiom, using commands akin to `gcc -M`) would
> solve these issues. What are the reasons bjam doesn't use that strategy ?

- It's more efficient, since each header only needs to be read once.
- It can scan headers that are generated during the build.

>> In addition, it's impossible to determine
>> a target's fate without knowing its location,
>> as you need an actual file to check the timestamp.
>> To make this work, you'd need to merge make0 into
>> make1 completely. This creates another problem,
>> because the cycle detection in make0 requires a
>> strict depth-first search.
> I see "scc" related code in multiple locations, not just in make0().
> Assuming that that's the code used to detect cycles, how does it work,

scc = Strongly Connected Components.
The part in make0 is an implementation of Tarjan's algorithm

The other parts are for fixing up the result when
the dependency graph changes due to header scanning.

Basically we treat a cycle as if the entire cycle
were a single node. This works as long as none of
the targets have updating actions attached to them.
A #include cycle exists in the 'internal nodes',
which never have updating actions.

> and why isn't it a local call in make0 that
> simply raises an error if a cycle is detected ? In fact, why do cycles
> merely generate warnings, rather than errors ?

I don't know. I think it was originally that way,
and I never changed it.

> Is that merely to support
> cyclic header dependencies (which would be another argument to use
> something like `gcc -M`, as that would already break up cycles)

Cyclic headers don't generate any warning.

>> make1 handles asynchronous
>> execution, so the actual traversal order is
>> non-deterministic. (This is probably solvable,
>> but will make the algorithm even more complex)
> Slightly. The only issue I see right now (assuming the cycle detection
> to be solved separately) is with temporaries. If the binding happens
> late, there needs to be a provision to postpone the computation of a
> temporary's fate until the parent has been bound, as only then the
> timestamp comparison can take place. (This obviously implies that it
> shouldn't be possible for temporaries to update features, as that would
> require temporaries to be force-updated for the data flow to be
> well-defined).

In Christ,
Steven Watanabe

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