|
Boost-Build : |
From: Vladimir Prus (ghost_at_[hidden])
Date: 2002-11-12 01:42:57
David Abrahams wrote:
> Whatever's going on in this rule, it's _way_* too tricky. If it _were_
> important to do something this tricky, it's at least way
> under-commented:
Well, I believe we've concluded long ago that writing comments is not
my strong point. Let me explain.
General scheme for creating main target is:
1. You call some rule:
exe hello : hello.cpp ;
2. It does some preprocessing of requirements and default build.
3. That rules creates an instance of some class derived from 'abstract-target'.
In this case, it's 'typed-target'.
4. It obtains 'project-target' for the current project, and calls 'add-alternative'
method on it.
What's in step 2?
- If there are any path properties, they should be adjusted.
- You should refine parent's requirements with target's requirements.
- If no default build is specified, then parent's default build is
used instead.
You see that steps 2 and 4 are not specific to target type, but look at
'main-target-alternative' implementation. Those steps take a lot of code,
so it's desirable to not repeat them in all rules that declared targets.
I agree that the current solution is tricky.
> What the heck is "will be specially processed" supposed to indicate to
> the reader?
Refer to step 2 description above.
> Also, the way this rule is invoked is extremely tricky as well:
>
> rule main-target-rule ( name : sources * : requirements * : default-build *
> : use-requirements * )
> {
> # First find required target type, which is equal to the name used
> # to invoke us.
> local bt = [ BACKTRACE 1 ] ;
> local type = $(bt[4]) ;
>
> targets.main-target-alternative $(name) [ CALLER_MODULE ] typed-target : 3 : 5 : 4
> : $(type:U) : $(sources) : $(requirements) : $(default-build) : $(use-requirements)
> ;
> }
There are two aspects. First, it's as tricky as 'main-target-alternative' interface.
I did make mistakes with it several times myself. I believe we can use a better way:
- Introduce three rules:
- 'adjust-main-target-requirements'
- 'adjust-main-target-use-requirements'
- 'adjust-main-target-default-build'
- Call those rules as appropriate. This will make all this "3 : 5 : 4" unneeded.
You'd write
targets.main-target-alternative $(name)
[ new typed-target : $(type:U) : $(sources)
: [ adjust-main-target-requirements $(requirements) ]
: [ adjust-main-target-use-requirements $(use-requirements) ]
: [ adjust-main-target-default-build $(default-build) ]
] ;
This is more writing but is much more clear.
> Where does "type" come from? How do we get here?
> This kind of reaching back into the call stack always needs some extra
> comments to describe what's actually going on.
> Something should state explicitly that types and main target rule
> names have a one-to-one uppercase/lowercase relationship.
It is possible to create main target rule for any given type. That
rule will have the same name as type, only lower cases. In fact,
all those rules will call type.main-target-rule, which uses the
name it's called with to find what type is needed. I think that
the comment says that we're finding the name used to call us,
which is equal to type. Maybe, you could put it in better words?
BTW, I positively don't know why target types are uppercase! I belive
that's because the type hierarchy graph used in design discussion had
uppercase type names. Should we switch to lower-case type names?
- Volodya
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