Reputation: 49403
I have a bunch of C files in different directories and I'm getting a make: nothing to be done for 'all'
error with my recursive Makefile; however if I tweak the dependences I can get it to work... but I don't understand why I have to.
Here's my original Makefile:
APP_DIRS=rescoco ressys resvm
.PHONY: all
all: $(APP_DIRS)
$(APP_DIRS):
$(MAKE) --directory $@
clean:
$(RM) *~
Now if I change my line: .PHONY
to .PHONY: all $(APP_DIRS)
it builds fine.
Another possibility is if I change the line: $(APP_DIRS):
to $(APP_DIRS): clean
it builds fine.
(NOTE: removing .PHONY target doesn't change anything)
So what's going on here? Is the Makefile trying to tell me I haven't listed dependencies correctly? I was thinking make
would do something like:
.PHONY
I first have to build all
all
I first have to build $(APP_DIRS)
$(APP_DIRS)
has no prereqs so execute the command for that (which would cause the recursive makes to run). Clearly I am wrong; but why?
FYI, if it matters my files are structured something like this:
Makefile #top level makefile as seen above
/rescoco
rescoco.c
Makefile #builds rescoco src and moves archive to ../lib directory
/ressys
ressys.c
Makefile #same as above but for ressys
/resvm
resvm.c
Makefile #same as above but for resvm
/lib
and my build command is simply make
. When I run with make -n
or make -n all
I get no output at all:
:~/proj$ make -n all
make: Nothing to be done for 'all'.
:~/proj$
Upvotes: 0
Views: 1718
Reputation: 49473
Things first you should be aware of:
So your Makefile esentially only tells this:
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:
$(APP_DIRS):
to $(APP_DIRS): clean
implies that $(APP_DIRS)
depends on the clean
target.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
.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.
Upvotes: 2
Reputation: 703
This is how you can do it, just remove the wildcard if you don't want it.
make wildcard subdirectory targets
Upvotes: 0
Reputation: 4102
You are defining a variable named 'APP_DIRS' with a list of directories. That is fine.
You then do
$(APP_DIRS): make blah blah,
which is essentially equivalent to rescoco ressys resvm: make blah blah
which obviously isnt valid.
So you need to pretend your $(APP_DIRS) is a variable, not a target name, which seems to be what you're using it as.
having said that, think why .PHONY: all $(APP_DIRS) works
Upvotes: 0