简体   繁体   中英

Makefile Pattern rule: Circular makefile.o <- makefile dependency dropped

I am working on a makefile for a C++ project that needs to support a few configurations, ie debug , release and maybe a few more customized ones in the future.

Currently, my naming convention for generated .o files is $(SOURCE_FULLPATH).$(CONFIGURATION).o . For instance, ABC.cpp generates ABC.cpp.debug.o in debug mode.

Now I would like to write the pattern rule for generating those object files in a configuration-independent way. What I did was: from each XX.o filename, I strip the .debug or .release suffix from XX , and use the remaining part of XX as the source filename.

%.o: $$(basename %)
    $(CC) $(CC_FLAGS) $(INCLUDE_FOLDERS) -c -o $@ $<

With this trick, I can build the executable correctly, except that I get one warning message from make:

make: Circular makefile.o <- makefile dependency dropped.

I am puzzled because I do not list makefile or makefile.o as a target or dependency anywhere in my makefile. I did a search on SO, but most questions about Circular dependency is on a specific user source file, rather than the makefile itself. Can anyone help me understand what causes the circular dependency, and how to get rid of this warning message ?

A sample makefile that can reproduce this issue is listed below.

.SECONDEXPANSION:

PROJECT := helloworld
CC := clang++
BUILD_FOLDER := Build
OBJ_FILE_SUFFIX := .o

# Source
CPP_FILES :=\
    Source/hello.cpp \
    Source/mysqrt.cpp \

INCLUDE_FOLDERS := \
    -IInclude

# MMD outputs the dependency files (".d" files). These files will be used by
# this makefile to allow for dependency checking on .h files.
CC_FLAGS += -MMD

EXISTING_OBJ_FILES = $(wildcard $(addsuffix *.o, $(basename $(CPP_FILES))))

##--------------------
## Targets definition
##--------------------
.PHONY:default
default: all

.PHONY:all
all: debug release

.PHONY:debug release
# Add a 'debug'/'release' suffix to the name of the object file
# e.g. hello.cpp -> hello.cpp.debug.o
debug release: OBJ_FILES=$(addsuffix .$@$(OBJ_FILE_SUFFIX), $(CPP_FILES))
debug release: $${OBJ_FILES}    # Use Secondary Expansion to get the obj names
    $(CC) $^ -o $(BUILD_FOLDER)/$(PROJECT)_$@ 

# Strip configuration name from the end of the object file name
%.o: $$(basename %)
    $(CC) $(CC_FLAGS) $(INCLUDE_FOLDERS) -c -o $@ $<

## clean: remove executable, all object files, and all dependency files
.PHONY:clean
clean:
    -rm -f $(BUILD_FOLDER)/$(PROJECT) $(EXISTING_OBJ_FILES) $(EXISTING_OBJ_FILES:.o=.d)

# Include the dependent files so that in later builds, modified .h files 
# will cause all .cpp dependent on them to rebuild
-include $(OBJ_FILES:.o=.d)

The folder structure is

makefile
Source
- hello.cpp
- mysqrt.cpp
Include
- mysqrt.h

The full output of make debug is

make: Circular makefile.o <- makefile dependency dropped.
clang++ -MMD -IInclude -c -o Source/hello.cpp.debug.o Source/hello.cpp
clang++ -MMD -IInclude -c -o Source/mysqrt.cpp.debug.o Source/mysqrt.cpp
clang++ Source/hello.cpp.debug.o Source/mysqrt.cpp.debug.o -o Build/helloworld_debug 

Everything is good except for the first line.

I would also really appreciate it if anyone can point to me if there is any bad practice in my makefile (I am still a newbie in makefile). Thank you in advance!

GNU Make always attempts to update the makefile(s) it has read before making anything else. If it finds rules and prerequisites that tell it to update makefile(s), then it does so and then starts again from scratch - including attempting to update the makefile(s). See 3.5 How Makefiles Are Remade .

In your recipe:

%.o: $$(basename %)
    $(CC) $(CC_FLAGS) $(INCLUDE_FOLDERS) -c -o $@ $<

you have provided make with a rule for making makefile.o from makefile .

It is also the inverse of the rule in the builtin recipe

%: %.o
    $(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $@

which makes an executable from a single object file. So your recipe has introduced the circularity:

makefile.o <- makefile <- makefile.o

when make is considering makefile itself as a target. You could suppress the circularity by expressly deleting the builtin inverse rule, by writing the empty rule:

%: %.o

in the makefile. Then you could observe the following confusion on the part of the compiler:

$ make makefile.o
clang++   -c -o makefile.o makefile
clang: warning: makefile: 'linker' input unused

And the same would occur if you attempted to make any target that depended on makefile.o .

It is probably safe to assume that you will have no targets that depend on makefile.o . Nevertheless a rule that would attempt to compile foo.o from any existing file foo is clearly more sweeping that you want or need. For the particular pattern of dependency that you wish to capture:

foo.cpp.{debug|release}.o: foo.cpp

You'd be better off with:

%.o: $$(basename $$(basename %)).cpp
    $(CC) $(CC_FLAGS) $(INCLUDE_FOLDERS) -c -o $@ $<

Note, BTW, that in GNU Make conventions - the conventions that are assumed by GNU Make's builtin rules - CC denotes your C compiler while CXX denotes your C++ compiler. Likewise flags for the C compiler are denoted CFLAGS and flags for the C++ compiler are denoted CXXFLAGS .

Flags for the preprocessor are denoted CPPFLAGS , and -I path options - which are preprocessor options - are conventionally be passed through CPPFLAGS .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM