Makefile Automatic Dependency Generation (%.o) - makefile

I want to make a flat layout of *.[cpp,h] files using the automatic dependency management trick staged here: http://locklessinc.com/articles/makefile_tricks/
My work is:
.PHONY: all clean
CXX ?= g++
DEBUG ?= "1"
ifeq ($(DEBUG), "1")
CFLAGS+=-g
endif
BODIES := ExecuteStart GraphNode IdNodeMap IdValuePairCollection IScenarioReader XMLScenarioReader INodeExecute
SRCS := $(addsuffix .cpp, $(BODIES))
OBJECTS := $(addsuffix .o, $(BODIES))
DEPS := $(addsuffix .d, $(SRCS))
dependless = %.o %.a %.d %.h
expand = $($(var)) $(var) $(var).d
depend_test = $(if $(filter $(dependless),$(var)),$(var),$(expand))
depend = $(sort $(foreach var,$(1),$(depend_test)))
default: all
include $(wildcard *.d)
& = $(filter-out %.h %.d,$^)
all: $(OBJECTS)
%.cpp.d: %.cpp
#echo creating $# for $ $#'
clean:
rm $(OBJECTS) $(DEPS)
The problem is that the rule %.o: $(call depend, %.cpp) is not working and hence if I make --warn-undefined-variables it warns about %.cpp. The result being make figures out how to produce *.o files and doesn't use my rule.
Do I have a skipped issue?

I found the horrible miss in the rules:
all: $(DEPS) $(OBJECTS)
That fixed the issue. But it needs explicit "generate dependency" rule added to all.

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?

Pattern target in Makefile not recognized?

