Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Real targets with PHONY dependencies

Trying to find an elegant method to solve some complex dependencies. I have something like the following in my Makefile:

.PHONY: FOO
FOO: foo
foo:
    build foo

.PHONY: BAR
BAR: bar
bar: FOO
    build bar

The idea here is that I want to abstract the real files (foo, bar) with phony targets (FOO BAR). In my real Makefile, of course, it is more complicated which is why the abstraction is important. The problem here, though, is by making phony target FOO a dependency for bar, then Make always tries to rebuild bar even if both foo and bar are up-to-date. This is apparently because it always treats FOO as out-of-date. But this behavior is not really correct.

So it seems I only have 3 options: 1) Make bar directly dependent on foo. In my real Makefile it is more complicated and trying to specify the real files as dependencies is highly undesirable. 2) Use variables in addition to all the phonies. This makes the whole Makefile more complex. 3) Remove foo/Foo as a dependency from bar and add a recursive make of FOO as part of the rule in bar. This is very bad form.

Is there some more elegant solution that I am not aware of?

Thanks.

like image 336
Miguel Corazao Avatar asked Sep 06 '13 21:09

Miguel Corazao


2 Answers

As you suggest, variables are what you need, and can actually help readability. They allow us to make the bar-file depend correctly on the foo-file, rather than on your user-friendly .PHONY target:

foo.file = horrendously/long/path/to/the/real/foo.file
bar.file = horrendously/long/path/to/the/real/bar.file

.PHONY: FOO
FOO: $(foo.file)
$(foo.file):
        touch $@

.PHONY: BAR
BAR: $(bar.file)
$(bar.file): $(foo.file)
        touch $@

And here we go:

$ make BAR 
touch horrendously/long/path/to/the/real/foo.file
touch horrendously/long/path/to/the/real/bar.file

$ make BAR
make: Nothing to be done for `BAR'.
like image 125
Douglas Royds Avatar answered Nov 12 '22 02:11

Douglas Royds


GNU make's answer to this situation is order-only dependencies. It allows you to provide ordering of targets without having the "out of date" relationship as well. From your question, it appears that this is what you are looking for.

So your makefile snippet from above would look like this:

.PHONY: FOO
FOO: foo
foo:
    build foo

.PHONY: BAR
BAR: bar
bar: | FOO
    build bar

This will allow foo to always be built before bar, but will not mandate that when foo is updated, that bar must be built. foo will only be built when make BAR is called and foo's files do not exist.

like image 32
Mike K Avatar answered Nov 12 '22 01:11

Mike K