I have a Makefile that depends on a few things from a subproject that has its own Makefile. In the subproject, the targets have dependencies which I was hoping my main project would not have to know about. So I am trying to use the subproject's Makefile to build anything I need from it when necessary. This is what I have in my sample project before building:
$ find . -type f | xargs head
==> ./subproject/Makefile <==
binary: source.txt
echo subproject source: > $@
date >> $@
cat $< >> $@
clean:
rm binary
==> ./subproject/source.txt <==
this is the subproject source code
==> ./Makefile <==
binary: source.txt subproject/binary
echo main source: > $@
date >> $@
cat $^ >> $@
subproject/%:
$(MAKE) -C $(@D) $(@F)
clean:
rm binary
$(MAKE) -C subproject clean
==> ./source.txt <==
this is the main source code
and this is what I have after building:
$ make
make -C subproject binary
make[1]: Entering directory '~/make-example/subproject'
echo subproject source: > binary
date >> binary
cat source.txt >> binary
make[1]: Leaving directory '~/make-example/subproject'
echo main source: > binary
date >> binary
cat source.txt subproject/binary >> binary
$ find . -type f | xargs head
==> ./subproject/Makefile <==
binary: source.txt
echo subproject source: > $@
date >> $@
cat $< >> $@
clean:
rm binary
==> ./subproject/binary <==
subproject source:
Di 10. Okt 14:01:03 CEST 2023
this is the subproject source code
==> ./subproject/source.txt <==
this is the subproject source code
==> ./Makefile <==
binary: source.txt subproject/binary
echo main source: > $@
date >> $@
cat $^ >> $@
subproject/%:
$(MAKE) -C $(@D) $(@F)
clean:
rm binary
$(MAKE) -C subproject clean
==> ./binary <==
main source:
Di 10. Okt 14:01:03 CEST 2023
this is the main source code
subproject source:
Di 10. Okt 14:01:03 CEST 2023
this is the subproject source code
==> ./source.txt <==
this is the main source code
alex@elephant:~/make-example$
When I change subproject/source.txt
, and run make
in the parent project, it still doesn't recompile.
I can almost fix that like this:
subproject/%: always
$(MAKE) -C $(@D) $(@F)
always:
when make is run in the subproject, subproject/binary
will not be recompiled. However, binary
in the parent project will still get recompiled because one of its prereqs got run, even if the date on prereq file is old.
So I think that the answer is probably that this is not how I am supposed to be doing it. I really wanted the parent project and subproject to know as little about one another as possible.
Is there any way to make the parent project check the date on subproject/binary
and use that to determine whether to rebuild binary
even if the subproject/binary
formula was run?
I would like to be able to type make
and build it, and then change subproject/source.txt
and type make
again in the main project, and have it recompile subproject/binary
and then recompile binary
as a result, and then right after, not change anything, and type make
again, not recompile anything
You write:
However, binary in the parent project will still get recompiled because one of its prereqs got run, even if the date on prereq file is old.
That is not how make works. Just because a recipe is invoked does not mean that make always assumes that the target was modified; make will examine the modification time of the prerequisite and compare it, even if the prerequisite's recipe was invoked.
So, if you're seeing binary
always rebuilt then something else is happening here: maybe the sub-make is written in such a way that it always modifies the binary. You may want to use make --trace
or make -d
to understand why make decides to rebuild binary
.
Example:
UPDATE = touch $@
binary: prereq; touch $@
prereq: FORCE ; : updating; $(UPDATE)
FORCE:
Now:
$ make
: updating; touch prereq
touch binary
$ make
: updating; touch prereq
touch binary
as expected, but now if we don't actually change the prerequisite:
$ make UPDATE=
: updating;
We can see that the prerequisite updating rule was run, but since it didn't actually change prereq
, make didn't rebuild binary
.