I don't understand why the pattern target %.o: %.cpp ist not recognized by the Makefile below. Line 42 should invoke the rule at line 58.
The purpose is to create a Makefile to generate different executables out of the same code.
Further the Makefile shall (in future) take into account to rebuild the code if header-files were changed (dependencies). But this is no question at this point.
.SECONDEXPANSION:
SUFFIXES += .d
MD := mkdir
MD_FLAGS := -p
RM := rm
RM_FLAGS := -rf
EC := echo
SRC_DIR := src
# SRC_FILES - target specific
OBJ_DIR := obj
# OBJ_FILES - target specific
DEP_DIR := dep
# DEP_FILES - target specific
BUILD_DIR := build
CC := clang++
CC_FLAGS := -c -std=c++11 -I $(SRC_DIR) -O3
LD := clang++
# LD_FLAGS - target specific
.PHONY: all
all: first
.PHONY: first
first: LD_FLAGS :=
first: SRC_FILES :=\
$(SRC_DIR)/executables/first.cpp\
$(SRC_DIR)/factory/milk.cpp
first: obj
first: $(OBJ_FILES)
#echo $(OBJ_FILES)
#echo making $#
first: dep
first: lnk
.PHONY: obj
obj:
$(eval OBJ_FILES := $(patsubst $(SRC_DIR)/%.cpp, $(OBJ_DIR)/%.o, $(SRC_FILES)))
.PHONY: dep
dep:
$(eval DEP_FILES := $(patsubst $(SRC_DIR)/%.cpp, $(DEP_DIR)/%.dep, $(SRC_FILES)))
%.o: %.cpp
#$(EC) "Begin compiling "$#
#$(MD) $(MD_FLAGS) $(dir $#)
#$(CC) $(CC_FLAGS) $< -o $#
#$(EC) "Done compiling "$#
.PHONY: lnk
lnk: $(DEP_FILES) $(OBJ_FILES) $(SRC_FILES)
#$(EC) $(SRC_FILES)
#$(EC) $(OBJ_FILES)
#$(EC) $(DEP_FILES)
#$(EC) "Begin linking "$#
#$(MD) $(MD_FLAGS) $(DEP_DIR) $(BUILD_DIR)
#$(LD) -o $(BUILD_DIR)/$# $(OBJ_FILES) $(LD_FLAGS)
#$(EC) "Done linking "$#
.PHONY: clean
clean:
#$(EC) "Begin cleaning"
#$(RM) $(RM_FLAGS) $(DEP_DIR) $(OBJ_DIR) $(BUILD_DIR)
#$(EC) "Done cleaning"
A snippet of a debug output (make -d) is not a big help I guess but for completion...
Updating goal targets....
Considering target file 'all'.
File 'all' does not exist.
Considering target file 'first'.
File 'first' does not exist.
Considering target file 'obj'.
File 'obj' does not exist.
Finished prerequisites of target file 'obj'.
Must remake target 'obj'.
Successfully remade target file 'obj'.
Considering target file 'dep'.
File 'dep' does not exist.
Finished prerequisites of target file 'dep'.
Must remake target 'dep'.
Successfully remade target file 'dep'.
Considering target file 'lnk'.
File 'lnk' does not exist.
Finished prerequisites of target file 'lnk'.
Must remake target 'lnk'.
Update 1
I've updated the code as it now uses MAKECMDGOALS to build several executables (e.g. first,second) from subsets of a biger set.
No it works as expected but the target all is broken. It's clear to me why but I don't have a solution right now.
.SECONDEXPANSION:
SUFFIXES += .d
MD := mkdir
MD_FLAGS := -p
RM := rm
RM_FLAGS := -rf
EC := echo
SRC_DIR := src
ifeq ($(filter first, $(MAKECMDGOALS)), first)
SRC_FILES :=\
$(SRC_DIR)/executables/first.cpp\
$(SRC_DIR)/factory/milk.cpp
endif
ifeq ($(filter second, $(MAKECMDGOALS)), second)
SRC_FILES :=\
$(SRC_DIR)/executables/second.cpp\
$(SRC_DIR)/factory/milk.cpp\
$(SRC_DIR)/factory/cream.cpp
endif
OBJ_DIR := obj
OBJ_FILES := $(patsubst $(SRC_DIR)/%.cpp, $(OBJ_DIR)/%.o, $(SRC_FILES))
DEP_DIR := dep
DEP_FILES := $(patsubst $(SRC_DIR)/%.cpp, $(DEP_DIR)/%.dep, $(SRC_FILES))
BUILD_DIR := build
CC := clang++
CC_FLAGS := -c -std=c++11 -I $(SRC_DIR) -O3
LD := clang++
ifeq ($(filter first, $(MAKECMDGOALS)), first)
LD_FLAGS :=
endif
ifeq ($(filter second, $(MAKECMDGOALS)), second)
LD_FLAGS :=
endif
.PHONY: all
all: first second
.PHONY: first
first: $(OBJ_FILES) lnk
.PHONY: second
second: $(OBJ_FILES) lnk
%.o: %.cpp
#$(EC) "Begin compiling "$#
#$(MD) $(MD_FLAGS) $(dir $#)
#$(CC) $(CC_FLAGS) $< -o $#
#$(EC) "Done compiling "$#
.PHONY: lnk
lnk: $(OBJ_FILES)
#$(EC) "Begin linking "$#
#$(MD) $(MD_FLAGS) $(DEP_DIR) $(BUILD_DIR)
#$(LD) -o $(BUILD_DIR)/$# $(OBJ_FILES) $(LD_FLAGS)
#$(EC) "Done linking "$#
.PHONY: clean
clean:
#$(EC) "Begin cleaning"
#$(RM) $(RM_FLAGS) $(DEP_DIR) $(OBJ_DIR) $(BUILD_DIR)
#$(EC) "Done cleaning"
Update 2
I had to change the targets first and second, a copy-paste error. Here's the working example:
MD := mkdir
MD_FLAGS := -p
RM := rm
RM_FLAGS := -rf
EC := echo
SRC_DIR := src
ifeq ($(filter first, $(MAKECMDGOALS)), first)
SRC_FILES :=\
$(SRC_DIR)/executables/first.cpp\
$(SRC_DIR)/factories/milk.cpp
endif
ifeq ($(filter second, $(MAKECMDGOALS)), second)
SRC_FILES :=\
$(SRC_DIR)/executables/second.cpp\
$(SRC_DIR)/factories/milk.cpp\
$(SRC_DIR)/factories/cream.cpp
endif
OBJ_DIR := obj
OBJ_FILES := $(patsubst $(SRC_DIR)/%.cpp, $(OBJ_DIR)/%.o, $(SRC_FILES))
DEP_DIR := dep
DEP_FILES := $(patsubst $(SRC_DIR)/%.cpp, $(DEP_DIR)/%.dep, $(SRC_FILES))
BUILD_DIR := build
CC := clang++
CC_FLAGS := -c -std=c++11 -I $(SRC_DIR) -O3
LD := clang++
ifeq ($(filter first, $(MAKECMDGOALS)), first)
LD_FLAGS :=
LD_FILE := first
endif
ifeq ($(filter second, $(MAKECMDGOALS)), second)
LD_FLAGS :=
LD_FILE := second
endif
.PHONY: all
all:
#$(MAKE) $(MAKEFLAGS) first
#$(MAKE) $(MAKEFLAGS) second
.PHONY: first
first: $(OBJ_FILES) lnk
.PHONY: second
second: $(OBJ_FILES) lnk
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
#$(EC) "Begin compiling "$#
#$(MD) $(MD_FLAGS) $(dir $#)
#$(CC) $(CC_FLAGS) $< -o $#
#$(EC) "Done compiling "$#
.PHONY: lnk
lnk: $(OBJ_FILES)
#$(EC) "Begin linking "$(LD_FILE)
#$(MD) $(MD_FLAGS) $(DEP_DIR) $(BUILD_DIR)
#$(LD) -o $(BUILD_DIR)/$(LD_FILE) $(OBJ_FILES) $(LD_FLAGS)
#$(EC) "Done linking "$(LD_FILE)
.PHONY: clean
clean:
#$(EC) "Begin cleaning"
#$(RM) $(RM_FLAGS) $(DEP_DIR) $(OBJ_DIR) $(BUILD_DIR)
#$(EC) "Done cleaning"
You have to understand more clearly make's rules for when variables are expanded. See the GNU make manual section How Make Reads a Makefile for full details.
There you will discover that variables and functions that appear in the target or prerequisites section of a rule definition are expanded immediately as the makefile is parsed. Expansion of variables and functions which appear inside a rule's recipe are deferred until that recipe is invoked.
So let's look at the interesting parts of your makefile:
all: first
first: obj
first: $(OBJ_FILES)
#echo $(OBJ_FILES)
#echo making $#
obj:
$(eval OBJ_FILES := $(patsubst $(SRC_DIR)/%.cpp, $(OBJ_DIR)/%.o, $(SRC_FILES)))
What happens here? Make reads the first line and knows that first is a prerequisite of the default target (because it's the first target in the makefile) all. Then it sees that first depends on the target obj. Then it sees that first depends on the value of the variable $(OBJ_FILES), but at this point OBJ_FILES is not set so it expands to the empty string and doesn't actually depend on any object files.
Now when make gets through parsing things and wants to run the build, it sees the first target is all and that depends on first, which depends on obj, which doesn't depend on anything so it runs the recipe to build the obj target. This uses eval to set the make variable OBJ_FILES so now that has a value, but it's too late to help the prerequisites list of the first target, which has already been computed. So now make runs the recipe for first which prints the value of OBJ_FILES.
You have various other issues here, such as rules (like lnk) which build targets that are not $#.
But, basically you need to reconsider your approach of setting make variables inside recipes. That is useful only in rare/obscure situations. It's not clear to me why you are doing this in a recipe with eval, instead of just assigning OBJ_FILES directly, so I can't advise you specifically how to rewrite your makefile.
If you want to see the set of rules that make parsed for you, you can run make with the -p flag and it will print out the rules database it's using to build your project.

In creating a makefile with subdirectories in windows, % wildcard stops working

This is in reference to the second response here:
How to generate a Makefile with source in sub-directories using just one makefile
The solution works great for me except for when the make rules are called. They never seem to make any once make-goal is called since the files don't exist in the build directory yet. I tested this by creating empty files in the build directory (just anyting.o) and the make rule is then found
my conclusion is that the % wildcard character is only looking for what is in the directory, and can't find the file so it doesnt make a build rule for it, and thus fails to continue. There are two possible solutions:
1) Find a way to make dummy object files that are overwritten when the compiler actually starts
2) Make make "realize" that the wild card is for anything put into the make-goal function, not what is already in the directory
any pointers?
As far as I know, I am the first one to have this issue
\
MODULES := calibration calibration/settings camera/nikon camera ommon
SRC_DIR := $(addprefix src/, $(MODULES)) src
SDK_INCLUDES := include $(addprefix include/, $(MODULES))
BUILD_DIR := build $(addprefix build/, $(MODULES))
SRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.cpp))
OBJ := $(patsubst src/%.cpp,build/%.o, $(SRC))
# OpenCV directories, change according to your own installation
CV_INCLUDE_DIR = C:\Users\a0225122\Downloads\opencv\build\include
CV_LIB_DIR = C:\Users\a0225122\Downloads\opencv\bin\lib
CV_LIBS = -llibopencv_core249 \
-llibopencv_highgui249 \
-llibopencv_imgproc249 \
-llibopencv_features2d249 \
-llibopencv_calib3d249
CV_FLAGS = -I$(CV_INCLUDE_DIR) -L$(CV_LIB_DIR) $(CV_LIBS)
HID_API_INCLUDE_DIR := 3rd_party/hidapi-master/hidapi/hid.h
# Compiler instructions
CXXFLAGS = -std=c++11 -Wall -I $(SDK_INCLUDE_DIR) -I $(CV_INCLUDE_DIR) -I $(HID_API_INCLUDE_DIR) -L $(CV_LIB_DIR) $(CV_LIBS) -L $(FLYCAP_LIB_DIR) $(FLYCAP_LIBS)
# Clean up instructions
ifdef SystemRoot #This is windows
CXX = mingw32-g++
RM = del /Q
FixPath = $(subst /,\,$1)
BUILD_DIR := $(call FixPath, $(BUILD_DIR))
SRC_DIR := $(call FixPath, $(SRC_DIR))
SDK_INCLUDES := $(call FixPath, $(SDK_INCLUDES))
SRC := $(call FixPath, $(SRC))
OBJ := $(call FixPath, $(OBJ))
CXXFLAGS := $(call FixPath, $(CV_FLAGS))
define make-goal
$1\%.o: %.cpp
$(CXX) $(CXXFLAGS) -c $$< -o $$#
endef
else #more ifeqs can be added for more OS's but this should be fine
CXX = g++
RM = rm -f
define make-goal
$(1)/%.o: %.cpp
$(CXX) $(CXXFLAGS) -c $$< -o $$#
endef
endif
vpath %.cpp $(SRC_DIR)
SDK_LIBS = lib_core.a
default: SDK.exe
.PHONY: clean
clean:
$(RM) build *.a
#executable generation
SDK.exe: $(SDK_LIBS)
$(CXX) $(CXXFLAGS) $^ -o $#
lib_core.a: checkdirs $(OBJ)
ar rcs lib_core.a $(OBJ)
checkdirs: $(BUILD_DIR)
$(BUILD_DIR):
mkdir $#
#$(OBJ): $(SRC)
# $(CXX) $(CXXFLAGS) -c $^ -o $#
$(foreach bdir,$(BUILD_DIR),$(eval $(call make-goal,$(bdir))))
Your first problem is that you cannot use backslashes in GNU make rules, except in recipes (make just sends the recipe to the shell, it doesn't interpret the recipe except for $). All GNU make targets, prerequisites, etc. must use forward slashes, all the time, even on Windows.
Almost all Windows applications will accept forward-slashes as directory separators properly. For the few that don't, you can use your function FixPath, but you must use it inside the recipe, not in the target or prerequisite lists.
Once you've resolved that issue if you still have problems, post what you have and we'll look.

How to have a sometimes empty dependency in makefiles?

I have the following rule:
EXECS = $(sort $(patsubst %.cpp,%$(EXESUFFIX), $(patsubst %.c,%$(EXESUFFIX), $(filter-out $(IGNORESRCS), $(EXECSRCS)))))
SRCS = $(sort $(filter-out $(EXECSRCS), $(filter-out $(IGNORESRCS), $(wildcard *.c) $(wildcard *.cpp) $(foreach DIR,$(SUBDIRS),$(wildcard $(DIR)/*.cpp) $(wildcard $(DIR)/*.c) ) )))
#OBJS = $(addprefix $(OBJDIR), $(patsubst %.cpp,%$(OBJSUFFIX), $(patsubst %.c,%$(OBJSUFFIX), $(SRCS))))
OBJS = $(patsubst %.cpp,%$(OBJSUFFIX), $(patsubst %.c,%$(OBJSUFFIX), $(SRCS)))
RESOURCE_SRCS= $(sort $(filter-out $(IGNORESRCS), $(wildcard *.rc) $(foreach DIR,$(SUBDIRS),$(wildcard $(DIR)/*.rc) ) ))
RESOURCES = $(patsubst %.rc,%$(OBJSUFFIX), $(RESOURCE_SRCS))
%$(EXESUFFIX) : %.cpp $(LIBS) $(RESOURCES)
$(CXX) $(DEFINES) $(CFLAGS) $(INCLUDES) $(LIBPATH) -o $(BINDIR)/$* $< $(RESOURCES) $(LIBINCLUDES)
The problem is that $(RESOURCES) doesnt exist for all platforms. The %$(EXESUFFIX) : %.cpp rule doesnt run, instead it tries to run g++ exec.cpp -o exec which as far as I can tell isnt a rule that I declared anywhere.
How do I get the rule to still build despite the fact that it is empty (and build the resources if it is not empty)?
If the variable is empty it has no effect on the rule. It should just work as written. What is the actual error you're seeing?
ETA:
Your question is very unclear in what, exactly, you mean by $(RESOURCES) doesn't exist. My answer was assuming you meant that the variable was empty. But given your comment below about how the makefile behaves, I now suspect what you mean is that the variable is still set to a list of files, but that those files are not present.
Because they're not there, and make doesn't know how to build them, make decides that this pattern rule cannot be used at all and it chooses a different rule.
If you want these files to only have any impact if they exist, then you can use the $(wildcard ...) function to expand only to those files that exist:
%$(EXESUFFIX) : %.cpp $(LIBS) $(wildcard $(RESOURCES))
$(CXX) ...
One critical point here: the contents of $(RESOURCES) MUST be source files. They cannot be derived files (files that are supposed to be created by make). If they are derived, the situation is far more complex.

Resources