user1237916231
user1237916231

Reputation: 3

Makefile not doing what I want - Compiling same thing twice

CXX         := g++
CXX_FLAGS   := -std=c++17

SRC_DIR     := ./src
LIB_DIR     := $(SRC_DIR)/lib
OBJ_DIR     := $(SRC_DIR)/obj
BIN_DIR     := $(SRC_DIR)/bin

BIN_DEBUG   := $(BIN_DIR)/Test-debug
BIN_RELEASE := $(BIN_DIR)/Test

SRC_FILES   := $(wildcard $(SRC_DIR)/*.cpp)
LIB_FILES   := $(wildcard $(LIB_DIR)/*.cpp)
OBJ_FILES   := $(patsubst $(SRC_DIR)/%.cpp,$(OBJ_DIR)/%.o,$(SRC_FILES)) $(patsubst $(LIB_DIR)/%.cpp,$(OBJ_DIR)/%.o,$(LIB_FILES))

$(BIN_RELEASE): $(OBJ_FILES)
    $(CXX) $(CXX_FLAGS) -o $@ $^

$(OBJ_FILES): $(SRC_FILES) $(LIB_FILES)
    $(CXX) $(CXX_FLAGS) -c -o $@ $<

clean:
    rm ./src/obj/*.o
    rm ./bin/*
    
run:
    $(BIN_RELEASE)

This is my Makefile and it is doing the same g++ -c command in a row and then failing in the linking because it tries to link the a file to it self. Or can someone say how you debug a Makefile.

Upvotes: 0

Views: 76

Answers (1)

MadScientist
MadScientist

Reputation: 100836

This is wrong:

$(OBJ_FILES): $(SRC_FILES) $(LIB_FILES)
        $(CXX) $(CXX_FLAGS) -c -o $@ $<

Say you have src/foo.cpp and src/bar.cpp in SRC_FILES. Now OBJ_FILES is src/obj/foo.o and src/obj/bar.o. Now the above rule expands like this:

src/obj/foo.o src/obj/bar.o: src/foo.cpp src/bar.cpp
        $(CXX) $(CXX_FLAGS) -c -o $@ $<

It's not the case that make will intuit what you want to do here and match up each object file with the source file, or something like that. The above means exactly the same thing as if you'd written these rules:

src/obj/foo.o: src/foo.cpp src/bar.cpp
        $(CXX) $(CXX_FLAGS) -c -o $@ $<

src/obj/bar.o: src/foo.cpp src/bar.cpp
        $(CXX) $(CXX_FLAGS) -c -o $@ $<

Now you can see why every compile line compiles the same source file: the $< variable expands to the first prerequisite, and for every object file the first prerequisite is always the same (here, src/foo.cpp).

You need to use a pattern rule here, telling make how to build one single file. And since you're building things in two different ways, you actually need two pattern rules.

$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
        $(CXX) $(CXX_FLAGS) -c -o $@ $<

$(OBJ_DIR)/%.o: $(LIB_DIR)/%.cpp
        $(CXX) $(CXX_FLAGS) -c -o $@ $<

Upvotes: 1

Related Questions