Makefile always recompiling a file - c++

I am learning how to set up makefiles, and have ran into a problem. To demonstrate this I have created a simple "project" consisting of source files main.m and test.m.
I am trying to setup make to compile these files (only if somethings changed), and store the object files in somewhere else (here build/)
My Makefile:
OBJ = ./build
SOURCES=main.m test.m
OBJECTS=$(addprefix $(OBJ)/,$(SOURCES:.m=.o))
EXECUTABLE=test
all: $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
gcc $(OBJECTS) -o $(EXECUTABLE)
$(OBJECTS): $(OBJ)/%.o: %.m build/
gcc -c $< -o $#
build/:
mkdir build
When I run it for the first time (with only the Makefile and the sources in the current directory) it does what I expect it to do:
gcc -c main.m -o build/main.o
gcc -c test.m -o build/test.o
gcc ./build/main.o ./build/test.o -o test
However if I run make again:
gcc -c main.m -o build/main.o
gcc ./build/main.o ./build/test.o -o test
What have I done wrong? Also noting any other errors in the Makefile is appreciated, as I am trying to learn to create "good" Makefiles.
EDIT:
What I spotted from make -d:
Finished prerequisites of target file `build/main.o'.
Prerequisite `main.m' is older than target `build/main.o'.
Prerequisite `build/' is older than target `build/main.o'.
No need to remake target `build/main.o'.
and
Finished prerequisites of target file `build/test.o'.
Prerequisite `test.m' is older than target `build/test.o'.
Prerequisite `build/' is newer than target `build/test.o'.
Must remake target `build/test.o'.

Your make -d output shows that make thinks your build directory has been updated, and so that file needs to be rebuilt.
I guess that happens because some operation either on your build system's part or by something else in your filesystem is causing some timestamp on that directory to be updated.
You can fix the problem by making build an order-only prerequisite by adding a | to that rule:
$(OBJECTS): $(OBJ)/%.o: %.m | build
I deleted the / too, since it wasn't doing anything.
Since you asked, some other editorial notes:
Add a clean target. Something like:
clean:
rm -rf $(EXECUTABLE) $(OBJ)
You don't need the ./ when you set OBJ. Just OBJ = build is enough.
You don't need the / on build as mentioned above. But that doesn't really matter, since you shouldn't be referring it to it anyway. Repalce build with $(OBJ) wherever you see it.
mkdir will fail if the directory already exists. You probably should prefix that command with a -:
$(OBJ):
-mkdir $(OBJ)
Note that I've done the replacement with $(OBJ) that I mentioned in #3 above.
Auto-generation of dependencies is very helpful. Your project as shown isn't big enough to really need it, but it's easy enough to add, so why not. You'll need to do a couple of things. First, get the appropriate dependency file names:
DEPFILES = $(addprefix $(OBJ)/,$(SOURCES:.m=.d))
Then get the compiler to generate them by adding the -MMD flag:
gcc -MMD -c $< -o $#
Lastly, include them in your makefile if they're available, by adding a line at the end of your makefile:
-include $(DEPFILES)

Related

makefile: how to specify header files

I'm trying to write a makefile for all of my cpp prjects. After searching from the internet, I make a makefile as below:
g++11=g++ -std=c++11 -stdlib=libc++
CPPFILES=$(wildcard *.cpp)
OBJFILES=$(CPPFILES:.cpp=.o)
res.out: $(OBJFILES)
$(g++11) -lncurses -o $# $^ -g
#obj/%.o: %.cpp
%.o: %.cpp
$(g++11) -c -o $# $< -g
clean:
rm *.o *.out
I tried to use this file to compile my cpp projects and it worked well.
However, when I make some change in the header files, it doesn't work anymore because this makefile can't detect the modification in header files.
Is there any easy way to specify header files in the makefile?
Ofc I don't want to specify them one by one.
First of all, you should understand the concept of make.
Make is not only for compiling C++, it's a universal tool where a product (file) is built from other files. When you issue the make, it checks whether the top product should be rebuilt, based on the file change dates of dependencies. If rebuild is needed, first checks all the dependencies whether they should be rebuild... and so on. These bricks are called rules.
This is a rule:
target: dependency1 dependency2 ...
command1 to produce targets
command2
In case of a CPP project:
myapp: myapp.cpp myapp.hpp
g++ myapp.cpp -o myapp
More info: http://www.cs.cmu.edu/~gkesden/412-18/fall01/projects/proj1/make/makeintro.html

Using makefile arguments without foo=

I have a makefile I use to compile a single file. When I need to pass an argument, I use target=targetFile.
The script takes the argument, looks for the file (within the same directory) that has the same value as the argument and compiles it.
I use this for compiling problems from uhunt and uva, which use a single c++ file. So I dont' need multiple makefiles for multiple source files. Single makefile for multiple source files is the reason I made the makefile.
Here's the code I have so far
OBJS = $(target).o
CC = g++
CFLAGS = -Wall -g -std=c++11
INCLUDE = -I./$(target)
#default command to run
all : Main-$(target) clean run
#compile and build
Main-$(target) : $(OBJS)
$(CC) $(CFLAGS) $^ -o $#
%.o : %.cpp
$(CC) -c $(CFLAGS) $<
#remove object and any other garbage files.
clean:
rm -rf -d $(target).o *~ *% *# .#*
#remove the compiled file
clean-all:
$(clean) rm Main-$(target)
#run the compiled file
run:
./Main-$(target)
The command I use to compile is,
make target=sourceFile
Also I don't include the file extension, I have all my source file extensions to be cpp
What I want in the end is:
make sourceFile
Just a side note, for using the command clean and clean-all, I use
make target=sourceFile clean
make target=sourceFile clean-all
I'd prefer if I can use:
make sourceFile clean
make sourceFile clean-all
You may use common Makefile variable MAKECMDGOALS that contains all targets passed to make.
Please try this variant
CC = g++
CFLAGS = -Wall -g
MAKECMDGOALS := $(filter-out clean, $(MAKECMDGOALS))
.PHONY: $(MAKECMDGOALS)
$(MAKECMDGOALS):
$(CC) $(CFLAGS) $#.c -o Main-$#
clean:
rm -f *.o
Here the lines
$(MAKECMDGOALS):
$(CC) $(CFLAGS) $#.c -o Main-$#
will generate separate build targets for each word in MAKECMDGOALS.
Note, we need this Makefile to know that 'clean' is a target for removing stuff, but not to attempt build Main-clean. This why we remove clean from MAKECMDGOALS using filter-out function.
So if we run make a b clean, the build system will generate automatically targets for building Main-a and Main-b and then use already written clean target
Disclaimer -- this is a non-standard use of Make, and will therefore open up all kinds of corner cases, so I don't recommend it. This is better suited for a shell script calling make. That being said... it is an interesting question.
You can't do make xxx clean, and not have it try to build xxx (unless you do some really nasty cludge using recursive make, but I won't go there). You could do something like make clean-xxx though, as follows:
%:Main-%
Main-%:%.cpp
$(CC) $(CFLAGS) $< -o Main-$#
clean-%:
rm Main-$*
Notice that %-clean has a shorter stem, and therefor takes precedence over the % if the make target starts with clean-.

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, 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!
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 -Ipath options
- which are preprocessor options - are conventionally be passed through CPPFLAGS.

Why does GNU make always re-link my project?

I have the following Makefile in a directory full of .cpp and .h files:
CFLAGS=-g -std=c++0x -Wall -pedantic -Wextra -D __STDC_LIMIT_MACROS -D __STDC_FORMAT_MACROS -O0
CXX=g++
LDFLAGS=-lgmp -lmathsat -lz3
all: Foo.o Bar.o
$(CXX) $(CFLAGS) -o myexe Foo.o Bar.o $(LDFLAGS)
depend: .depend
.depend: $(wildcard *.cpp)
rm -f ./.depend
$(CXX) $(CFLAGS) -MM $^ > ./.depend
include .depend
%.o: %.cpp
$(CXX) $(CFLAGS) $(INCLUDE) $< -c
clean:
rm -f *.o myexe
When I hit make, it invariably executes the last step (linking) even when none of the .o files have changed. How can I prevent make from doing that? I'd expect make to output Everything up-to-date or something similar.
I'm on a i686 GNU/Linux machine with GNU Make 3.82 and g++ version 4.8.2.
Make relinks your project because it tries to build all. The rule for all does not create any file named all. Instead it produces myexe. Next time you run make, it will see that there's no all, but there's a rule to build one, so it dutifully executes that rule which happens to link myexe every time you run make.
In order to fix your problem you need to change your makefile to look roughly like this:
all: myexe
echo Build done
myexe: <myexe dependencies go here>
$(CXX) $(CFLAGS) -o myexe $(wildcard *.o) $(LDFLAGS)
Make always tries to build the top rule. For you, this is all. Since your all rule doesn't actually make an all file it will always be run.
Your probably want your all rule to be a myexe rule and, if you want an explicit all rule, have a dependency only rule: all: myexe.
(With GNU Make, you might want to explicitly declare those targets which aren't supposed to generate a real file with a .PHONY rule. e.g. .PHONY: all depend clean.)
make is a rule-based expert system.
You give it a heap of rules and a target (default target is the first one listed), and then it builds a complete dependency tree.
All parts are rebuilt iff they are non-existent resp. older than their dependencies, recursively.
The rule you are stumbling over is this: Because the target all does not create an output file all, make invokes the non-existent-or-outdated rule.
You can correct this by making the target all not do any work but instead just depend on the output file. Marking it .PHONY is also a good idea.

make include directive and dependency generation with -MM

I want a build rule to be triggered by an include directive if the target of the include is out of date or doesn't exist.
Currently the makefile looks like this:
program_NAME := wget++
program_H_SRCS := $(wildcard *.h)
program_CXX_SRCS := $(wildcard *.cpp)
program_CXX_OBJS := ${program_CXX_SRCS:.cpp=.o}
program_OBJS := $(program_CXX_OBJS)
DEPS = make.deps
.PHONY: all clean distclean
all: $(program_NAME) $(DEPS)
$(program_NAME): $(program_OBJS)
$(LINK.cc) $(program_OBJS) -o $(program_NAME)
clean:
#- $(RM) $(program_NAME)
#- $(RM) $(program_OBJS)
#- $(RM) make.deps
distclean: clean
make.deps: $(program_CXX_SRCS) $(program_H_SRCS)
$(CXX) $(CPPFLAGS) -MM $(program_CXX_SRCS) > make.deps
include $(DEPS)
The problem is that it seems like the include directive is executing before the rule to build make.deps which effectively means that make is either getting no dependency list if make.deps doesn't exist or always getting the make.deps from the previous build and not the current one.
For example:
$ make clean
$ make
makefile:32: make.deps: No such file or directory
g++ -MM addrCache.cpp connCache.cpp httpClient.cpp wget++.cpp > make.deps
g++ -c -o addrCache.o addrCache.cpp
g++ -c -o connCache.o connCache.cpp
g++ -c -o httpClient.o httpClient.cpp
g++ -c -o wget++.o wget++.cpp
g++ addrCache.o connCache.o httpClient.o wget++.o -o wget++
Edit
I read the docs for the include directive, and it sounds like if the include target doesn't exist it will continue processing the parent makefile try and build the target, but it's not completely clear to me how this works:
If an included makefile cannot be
found in any of these directories, a
warning message is generated, but it
is not an immediately fatal error;
processing of the makefile containing
the include continues. Once it has
finished reading makefiles, make will
try to remake any that are out of date
or don't exist. See section How
Makefiles Are Remade. Only after it
has tried to find a way to remake a
makefile and failed, will make
diagnose the missing makefile as a
fatal error.
ANSWER
This is a modification of the answer I accepted. The one thing missing was that the dependency files also depend on the sources, and won't get regenerated unless they are added to the deps files which are being included:
%.d: $(program_CXX_SRCS)
# $(CXX) $(CPPFLAGS) -MM $*.cpp | sed -e 's#^\(.*\)\.o:#\1.d \1.o:#' > $#
sed adds the name of the .d file to the beginning of each dependency line like so:
foo.d foo.o: foo.cpp foo.h bar.h baz.h
I got the idea from this amazing paper on the dangers of recursive make:
Recursive Make Considered Harmful
I also add the following to the makefile:
clean_list += ${program_SRCS:.c=.d}
# At the end of the makefile
# Include the list of dependancies generated for each object file
# unless make was called with target clean
ifneq "$(MAKECMDGOALS)" "clean"
-include ${program_SRCS:.c=.d}
endif
You are relying on an implicit rule to compile your .cpp files. You have to redefine it to use the -MM and -MF flags that will create the dependency file.
%.o: %.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $# -MM -MF $#.d
Then, you have to include these dependencies files in the Makefile, using -include that will not error when the dependencies files do not exist yet (on the first time, or after a clean).
program_DEPS := $(program_OBJS:.o=.o.d)
-include $(program_DEPS)
And remember to add the rm command for the dependencies files in the clean rule.
An important point that it took me a while to grasp is that the make.deps from the previous build are good enough. Think about it: for a given object file, the only way the list of dependency files can change is if... one of the old dependency files has been altered. And if that's the case, then the old make.deps will cause that object file to be rebuilt, and if rebuilding the object file also rebuilds make.deps, then everything will be up to date. You don't have to rebuild make.deps before checking to see which objects must be rebuilt.
The include directives work like they do in C and C++ - they are processed before anything else happens, to build the "real" makefile that make then processes. Specifically, they are processed before any rules are fired.