Things first you should be aware of:
- If you have directories as dependencies, make is going to consider building the targets (i.e. executing the recipes for such directory targets), only if the modification timestamp of the directory gets updated.
This would happen only when you add a new file in the directory but not for file modifications in the directory. Adding files in a sub-directory does not change the timestamp of the directory.
- PHONY targets are meant to be used when executing such a target does not create a file with the name of the target. In other words, you want make to execute the rule irrespective of whether the file already exists or not.
So your Makefile esentially only tells this:
- To build the target
all
, I need to build $(APP_DIRS)
. Since all
is a PHONY target, I will always execute the recipe for all
.
$(APP_DIRS)
is not a PHONY
target and does not have any dependencies. So *only if $(APP_DIRS)
does not exist already (i.e. the file or directory), I'm going to execute the recipe, otherwise I'm doing nothing for this target.
clean
has no pre-requisite and not a PHONY
, so I expect to execute this rule only when explicitly invoked by make (from the command line or another Makefile). Also clean
is not a PHONY
, so I expect the recipe to create a file called clean
after execution (which is incorrect for your case)
Hence changing the .PHONY
line to:
.PHONY: all $(APP_DIRS)
makes the Makefile go and execute the recipe for $(APP_DIRS) always.
So if you would like make to always traverse into all of the $(APP_DIRS) directories and invoke make again on them, you need to add $(APP_DIRS)
to .PHONY
, which makes $(APP_DIRS) a PHONY target, and executes the recipe irrespective of the file's/directory's timestamp if it exists.
For your particular use-case, I think this is the Makefile you should be using:
APP_DIRS=rescoco ressys resvm
.PHONY: all clean $(APP_DIRS)
all: $(APP_DIRS)
$(APP_DIRS):
$(MAKE) --directory $@
clean:
$(RM) *~
BONUS:
- Changing
$(APP_DIRS):
to $(APP_DIRS): clean
implies that $(APP_DIRS)
depends on the clean
target.
- Although
clean
is not marked a PHONY, make does not see a file named clean
in the current directory. So it goes ahead and tries to execute the recipe for clean
.
- Since a dependency of $(APP_DIRS) (i.e.
clean
) was built, this makes the Makefile execute the recipe for building $(APP_DIRS).
This brings us to an interesting observation:
- Any target that depends on a PHONY target will always get rebuilt (i.e. the recipe would be executed).
Take this simple Makefile:
all: target1
target1: target2
@echo "$@"
@touch $@
target2: target3
@echo "$@"
@touch $@
target3:
@echo "$@"
.PHONY: all target3
The first time I run make
, I see this output:
target3
target2
target1
After this, files target1
and target2
are created. Even then, if I run make
again, I would see the output:
target3
target2
target1
As you can see, the PHONY
dependencies get propagated up and not the other way down. target2
gets rebuilt just because target3
is a PHONY, and target1
gets rebuilt just because target2
got rebuilt.