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

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 $#
...

Related

How do I use automatic variables in makefile conditionals?

Summarize the problem
I would like to change the compilation for a single source file, like so:
%.exe: %.c
ifeq($#, cannon.exe)
$(CC) $(CFLAGS) -o $(patsubst %.exe,%,$#) $^ $(inc_flags) $(LDLIBS)
else
$(CC) $(CFLAGS) -o $(patsubst %.exe,%,$#) $^
endif
but it doesn't work!
Describe what you’ve tried
I have tried getting bash conditionals involved, but I couldn't figure it out and I shouldn't have to mix bash and make.
Here's the full Makefile:
CC := gcc
CFLAGS := -g -Wall -Wextra
LDLIBS := -lm
inc_dirs := math.h stdio.h
inc_flags := $(addprefix -I,$(inc_dirs))
executable:=cannon.exe
source:=$(executable:%.exe=%.cpp)
.DELETE_ON_ERROR:
all: $(executable)
%.exe: %.c
ifeq($#, cannon.exe)
$(CC) $(CFLAGS) -o $(patsubst %.exe,%,$#) $^ $(inc_flags) $(LDLIBS)
else
$(CC) $(CFLAGS) -o $(patsubst %.exe,%,$#) $^
endif
clean:
rm -f $(executable:%.exe=%)
It turns out that if you want to do a special case for a certain source file, you can just define its recipe explicitly! Make will take explicit over implicit rules. Full working code below.
CC := gcc
CFLAGS := -g -Wall -Wextra
LDLIBS := -lm
inc_dirs := math.h stdio.h
inc_flags := $(addprefix -I,$(inc_dirs))
executable:=cannon.exe
source:=$(executable:%.exe=%.cpp)
# no deps so no objs
.DELETE_ON_ERROR:
all: $(executable)
%.exe: %.c
$(CC) $(CFLAGS) -o $(patsubst %.exe,%,$#) $^
cannon.exe: cannon.c
$(CC) $(CFLAGS) -o $(patsubst %.exe,%,$#) $^ $(inc_flags) $(LDLIBS)
clean:
rm -f $(executable:%.exe=%)
A better / more make-ish solution is to use constructed variable names, like this:
CC := gcc
CFLAGS := -g -Wall -Wextra
LDLIBS := -lm
inc_dirs := math.h stdio.h
cannon_CFLAGS := $(addprefix -I,$(inc_dirs))
executable := cannon.exe
source := $(executable:%.exe=%.cpp)
# no deps so no objs
.DELETE_ON_ERROR:
all: $(executable)
%.exe: %.c
$(CC) $(CFLAGS) $($*_CFLAGS) -o $# $^
clean:
rm -f $(executable:%.exe=%)
Notes:
Your rules should always create the same name as the target in the makefile. It's not right for the target to be named foo.exe but the build command creates a file named foo. If you want to create a file named foo, then the makefile target should be named foo. Basically you should always create the file contained in the make variable $#.
Is it really the case that the directories you have are named math.h and stdio.h? That's.... bizarre. And very likely to cause serious problems. If math.h and stdio.h are files, then you should not add them with -I because -I takes directory names, in which to search file files. It doesn't take filenames.
If you really did create local files named math.h and stdio.h, that's also a very bad idea: those are standard header file names and you shouldn't redeclare them yourself unless you really know what you're doing.
If you didn't create these files and you're just trying to include the standard headers math.h and stdio.h in your file, then you definitely don't need to add any flags to your compile line. Just include them.

Make doesn't recompile after cleaning object files

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.

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 mirror build directory

I need to create Makefile that compiles .c files with a lot of subdirs (sources directory goes in around 5 level depth) and I need to place the object files in the mirrored build directory. So far, I have created this Makefile:
CC := gcc.exe
AS := as.exe
CFLAGS = -DCORE_SW_VERSION='"$(CORE_SW_VERSION)"' -Wall -mA6 -c -fmessage-length=0 -Hsdata0
CFLAGS += -fgnu89-inline -mno-volatile-cache $(INCLUDE) -Hon=each_function_in_own_section -Xcrc -std=c99 -O1
CORE_SW_VERSION:=CORE.07.01.04.01.03.01.R
HAL_SW_VERSION:=16.01.06.01.06.00
MODE_CORE := dev
MODE_HAL := dev
OBJDIR := $(shell pwd)/$(TARGET12) #TARGET12 is a make parameter
INCLUDE := $(shell cat ./$(TARGET12)_include.txt)
SOURCEDIR := ../sources
CSRC := $(shell find $(SOURCEDIR) -name '*.c')
EXCLUDES := $(shell cat ./$(TARGET12)_exclude.txt)
OBJ := $(CSRC:.c=.o)
OBJS := $(patsubst ../%.c,$(OBJDIR)/%.o,$(CSRC))
.PHONY: $(TARGET12)
$(TARGET12): $(OBJS)
$(AR) -r $(CORE_SW_VERSION).a $(OBJS)
$(OBJS): $(CSRC)
mkdir -p $(dir $#)
$(CC) $(CFLAGS) $< -o $(patsubst ../%,$(OBJDIR)/%,$#)
If I define rule for $(OBJS) this way, $< is always the first .c file in $(CSRC).
If I define $(OBJS) this way:
$(OBJS): %.o: %.c
mkdir -p $(dir $#)
$(CP) $< $#
I get error that there is no rule to make target for .c file. But I see that make is looking for .c file in build mirrored directory, and it should look at the source dir. Do you maybe know how this could be arranged?
Thanks you in advance!
The rule $(OBJS): %.o: %.c means something like this: when trying to create a .o file, use this rule if the corresponding .c file exists. For example: when make is looking for a way to create $(OBJDIR)/foo.o, it will look for $(OBJDIR)/foo.c.
In your case this file does not exists, so the rule is ignored.
What you want is rather something like this:
$(OBJS): $(OBJDIR)/%.o: $(SOURCEDIR)/%.c
mkdir -p $(dir $#)
$(CP) $< $#
The first rule for $(OBJS) you tried, states that every object file individually depends on all source files. Surely that's not correct.
Your second attempt is better, although the recipe is weird. Fix that and use VPATH to make make find the sources.

Resources