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)?
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.
From this section of the make manual:
The implicit rule search (see Implicit Rules) is skipped for .PHONY targets. This is why declaring a target as .PHONY is good for performance, even if you are not worried about the actual file existing.
Therefore, your implicit targets are never searched for because they are phony.
You can achieve what you are trying to do another way. Try this:
SUBDIRS := all clean
.PHONY: $(SUBDIRS)
$(SUBDIRS):
echo $(MAKE) -C src $@
echo $(MAKE) -C dict $@