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


AMDG

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
https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_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 acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk