I have the following project structure: a folder called "src" with all the .cpp, a folder called "include" with the .h, a folder called "build" for the .o (object files), another folder called "dep" for the .d files (dependencies) and finally another folder called "bin" for the executables.
Given that, I have done this makefile to carry out the build process
OPTIONS := -O2 -Wall
EXE_NAME = example.exe
BIN_PATH = bin/
BUILD_PATH = build/
DEP_PATH = dep/
INCLUDE_PATH = include/
SRC_PATH = src/
################################################################################
# get project files
ALL_CPP := $(shell find $(SRC_PATH) -type f -name "*.cpp")
ALL_H := $(shell find $(INCLUDE_PATH) -type f -name "*.h")
ALL_O := $(subst $(SRC_PATH),$(BUILD_PATH),$(subst .cpp,.o,$(ALL_CPP)))
ALL_D := $(subst $(SRC_PATH),$(DEP_PATH),$(subst .cpp,.d,$(ALL_CPP)))
all: $(BIN_PATH)$(EXE_NAME)
#linking
$(BIN_PATH)$(EXE_NAME): $(ALL_O)
g $(OPTIONS) -o $@ $(ALL_O)
# generic build rule
$(BUILD_PATH)%.o: $(SRC_PATH)%.cpp
g $(OPTIONS) -c $< -o $(BUILD_PATH)$@ -I$(INCLUDE_PATH) -MMD -MF $(DEP_PATH)$(@:.o=.d)
.PHONY: clean
clean:
rm $(ALL_D) $(ALL_O) $(BIN_PATH)$(EXE_NAME)
-include $(ALL_D)
But whenever I try to execute it, this error pops out:
make: *** No rule to make target 'build/file.o', needed by 'bin/example.exe'. Stop.
Which does not make sense, as there is a rule for building targets that end in ".o".
What might be going on here?
CodePudding user response:
First, you should avoid using subst since it substitutes every instance of one set of text with another. Safer is to use patsubst:
ALL_O := $(patsubst $(SRC_PATH)%.cpp,$(BUILD_PATH)%.o,$(ALL_CPP))
ALL_D := $(patsubst $(SRC_PATH)%.cpp,$(DEP_PATH)%.d,$(ALL_CPP))
Second, your command line is wrong: $@ already contains the path so you don't want to use $(BUILD_DIR)$@. You want just $@ by itself. You'll have a similar problem for .d.
But I don't see any way to get the error you show (no rule to make target 'build/file.o') given the makefile you provide. Either there's something different about your makefile than what you have here or something mysterious is happening.
You can add the -d option to make to get some debug info.
CodePudding user response:
Thanks to all who replied. As many of you suggested, the error I provided does not appear in the makefile version I posted, and that is because I did some code cleaning before posting which ironically end up solving the error (I had no idea the changes I made would be important). More precisely, I am sure the problem was with the line
$(BUILD_PATH)%.o: $(SRC_PATH)%.cpp
Which in the original makefile was
$(BUILD_PATH)%.o: %.cpp
I have also tried without the $(BUILD_PATH), which gave no luck, that's why I thought that line was not important.
I did some of the changes you suggested and the final working version of the Makefile is as follows
OPTIONS := -O2 -Wall -Wno-sign-compare -Wno-unused-parameter
EXE_NAME = example
BIN_PATH = bin/
BUILD_PATH = build/
DEP_PATH = dep/
INCLUDE_PATH = include/
SRC_PATH = src/
################################################################################
# get project files
ALL_CPP := $(shell find $(SRC_PATH) -type f -name "*.cpp")
ALL_H := $(shell find $(INCLUDE_PATH) -type f -name "*.h")
ALL_O := $(subst $(SRC_PATH),$(BUILD_PATH),$(subst .cpp,.o,$(ALL_CPP)))
ALL_D := $(subst $(SRC_PATH),$(DEP_PATH),$(subst .cpp,.d,$(ALL_CPP)))
all: $(BIN_PATH)$(EXE_NAME)
#linking
$(BIN_PATH)$(EXE_NAME): $(ALL_O)
@echo ' -> linking'
@g $(OPTIONS) -o $@ $(ALL_O)
@echo Finished!
# generic build rule
$(BUILD_PATH)%.o: $(SRC_PATH)%.cpp
@echo ' -> building:' $<
@g $(OPTIONS) -c $< -o $@ -I$(INCLUDE_PATH) -MMD -MF $(subst $(BUILD_PATH),$(DEP_PATH),$(@:.o=.d))
.PHONY: clean
clean:
@echo Removed files: $(ALL_D) $(ALL_O) $(BIN_PATH)$(EXE_NAME)
@rm $(ALL_D) $(ALL_O) $(BIN_PATH)$(EXE_NAME)
-include $(ALL_D)
