tech-pkg archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: bmake: : vs :: and :?



On Tue, Jun 10, 2008 at 11:03:39PM +0200, Edgar Fuß wrote:
> I suppose my question may as well be asked in tech-toolchain, but first its
> devel/bmake and second pkgsrc seems to be the single largest bmake 
> application,
> so I suppose knowledgeable people here.
> 
> My first question (probably a documentation issue) is about : vs ::.
> I thought (and ws@ taught me) that :: was for things like
> 
> default:: install
> 
> .if(have_foo)
> default:: install_foo
> .endif
> .if(have_bar)
> default:: install_bar
> .endif
> 
> so I would expect
> 
> default: x
> 
> default: y
> 
> to give syntax error, which it doesn't.
> OTOH, man bmake says
> 
> Sources for a target accumulate over dependency lines [for :]
> and
> Sources for a target do not accumulate over dependency lines [for ::]
> 
> Also, I can't tell a difference in the behavior of : and :: other than that ::
> with no dependencies always rebuilds the target while : only rebuilds if the
> target doesn't exist.
> 
> Can someone enlighten me? Am I misunderstanding something?

Yes, you're confusing dependencies and rules.

With `normal' make, you're supposed to have just one single rule for each
target.

Specifically:

target: dep1 dep2 dep3
        cmd

should occur just once.

If you have
target:
        cmd

target:
        cmd2

what happens is unspecified (in fact, bmake and gmake go about it in reverse.
gmake is nice enough to give you a warning, bmake doesn't even warn).

You can have *as many dependencies* as you want on separate lines.

target: dep4 dep5 dep6

and dependencies do accumulate.

This reflects normal use. Specifically, you will have a
.c.o:

rule somewhere that gives you the way to compile C file (and you don't even
have to have a more specific rule), and then, you add dependencies on header
files as separate dependency lines, namely:

a.o: a.h

b.o: a.h b.h

and this works as intended (in general, you don't even write this manually,
but ask mkdep to give you those lines).

The main idea being, you have one single rule to regenerate a target, and
it's run if and only if at least one of the dependencies is out-of-date.


:: is something entirely different, it's there to give you a set of
distinct rules/dependencies that affect the same file.

So, with ::, each rule/dependencies is evaluated separately, and the same
rule can be run repeatedly.

So:

target:: dep1 dep2
        cmdA

target:: dep3 dep4
        cmdB

target is matched against dep1 dep2, and dep3 dep4.
- if it's out of date wrt dep1 or dep2, cmdA is run
- if it's out of date wrt dep3 or dep4, cmdB is run

Note that both cmds will be run if both sets of deps are out of date.


> My second question is about the intended use of the :? modifier.

it's a way to have lazy simple tests.

It can be useful it you want to have different behavior based on variable
values you don't yet have.

Assume
HAS_XXX=Yes/No is set in an include file, say foo.mk.

Without :?

you have to write stuff in that order:

.include "foo.mk"


.if ${HAS_XXX} == "Yes"
B=targeta
.else
B=targetb
.endif


with ?:, you can actually reverse the order, and have everything nice
and shiny with your include at the end, which helps make the pkgsrc tree
all symetric.


Home | Main Index | Thread Index | Old Index