3

Let's say that I have a Makefile that has two “main” targets: foo.o and clean. The former one has a recipe to create the foo.o file. The latter one removes all the temporary files.

To remove the need of specifying the dependencies of foo.o manually, I have target foo.d that is valid makefile specifying the dependencies in format foo.o foo.d : dep1 dep2 depn. This dependency file is included to the makefile.

The makefile looks like this:

;; This buffer is for text that is not saved, and for Lisp evaluation.
;; To create a file, visit it with C-x C-f and enter text in its buffer.

foo.o: foo.c
    cc -c -o $@ $<

foo.d: foo.c
    sh deps.sh $< > $@

include foo.d

.PHONY: clean
clean:
    rm …

When I want to make foo.o, everything works correctly: foo.d gets (re)made, it is included and foo.o gets made. The problem is that when I want to make the clean target, foo.d gets included, or even made.

How can I prevent make including the foo.d when clean target is being made? (Or, how to include that only when foo.o is made?)

The solution can use features of GNU Make.

1 Answer 1

1

The solution is quite simple, but results into somewhat unreadable Makefile code.

First, we must know that include directive tries to include the file, and if it does not exist, fails. There is also -include (or sinclude) that does simply does not include the file, if it does not exist. But that is not the thing we want, because it stills tries to remake the included makefile, if possible.

We can avoid that in two ways: either by changing the include directive parameter in such way that Makefile thinks it is not able to make that included file (e.g. relative vs absolute path etc.), or by omitting the parameter when the file does not exist. That can be done in multiple ways:

-include $(wildcard foo.d*)

but that has one problem: it matches also other files. So we can write this:

-include $(filter foo.d,$(wildcard foo.d*))

or even this:

-include $(filter foo.d,$(wildcard *))

And we made another problem: foo.d does not get made. This is resolved either by adding it as another target of the foo.o:

foo.o: foo.c foo.d

or adding it as a command:

foo.o: foo.c
    $(MAKE) foo.d
    cc …

or directly, without invoking make:

foo.o: foo.c
    sh script.sh …
    cc …

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .