2
votes

I've been reading through posts about Makefiles that use subdirectories, but can't seem to put all the pieces together properly. I have the following file structure:

program
    |
    - src
    |
    - include
    | 
    - build
    |
    - bin
    |
    - Makefile

All my sources (.cpp) are in program/src/, all my headers (.hpp) are in program/include, I want all my object files and dependency files put into program/build, and I want my binary placed into program/bin. The following is what I currently have in my Makefile:

CXX = g++
BIN_DIR = bin
TARGET = $(BIN_DIR)/coreint
BUILD_DIR = build
SRC_DIR = src
INC_DIR = include
CXXFLAGS = -Wall -g

# Get all source files
SRCS := $(shell find $(SRC_DIR) -name *.cpp)
# Get all object files by replacing src directory with build directory    and replace extension
OBJS := $(subst $(SRC_DIR), $(BUILD_DIR), $(SRCS:%.cpp=%.o))
# Get all depend files by replacing extensions
DEPS := $(OBJS:.o=.d)
# Get all includes by searching include directory
INCS := $(shell find $(INC_DIR) -name *.hpp)
# Append -I to the front of each include
INCS := $(foreach d, $(INCS), -I$d)
# Using VPATH to find files in src/ include/ and build/
VPATH = $(SRC_DIR):$(INC_DIR):$(BUILD_DIR)

all: $(TARGET)

$(TARGET): $(OBJS)
    $(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) -o $(TARGET)

# Build object files and put in build directory
$(BUILD_DIR)%.o: %.cpp
    $(CXX) $(CXXFLAGS) -c $< -o $@

# Place dependency files in build directory
# automatically generate dependency rules
$(BUILD_DIR)%.d: %.cpp
    $(CXX) $(CXXFLAGS) -MF"$@" -MG -MM -MD -MP -MT"$@" -MT"$(OBJS)" "$<"
# -MF  write the generated dependency rule to a file
# -MG  assume missing headers will be generated and don't stop with an error
# -MM  generate dependency rule for prerequisite, skipping system headers
# -MP  add phony target for each header to prevent errors when header is missing
# -MT  add a target to the generated dependency

.PHONY: clean all

clean:
    rm -f $(OBJS) $(DEPS) $(TARGET)

-include $(DEPS)

When I run make, I get the following error:

make: *** No rule to make target `build/assign.o', needed by `bin/coreint'.  Stop.

Where assign.o is the first file in the build directory. Thank you in advance.

1
Isn't there just missing slash after the $(BUILD_DIR)? AFAIK, the current code would generate rules like buildassign.o: assign.cppomusil
/me facepalms. That's all it was. I've been looking at this thing for over 4 hours this morning and you saw it right away. Thanks!Aginor

1 Answers

1
votes

I was simply missing a '/' after my BUILD_DIR:

# Build object files and put in build directory
$(BUILD_DIR)/%.o: %.cpp
    $(CXX) $(CXXFLAGS) -c $< -o $@