I have the following recursive makefile:
.PHONY: all clean %.subdir: $(MAKE) -C src $* $(MAKE) -C dict $* all: all.subdir clean: clean.subdir
and it works fine:
$ make all make -C src all make[1]: Entering directory `/or-1.3.6-fix/src' make[1]: Nothing to be done for `all'. make[1]: Leaving directory `/or-1.3.6-fix/src' make -C dict all make[1]: Entering directory `/or-1.3.6-fix/dict' make[1]: Nothing to be done for `all'. make[1]: Leaving directory `/or-1.3.6-fix/dict'
But it would be more logical to define %.subdir
rules as phony:
.PHONY: all clean all.subdir clean.subdir
and now make stops working as I want:
$ make all make: Nothing to be done for `all'. $ make -d all ... Updating goal targets.... Considering target file `all'. File `all' does not exist. Considering target file `all.subdir'. File `all.subdir' does not exist. Finished prerequisites of target file `all.subdir'. Must remake target `all.subdir'. Successfully remade target file `all.subdir'. Finished prerequisites of target file `all'. Must remake target `all'. Successfully remade target file `all'. make: Nothing to be done for `all'.
Can somebody explain me why (or even better point me to make documentation)?
PHONY: allows to declare phony targets, so that make will not check them as actual file names: it will work all the time even if such files still exist. You can put several . PHONY: in your Makefile : .
A phony target is one that is not really the name of a file; rather it is just a name for a recipe to be executed when you make an explicit request. There are two reasons to use a phony target: to avoid a conflict with a file of the same name, and to improve performance.
You're right, it would make more sense to define the subdir rules as PHONY. But Make does not consider implicit rules for PHONY targets, so you'll have to rewrite that rule. I suggest the following:
SUBDIR_TARGETS = all.subdir clean.subdir .PHONY: all clean $(SUBDIR_TARGETS) $(SUBDIR_TARGETS): %.subdir: $(MAKE) -C src $* $(MAKE) -C dict $* all: all.subdir clean: clean.subdir
That GNU make required targets declared as .PHONY
to be explicit has already been stated in the other answers, which also provided some remedy to this.
In this additional answer I would like to add an alterative which as I tested combines "phony" behavior, i.e. that targets are triggered each time no matter if a files of the same name exists (they are ignored). The alternative goes like this:
.PHONY: phony_explicit phony_explicit: %.subdir: phony_explicit $(MAKE) -C src $* $(MAKE) -C dict $*
It works on the premise that while only explicit targets can be set as .PHONY, whatever depends on a hence explicit phony target is itself inheriting much (to my knowledge all) phony attributes. An implicit, i.e. pattern matching target such as the %.subdir
above is just like if would being added to .PHONY
(which is impossible because it is not itself explicit), yet becoming phony via its prerequesite phony phony_explicit
.
It boils down that every rule - also implicit via pattern matching - which has in its prerequisites an explicit phony target (i.e. a target that is added to the .PHONY
) is via this dependency also executed in a phony style (everytime, unconditionally of the filesystem erronously having a file with a coninciding name).
Indeed the GNU make documentation mentions the FORCE
target, which in some versions of GNU that do not offer a .PHONY
target emulates partly the .PHONY
behaviour. The alternative presented here uses this FORCE
target approuch, yet because GNU make is used it also sets the FORCE
target as .PHONY
avoiding potential conflicts with really existing files of the same name.
With this solution even a
touch clean.subir; make clean.subdir
will yield the desired invocation of
make -C src clean make -C dist clean
What might be a potential pro point of this alternative is that it needs no explicit declaration of clean.subdir
and all.subdir
, but is really using the implicit %.subdir
pattern matching.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With