Home > OS >  Problems building a generic Makefile with dependency tracking
Problems building a generic Makefile with dependency tracking

Time:01-26

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)
  •  Tags:  
  • Related