# Makefile that compiles to two separate executables

I'm working on a project that will have both a server and a client, using Boost's ASIO library for networking. I'm not really comfortable working with Makefiles, but, with some help from Chase Lambert's https://makefiletutorial.com/#makefile-cookbook and other things I found online I got the following Makefile:

BUILD_DIR := ./build
INC_DIRS := ./include
SRC_DIRS := ./src

SERVER_TARGET_EXEC := server
CLIENT_TARGET_EXEC := client

TARGETS := $(BUILD_DIR)/$(SERVER_TARGET_EXEC) $(BUILD_DIR)/$(CLIENT_TARGET_EXEC)

# Find all the C and C++ files we want to compile
# For SRCS we exclude files inside the src/server and src/client directories
SRCS := $(shell find$(SRC_DIRS) $$-name "*.cpp" -or -name "*.c"$$ ! $$-path '*/server/*' -or -path '*/client/*'$$)

SERVER_SRCS := $(shell find$(SRC_DIRS)/server -name *.cpp -or -name *.c)
CLIENT_SRCS := $(shell find$(SRC_DIRS)/client -name *.cpp -or -name *.c)

# String substitution for every C/C++ file.
# As an example, hello.cpp turns into ./build/hello.cpp.o
OBJS := $(SRCS:%=$(BUILD_DIR)/%.o)

SERVER_OBJS := $(SERVER_SRCS:%=$(BUILD_DIR)/%.o)
CLIENT_OBJS := $(CLIENT_SRCS:%=$(BUILD_DIR)/%.o)

ALL_OBJS := $(SUDOKU_OBJS)$(SERVER_OBJS) $(CLIENT_OBJS) # String substitution (suffix version without %). # As an example, ./build/hello.cpp.o turns into ./build/hello.cpp.d DEPS :=$(ALL_OBJS:.o=.d)

# Every folder in ./src will need to be passed to GCC so that it can find header files
INC_DIRS += $(shell find$(SRC_DIRS) -type d ! $$-path '*/server' -or -path '*/client'$$)
# Add a prefix to INC_DIRS. So moduleA would become -ImoduleA. GCC understands this -I flag
INC_FLAGS := $(addprefix -I,$(INC_DIRS))

# The -MMD and -MP flags together generate Makefiles for us!
# These files will have .d instead of .o as the ouput
CPPFLAGS := $(INC_FLAGS) -MMD -MP -g CPPFLAGS += -g CPPFLAGS += -Wall -Wextra CPPFLAGS += -Wpedantic -Warray-bounds -Weffc++ CPPFLAGS += -Werror # For Boost ASIO we need to link against Boost Thread and Boost System LDFLAGS := -pthread LDFLAGS += -lboost_thread -lboost_system all:$(TARGETS)

$(BUILD_DIR)/$(SERVER_TARGET_EXEC): $(OBJS)$(SERVER_OBJS)
$(BUILD_DIR)/$(CLIENT_TARGET_EXEC): $(OBJS)$(CLIENT_OBJS)

# The final build step
$(TARGETS):$(CXX) $^ -o$@ $(LDFLAGS) # Build step for C source$(BUILD_DIR)/%.c.o: %.c
mkdir -p $(dir$@)
$(CC)$(CPPFLAGS) $(CFLAGS) -c$< -o $@ # Build step for C++ source$(BUILD_DIR)/%.cpp.o: %.cpp
mkdir -p $(dir$@)
$(CXX)$(CPPFLAGS) $(CXXFLAGS) -c$< -o $@ .PHONY: clean clean: rm -r$(BUILD_DIR)

# Include the .d makefiles. The - at the front suppresses the errors of missing
# Makefiles. Initially, all the .d files will be missing, and we don't want those
# errors to show up
-include $(DEPS)  Any suggestions on what could be improved? • Is SUDOKU_OBJS a copy paste error? Aug 11 at 3:01 ## 1 Answer Why are INC_DIRS and SRC_DIRS pluralized if they only contain one value each, and are treated that way throughout the rest of the makefile? These should be singular. It looks like $(OBJS) is common to both executables, and is re-linked in each case. It would be (in most cases) better to represent this as a separate, dedicated link step that produces a .so shared object rather than static linking. This shared object file would be shipped beside both the server and client, and the size of the server and client binaries would be reduced.

Your

    mkdir -p $(dir$@)
$(CC)$(CPPFLAGS) $(CFLAGS) -c$< -o $@  would ideally be split up into two different make targets - one to make the directory, and the second depending on the directory and compiling the object. SUDOKU_OBJS seems a likely error. • Thank you for your suggestions, I like the idea of compiling $(OBJS) as a shared object :) And yes, SUDOKU_OBJS was indeed a copy paste error, I forgot to change its name when modifying the code for my question :/ Aug 11 at 13:59