Consider this simple makefile:
all: output.txt
# The actual build command won't be this simple.
# It'll more be like "some-compiler file1.txt",
# which includes file2.txt automatically.
output.txt: file1.txt
cat file1.txt file2.txt > output.txt
file2.txt:
echo "heyo" > file2.txt
file1.txt: file2.txt
On first run, Make recognizes that file2.txt
is a dependency of file1.txt
, and so it needs to be built for output.txt
to be built. Thus, it runs echo "heyo" > file2.txt
and then cat file1.txt file2.txt > output.txt
.
However, on subsequent runs, if file2.txt
is changed, Make doesn't rebuild! If file1.txt
is changed it does, but not for file2.txt
. It just gives the dreaded make: Nothing to be done for 'all'.
message.
One hacky solution I've seen people suggest is to do the following:
all: output.txt
output.txt: file1.txt file2.txt
cat file1.txt file2.txt > output.txt
However, that's not possible in my case, as my secondary dependencies (the lines like file1.txt: file2.txt
) are dynamically generated using include
.
How do I make sure Make checks for modifications all the way up the tree when I have multiple levels of dependencies?
I think the problem here is that your makefile is slightly too simple.
Let a -> b
denote a depends on b
. From your makefile you have...
output.txt -> file1.txt -> file2.txt
When make
tries to update output.txt
it sees that output.txt
depends on file1.txt
. It then notices that file1.txt
depends on file2.txt
. At that point the dependency chain stops. If make sees that file2.txt
is newer than file1.txt
it will run the command(s) that is associated with the file1.txt: file2.txt
delendency. In this case, however, there aren't any commands -- just the dependency itself. That's fine as things go, but it does mean that even if file2.txt
is updated file1.txt
won't be. Hence, when make moves up the dependency chain to...
output.txt: file1.txt
it sees that output.txt
is still newer than file1.txt
so there is no need to run any command associated with that dependency.
If you add the touch
command...
file1.txt: file2.txt
touch $@
then file1.txt
will be updated and so the dependency chain works as you expect.