Make doesn't recompile after cleaning object files - makefile

I have the following makefile:
compiler := g++
flags := -Wall -Wextra -Wpedantic -Werror -O2 -march=native
libs := sqlite3
build_dir := build
debug_dir := debug
source_dir := src
object_dir := obj
include_dir := include
objects := main.o politician.o data_base.o exceptions.o input.o
# Prepend object_dir/ to every object
objects := $(patsubst %, $(object_dir)/%, $(objects))
dependencies := data_base.hpp exceptions.hpp politician.hpp input.hpp CLI11.hpp
# Prepend include_dir/ to every dependency
dependencies := $(patsubst %, $(include_dir)/%, $(dependencies))
executable := politician
# Don't remove object files when finished
.SECONDARY: $(objects)
.PHONY: all
all: $(build_dir)/$(executable) | $(build_dir)
.PHONY: debug
debug: flags += -g
debug: $(debug_dir)/$(executable) | $(debug_dir)/
%/$(executable): $(objects)
$(compiler) $(flags) -l $(libs) $^ -o $#
$(object_dir)/%.o: $(source_dir)/%.cpp $(dependencies) | $(object_dir)/
$(compiler) $(flags) -I $(include_dir) -c $< -o $#
%/:
mkdir -p $#
.PHONY: clean
clean:
rm -f $(objects)
.PHONY: clean-all
clean-all:
rm -f $(objects) $(build_dir)/$(executable) $(debug_dir)/$(executable)
It's expected that, after running make clean, make all would recompile everything (because the executable depends on the objects and they are not present anymore), but it's not what's happening: instead I get make: Nothing to be done for 'all'.
What's causing this behavior?

This happens because you are using a chain of pattern rules.
Consider a simple example:
all: build/politician
build/politician: main.o
whatever...
main.o: src/main.cpp
whatever...
If you run make, it will build main.o, then build/politician. If you then delete main.o and again run make, again it will build main.o and build/politician.
Now change two of the rules into pattern rules:
all: build/politician
%/politician: main.o
whatever...
%.o: src/%.cpp
whatever...
Now the first time you run make, it will once again build main.o and then build/politician. But then when you delete main.o and again run make, it will report "Nothing to be done for 'all'" and do nothing. This is because main.o is now an intermediate file, and according to the manual:
If an ordinary file b does not exist, and make considers a target that depends on b, it invariably creates b and then updates the target from b. But if b is an intermediate file, then make can leave well enough alone. It won’t bother updating b, or the ultimate target, unless some prerequisite of b is newer than that target or there is some other reason to update that target.

Related

How can I modify my Makefile so that I build two different executables

