Search code examples
makefileg++msys2

Generate object files from source files located in multiple folders


I want to generate my executable (TARGET = $(BUILD_DIR)/MySDLProgram) that is dependent of the object files (OBJS = $(wildcard $(BUILD_DIR)/*.o), whose are dependents of source files located in src/application and src/engine. How I should proceed?

I keep getting this error:

Note that Makefile not found the object files

This is my Makefile:

#CC specifies which compiler we're using
CC = g++

# Directories
SRC_DIR = src
BUILD_DIR = build

TARGET = $(BUILD_DIR)/MySDLProgram

# Source files
SRC_DIRS = src/engine src/application
SRCS = $(foreach dir, $(SRC_DIRS), $(wildcard $(dir)/*.cpp))

OBJS = $(wildcard $(BUILD_DIR)/*.o)

# INCLUDE_PATHS specifies the additional include paths we'll need
INCLUDE_PATHS = -Iheader

# COMPILER_FLAGS specifies the additional compilation options we're using
#   -w suppresses all warnings
#   -Wl,-subsystem,windows gets rid of the console window
# COMPILER_FLAGS = -w -Wl,-subsystem,windows
COMPILER_FLAGS = -g -O0 -Wall -std=c++11

#LINKER_FLAGS specifies the libraries we're linking against
LINKER_FLAGS = -lmingw32 -lSDL2main -lSDL2_image -lSDL2_mixer -lSDL2_ttf -lSDL2

.PHONY: all

all: $(TARGET)

$(TARGET): $(OBJS)
    $(CC) $(INCLUDE_PATHS) $(COMPILER_FLAGS) $(LINKER_FLAGS) $^ -o $@

$(BUILD_DIR)/%.o: $(foreach dir, $(SRC_DIRS), $(dir))/%.cpp | $(BUILD_DIR)
    $(CC) $(INCLUDE_PATHS) $(COMPILER_FLAGS) $(LINKER_FLAGS) $< -o $@

$(BUILD_DIR):
    mkdir -p $@

exec: $(BIN)
    $(BIN).exe

clean:
    @$(RM) -rv $(BUILD_DIR)/*

These are the commands that I want to run:

$ g++ -Iheader -g -O0 -Wall -std=c++11 -lmingw32 -lSDL2main -lSDL2_image -lSDL2_mixer -lSDL2_ttf -lSDL2 src/engine/Game.cpp -c -o build/Game.o

$ g++ -Iheader -g -O0 -Wall -std=c++11 -lmingw32 -lSDL2main -lSDL2_image -lSDL2_mixer -lSDL2_ttf -lSDL2 src/engine/Music.cpp -c -o build/Music.o

$ g++ -Iheader -g -O0 -Wall -std=c++11 -lmingw32 -lSDL2main -lSDL2_image -lSDL2_mixer -lSDL2_ttf -lSDL2 src/engine/State.cpp -c -o build/State.o

$ g++ -Iheader -g -O0 -Wall -std=c++11 -lmingw32 -lSDL2main -lSDL2_image -lSDL2_mixer -lSDL2_ttf -lSDL2 src/engine/Sprite.cpp -c -o build/Sprite.o

$ g++ -Iheader -g -O0 -Wall -std=c++11 -lmingw32 -lSDL2main -lSDL2_image -lSDL2_mixer -lSDL2_ttf -lSDL2 src/application/Main.cpp -c -o build/Main.o

$ g++ -g -O0 -Wall -std=c++11 -lmingw32 -lSDL2main -lSDL2_image -lSDL2_mixer -lSDL2_ttf -lSDL2 build/Main.o build/Game.o build/Music.o build/Sprite.o build/State.o

I'm using MSYS2 environment.


Solution

  • This cannot work:

    $(BUILD_DIR)/%.o: $(foreach dir, $(SRC_DIRS), $(dir))/%.cpp | $(BUILD_DIR)
    

    What does this expand to after the variables are resolved? You get this:

    build/%.o: src/engine src/application/%.cpp | build
                        ^^
    

    Which is clearly not what you wanted. Even if you fix your definition to do what you probably expected:

    $(BUILD_DIR)/%.o: $(foreach dir, $(SRC_DIRS), $(dir)/%.cpp) | $(BUILD_DIR)
                                                        ^^^^^^^
    

    which gives:

    build/%.o: src/engine/%.cpp src/application/%.cpp | build
    

    what does this mean to make? It means that in order to match this pattern rule, each build/XXX.o file has to find (or be able to build) a matching src/engine/XXX.cpp AND a matching src/application/XXX.cpp. Basically each object file has BOTH source files as a prerequisite.

    Since none of your files meet that criteria, this rule cannot match ever and so make will not be able to find a way to build the target build/XXX.o.

    You have to write two different rules here, one for each directory:

    $(BUILD_DIR)/%.o: src/engine/%.cpp | $(BUILD_DIR)
            ...
    $(BUILD_DIR)/%.o: src/application/%.cpp | $(BUILD_DIR)
            ...
    

    Alternatively you can use VPATH to ask make to go look in various directories, like this:

    VPATH = $(SRC_DIRS)
    
    $(BUILD_DIR)/%.o: %.cpp | $(BUILD_DIR)
            ...