Reputation: 943
I am working on a makefile for a C++ project that needs to support a few configurations, i.e. 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!
Upvotes: 1
Views: 950
Reputation: 61137
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
.
Upvotes: 2