I have a Makefile that works correctly, but now I want to modify it so that I can build two different executables (i.e. client.exe, server.exe). In my directory, I have a client.cpp and a server.cpp, each of which has a main function. I know I can't build an executable with more than one main function. Ultimately, I want to be able to build an executable (client.exe or server.exe) using 'make client', 'make server', or something to that effect.
I have seen similar questions on this website, but all of the solutions I have seen assume that the number of source files will not change. Take for example this solution: Makefile to compile multiple C programs? Or this question: How can I configure my makefile for debug and release builds?
I do not want to have to update my Makefile every time I add a new source file.
How can I modify my Makefile so that I build two different executables?
SRC_DIR := src
OBJ_DIR := obj
BIN_DIR := bin
EXE := $(BIN_DIR)/client.exe
SRC := $(wildcard $(SRC_DIR)/*.cpp)
OBJ := $(subst $(SRC_DIR),$(OBJ_DIR),$(SRC:.cpp=.o))
DEP := $(OBJ:.o=.d)
.PHONY: clean
all: $(EXE)
CXX := g++
CPPFLAGS := -I$(PWD) -MMD -MP
CXXFLAGS := -std=c++17
LDFLAGS := -L /usr/lib/x86_64-linux-gnu
CFLAGS := -Wall
$(EXE): $(OBJ) | $(BIN_DIR)
$(CXX) $(LDFLAGS) $^ -o $#
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp | $(OBJ_DIR)
$(CXX) $(CPPFLAGS) $(CFLAGS) $(CXXFLAGS) -c $< -o $#
$(BIN_DIR) $(OBJ_DIR):
mkdir -p $#
clean:
#$(RM) -rv $(BIN_DIR) $(OBJ_DIR)
-include $(DEP)
I have tried to exclude either the client.cpp or server.cpp file depending on which command I use (e.g. 'make client' or 'make server'). But I reached a dead end since I don't know how to make a rule that excludes one file.
SRC := $(filter-out $(SRC_DIR)/client.cpp, $(wildcard $(SRC_DIR)/*.cpp))
SRC := $(filter-out $(SRC_DIR)/server.cpp, $(wildcard $(SRC_DIR)/*.cpp))
Simply build two different lists of object files for your two executables:
...
EXE := $(patsubst %,$(BIN_DIR)/%.exe,client server)
...
CLIENT_OBJ := $(filter-out $(OBJ_DIR)/server.o,$(OBJ))
SERVER_OBJ := $(filter-out $(OBJ_DIR)/client.o,$(OBJ))
.PHONY: all client server
all: $(EXE)
client: $(BIN_DIR)/client.exe
server: $(BIN_DIR)/server.exe
$(BIN_DIR)/client.exe: $(CLIENT_OBJ)
$(BIN_DIR)/server.exe: $(SERVER_OBJ)
$(EXE): | $(BIN_DIR)
$(CXX) $(LDFLAGS) $^ -o $#
...

Makefile reference dependencies with patsubst or wildcard?

Following this question and my answer and its comments I have a doubt.
What is the proper way to reference dependencies in a Makefile?
Let me give an example considering this file:
CXX = g++
CXXFLAGS = -stdlib=libc++ -std=c++17
WARNING := -Wall -Wextra
PROJDIR := .
SOURCEDIR := $(PROJDIR)/
SOURCES := $(wildcard $(SOURCEDIR)/*.cpp)
OBJDIR := $(PROJDIR)/
OBJECTS := $(patsubst $(SOURCEDIR)/%.cpp,$(OBJDIR)/%.o,$(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.cpp,$(OBJDIR)/%.d,$(SOURCES))
# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean
all: main
clean:
$(RM) $(OBJECTS) $(DEPENDS) main
clean:
$(RM) $(OBJECTS) $(DEPENDS) parking
# Linking the executable from the object files
main: $(OBJECTS)
$(CXX) $(WARNING) $(CXXFLAGS) $^ -o $#
#include your dependencies
-include $(DEPENDS)
#create OBJDIR if not existin (you should not need this)
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: $(SOURCEDIR)/%.cpp Makefile | $(OBJDIR)
$(CXX) $(WARNING) $(CXXFLAGS) -MMD -MP -c $< -o $#
I can do DEPENDS := $(patsubst $(SOURCEDIR)/%.cpp,$(OBJDIR)/%.d,$(SOURCES)) but also DEPENDS := $(wildcard $(OBJDIR)/*.d): can't I?
If I delete a source file before running make clean the correspondent dependency file remains. In the second case it will be removed with the next make clean while in the first it will not. However if I do not run make clean dependencies not related to the sources might be included.
What is the best way to reference dependencies in a Makefile? Should I use two variables, one to run clean and the other for include?

Falty Makefile causes undefined reference and multiple definition errors

I'm on my path to study the wonderful world of Makefiles and this was my first attempt on my own makefile. However I have hit my small brains at a wall with errors and I can not figure the cause, I only know the issue is in the Makefile, I am doing something wrong, because when I compile my "project" manually, it compiles.
cxx := g++
dirs := obj bld_win32 bld_linux
cpp := $(wildcard src/*.cpp)
obj := $(addprefix obj/,$(notdir $(cpp:.cpp=.o)))
ifeq ($(OS), Windows_NT)
target := bld_win32/engine.exe
flags := -mwindows -lopengl32 -openal32 -lgdi32
else
target := bld_linux/engine
flags := -lX11 -lGL -lopenal -lalut
endif
all: precheck $(target)
precheck:
mkdir -p $(dirs)
$(target): $(obj)
$(cxx) -std=c++11 -Wall -o $# $^ $(flags)
obj/%.o: $(cpp)
$(cxx) -c -o $# $<
Your pattern rule is wrong, as you would have noticed if you'd tried to build object files one by one using this makefile. This rule:
obj/%.o: $(cpp)
$(cxx) -c -o $# $<
lists all source files as prerequisites of every object file, and when you try to build any object file, it compiles only the first source file in the list (src/aardvark.cpp, or whatever), so that all of your object files are the same, even though they have different names.
Change it to this:
obj/%.o: src/%.cpp
$(cxx) -c -o $# $<

Makefile that rebuilds all if compiled with dif flags

So I am having a little bit of a tough time trying to figure out how to make my Makefile so that when I do make and it compiles a release version then later on do a make debug it compiles a debug version with the new -DDEBUG and -g set on gcc if the files have not been updated.
For example:
main.cpp is edited
run make
compiles main.cpp
run make debug
main.cpp is not recompiled because there were no changes even though the flags for compilation differ
Note I don't want to have to do a clean each time either because I dont want to have to recompile files if I do 2 makes in a row so setting clean as a dependency is not going to be a valid answer here
You may like to compile object files into a different directory depending on the build mode, e.g.:
# default mode, override with `make BUILD=release`
BUILD := debug
obj_dir := ${BUILD}
CFLAGS.debug := -g -O0
CFLAGS.release := -g -O3 -march=native -DNDEBUG
all : ${obj_dir}/test
# Example executable
${obj_dir}/test : ${obj_dir}/test.o
test.c :
echo "int main() { return 0; }" > $#
# Generic rules
${obj_dir} :
mkdir $#
${obj_dir}/%.o : %.c Makefile | ${obj_dir} # Also recompile when Makefile changes.
${CC} -c -o $# ${CPPFLAGS} ${CFLAGS} ${CFLAGS.${BUILD}} -MD -MP $<
${obj_dir}/% : Makefile | ${obj_dir} # Also re-link when Makefile changes.
${CC} -o $# ${LDFLAGS} $(filter-out Makefile,$^) ${LDLIBS}
clean :
rm -rf ${obj_dir}
-include $(wildcard ${obj_dir}/*.d)
${obj_dir}/*.d : ;
.PHONY: all clean
(Bonus feature: automatic dependency generation).
Usage:
[max#localhost:~/tmp] $ make
mkdir debug
echo "int main() { return 0; }" > test.c
cc -c -o debug/test.o -g -O0 -MD -MP test.c
cc -o debug/test debug/test.o
[max#localhost:~/tmp] $ make
make: Nothing to be done for 'all'.
[max#localhost:~/tmp] $ make BUILD=release
mkdir release
cc -c -o release/test.o -g -O3 -march=native -DNDEBUG -MD -MP test.c
cc -o release/test release/test.o
[max#localhost:~/tmp] $ make BUILD=release
make: Nothing to be done for 'all'.
First of all, you should not run make debug - that would mean, you want to build a different target (debug). But you don't, you want to build the same target, just with different options. That's what you do, you run a different option, a variable value
>make DEBUG=Y
When you run
>make
you also pass that variable really, just with the empty string as value.
Now, in order for this to work as you want in the Makefile, you would want to make it as if DEBUG was a prerequisite file, with recipes like this:
foobar.o: foobar.c DEBUG
gcc $(if $(DEBUG), -DDEBUG -g) -c $< -o $#
Of course, normally this won't work, because DEBUG is a variable, not a file. So you need a hack, that I call "dependable variables". It is basically a way to declare a variable to behave like a file. I describe this technique in one of my other answers:
How do I add a debug option to Makefile
I once did something like this, it looked like that (boiled down to the minimum):
EXE := a.out
SRC := $(wildcard *.c)
ifneq ($(MAKECMDGOALS),debug)
OBJ := $(SRC:.c=.o)
else
OBJ := $(SRC:.c=-d.o)
endif
.PHONY: all debug
all: $(EXE)
debug: CFLAGS += -g -DDEBUG
debug: $(EXE)
$(EXE): $(OBJ)
$(CC) $(LDFLAGS) $^ $(LDLIBS) -o $#
%.o %-d.o: %.c
$(CC) $(CPPFLAGS) $(CFLAGS) -o $# -c $<
The trick is to use two separate list of object files, and select one depending of the target.

Make multiple targets in 'all'

i'm trying to build a debug and release version of a library with a Makefile and copy those libraries to the relevant build directories, e.g.
.PHONY: all clean distclean
all: $(program_NAME_DEBUG)
$(CP) $(program_NAME_DEBUG) $(BUILD_DIR)/debug/$(program_NAME_DEBUG)
$(RM) $(program_NAME_DEBUG)
$(RM) $(program_OBJS)
$(program_NAME_RELEASE)
$(CP) $(program_NAME_RELEASE) $(BUILD_DIR)/release/$(program_NAME_RELEASE)
$(RM) $(program_NAME_RELEASE)
$(RM) $(program_OBJS)
$(program_NAME_DEBUG): $(program_OBJS)
$(LINK_DEBUG.c) -shared -Wl,-soname,$(program_NAME_DEBUG) $(program_OBJS) -o $(program_NAME_DEBUG)
$(program_NAME_RELEASE): $(program_OBJS)
$(LINK_RELEASE.c) -shared -Wl,-soname,$(program_NAME_RELEASE) $(program_OBJS) -o $(program_NAME_RELEASE)
The 1st target in all (program_NAME_DEBUG) compiles OK but the 2nd, (program_NAME_RELEASE) produces the following error:
libGlam_rel.so
make: libGlam_rel.so: Command not found
make: *** [all] Error 127
libGlam_rel.so is the value of program_NAME_RELEASE
It doesn't seem to be recognising the 2nd target as it does the 1st?
EDIT
finally got this working.
one issue was having src files in multiple dirs, used VPATH to sort this, e.g.
# specify dirs other then current dir to search for src files
VPATH = ../../pulse_IO/src ../../../g2/src
Added in additional library targets into the platform conditional stuff, e.g.
# Platform specific conditional compilation
UNAME := $(shell uname)
TARGET := Glam
ifeq ($(UNAME), Linux)
# LINUX version
program_NAME := lib$(TARGET).so
program_DEBUG_NAME := lib$(TARGET)_dbg.so
program_RELEASE_NAME := lib$(TARGET)_rel.so
BUILD_DIR = ../build/linux
endif
ifeq ($(UNAME), MINGW32_NT-6.1)
# WINDOWS version
program_NAME := lib$(TARGET).dll
program_DEBUG_NAME := lib$(TARGET)_dbg.dll
program_RELEASE_NAME := lib$(TARGET)_rel.dll
BUILD_DIR = ../build/windows
endif
added the new debug and release object files:
DEBUG_OBJS := $(addprefix $(BUILD_DIR)/debug/,${program_OBJS})
RELEASE_OBJS := $(addprefix $(BUILD_DIR)/release/,${program_OBJS})
set my debug and release CFLAGS:
DEBUG_CFLAGS := -fPIC -g -Wall -DDEBUG=1
RELEASE_CFLAGS := -fPIC -O2 -Wall -DDEBUG=0
collated all the debug and release compiler options:
DEBUG_LINK.c := $(CC) $(DEBUG_CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
RELEASE_LINK.c := $(CC) $(RELEASE_CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)
added my new rules to the 'all' target:
.PHONY: all clean
all: $(program_DEBUG_NAME) $(program_RELEASE_NAME)
the rule set looks like this (inc. a replacement for the implicit object file generation):
$(program_DEBUG_NAME): $(DEBUG_OBJS)
$(DEBUG_LINK.c) -shared -Wl,-soname,$# $^ -o $(BUILD_DIR)/debug/$#
$(program_RELEASE_NAME): $(RELEASE_OBJS)
$(RELEASE_LINK.c) -shared -Wl,-soname,$# $^ -o $(BUILD_DIR)/release/$#
# rule to build object files (replaces implicit rule)
$(BUILD_DIR)/debug/%.o: %.c
$(DEBUG_LINK.c) $< -c -o $#
$(BUILD_DIR)/release/%.o: %.c
$(RELEASE_LINK.c) $< -c -o $#
and to finish off I modified clean to deal with all the new files:
clean:
#- $(RM) $(BUILD_DIR)/debug/$(program_DEBUG_NAME)
#- $(RM) $(DEBUG_OBJS)
#- $(RM) $(BUILD_DIR)/release/$(program_RELEASE_NAME)
#- $(RM) $(RELEASE_OBJS)
This works allowing me to produce debug and release versions of my library across linux and windows platforms with a single Makefile, e.g. $ make -k
First things first. You seem to want different versions of the object files for the two libraries, but there is nothing in this makefile that will provide that.
There are several ways to do it. The cleanest is probably to have two directories:
debug_objs/
ang.o
naur.o
gul.o
release_objs/
ang.o
naur.o
gul.o
The second-cleanest is to have different file names:
ang_debug.o
naur_debug.o
gul_debug.o
ang_rel.o
naur_rel.o
gul_rel.o
Either way, you can write rules for RELEASE_OBJS and DEBUG_OBJS (we can help with that, if need be).
Now look at the library rules:
$(program_NAME_DEBUG): $(DEBUG_OBJS)
$(LINK_DEBUG.c) -shared -Wl,-soname,$(program_NAME_DEBUG) $(DEBUG_OBJS) -o $(program_NAME_DEBUG)
$(program_NAME_RELEASE): $(RELEASE_OBJS)
$(LINK_RELEASE.c) -shared -Wl,-soname,$(program_NAME_RELEASE) $(RELEASE_OBJS) -o $(program_NAME_RELEASE)
We can use Automatic Variables to make them more concise:
$(program_NAME_DEBUG): $(DEBUG_OBJS)
$(LINK_DEBUG.c) -shared -Wl,-soname,$# $^ -o $#
$(program_NAME_RELEASE): $(RELEASE_OBJS)
$(LINK_RELEASE.c) -shared -Wl,-soname,$# $^ -o $#
(We could go a little farther, but let's not push it.)
Now for all. We move $(program_NAME_RELEASE) into the prerequisite list where it belongs:
all: $(program_NAME_DEBUG) $(program_NAME_RELEASE)
$(CP) $(program_NAME_DEBUG) $(BUILD_DIR)/debug/$(program_NAME_DEBUG)
$(RM) $(program_NAME_DEBUG)
$(RM) $(DEBUG_OBJS)
$(CP) $(program_NAME_RELEASE) $(BUILD_DIR)/release/$(program_NAME_RELEASE)
$(RM) $(program_NAME_RELEASE)
$(RM) $(RELEASE_OBJS)
But there's no reason to remove the object files, since they can't collide, and Make will delete them anyway if they're intermediate files. And there's no need to $(CP) and then $(RM) when we can just mv. And there's no need to mv; if that's where the libraries belong, we can build them there in the first place:
all: $(program_NAME_DEBUG) $(program_NAME_RELEASE)
$(program_NAME_DEBUG): $(DEBUG_OBJS)
$(LINK_DEBUG.c) -shared -Wl,-soname,$# $^ -o $(BUILD_DIR)/debug/$#
$(program_NAME_RELEASE): $(RELEASE_OBJS)
$(LINK_RELEASE.c) -shared -Wl,-soname,$# $^ -o $(BUILD_DIR)/release/$#
EDIT:
To build the object files (I'll guess that you're using C):
OBJS:= ang.o naur.o gul.o
DEBUG_OBJS := $(addprefix debug_objs/,$(OBJS))
RELEASE_OBJS := $(addprefix release_objs/,$(OBJS))
debug_objs/%.o: $(SOURCE_DIR)/%.c
$(CC) $(DEBUG_FLAGS) $< -o $#
release_objs/%.o: $(SOURCE_DIR)/%.c
$(CC) $(RELEASE_FLAGS) $< -o $#
(Just make sure that those directories exist-- you can automate that too, but you're making enough changes for one day.)
This change should do it:
all: $(program_NAME_DEBUG) $(program_NAME_RELEASE)
Otherwise, make all fails to make $(program_NAME_RELEASE), which is what the error message is telling you.

Resources