Potatoswatter
Potatoswatter

Reputation: 137820

GNU make: clean target depends on includes

I'm using gmake and gcc -MM to track header dependencies, following the manual. The mechanism relies on a makefile include directive to import the computed dependencies.

Because the .d files are included by the makefile, they must exist for any target to be made, including clean. So before clean can do the right thing, the dependencies must be generated, and if one fails to build then clean just made more mess.

Besides clean, it wants to make all the dependencies before building any target.

Furthermore, if any file is changed to include a nonexistent file, then the dependency resolution breaks and nothing at all will build.

If a header is deleted, then the existing dependency files contain still name it as a target, and nothing will build until the offending dependency files are removed… which can't be done with clean.

Replacing the substitution pattern of the include with a wildcard to include all preexisting dependency files solves some of the issues, but it still can't clean out a broken dependency, and stale dependency files are never removed. Is there a better solution? Is the manual's example really intended for real use?

Upvotes: 17

Views: 5259

Answers (3)

Jorgeluis
Jorgeluis

Reputation: 197

The solution is to use Conditional Syntax:

ifneq ($(MAKECMDGOALS), clean)
-include $(notdir $(SOURCES:.cpp=.d))
endif

This makes the clean target do not invoke the *.d targets, since when you run make clean the *.d files will not be included in the Makefile.

Reference: https://www.gnu.org/software/make/manual/html_node/Goals.html

Upvotes: 10

Eldar Abusalimov
Eldar Abusalimov

Reputation: 25493

Just don't provide a rule for generating .d files. A good explanation of why it is not so good (including your case too) is available in "Advanced Auto-Dependency Generation" of Paul Smith - a maintainer of GNU Make.

In a nutshell, the following pattern works fine for me for all cases:

CPPFLAGS += -MMD -MP

%.o: %.c
    $(CC) $(CPPFLAGS) $(CFLAGS) -o $@ -c $<

-include $(OBJS:.o=.d)

See also my previous related answers:

Upvotes: 19

sehe
sehe

Reputation: 393114

My usual pattern looks like

all: target
target: .depends

## [snip build rules]

.depends:
     gcc -MM $(CPPFLAGS) .... > $@

-include .depends

Note -include instead of include. Basically, it includes conditionally: i.e. iff file exists

See documentation: http://www.gnu.org/software/make/manual/make.html#Include

Upvotes: 2

Related Questions