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



# 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)



# 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 += -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)


# The final build step
    $(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
    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?

  • \$\begingroup\$ Is SUDOKU_OBJS a copy paste error? \$\endgroup\$
    – Reinderien
    Aug 11 at 3:01

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.


    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.

  • \$\begingroup\$ 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 :/ \$\endgroup\$
    – Spiwocoal
    Aug 11 at 13:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.