I want to create a Makefile where release build object files and program are generated in a ./build directory and debug build object files and program generated in a ./debug directory.
To achieve this I am using the target-specific variable values feature of make as per https://www.gnu.org/software/make/manual/make.html#Target_002dspecific
But the feature is not updating the directory to store the .o and program for some reason.
Makefile is below. When I run the command: make
then the release build is correctly created in the ./build directory.
But if instead I run : make debug
then the .o and program file is generated also in the ./build directory? Why is the directory not updated in the line:
debug: BUILD_DIR = ./debug
Here is the Makefile
CXX=g++
CXXFLAGS=-Wall -std=c++17 -Wextra -Wconversion
PROJECTNAME=ntpserver
SOURCES = main.cpp select-server.cpp ntp-server.cpp address.cpp
BUILD_DIR = ./build
OBJ = $(SOURCES:%.cpp=$(BUILD_DIR)/%.o)
$(BUILD_DIR)/$(PROJECTNAME): $(OBJ)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@
debug: CPPFLAGS += -DDEBUG
debug: CXXFLAGS += -g
debug: BUILD_DIR = ./debug
debug: $(BUILD_DIR)/$(PROJECTNAME)
$(BUILD_DIR)/%.o: %.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
.PHONY: clean
clean:
$(RM) $(BUILD_DIR)/*
As the manual says, target-specific variable values are available in the target's recipe, not the target's prerequisite list.
There are two approaches you can choose from. The simpler one is to use Recursive Make, but that may cause trouble later, so I advise against it.
The more tedious but maintainable way is to create a parallel to build
:
DEBUG_DIR := ./debug
DEBUG_OBJ = $(SOURCES:%.cpp=$(DEBUG_DIR)/%.o)
$(DEBUG_DIR)/$(PROJECTNAME): $(DEBUG_OBJ)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@
debug: $(DEBUG_DIR)/$(PROJECTNAME)
$(DEBUG_DIR)/%.o: %.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
(Once you have that working properly, you should consider moving the debug-specific compiler flags to the object pattern rule.)