Makefile improvements, dependency generation not functioning
c++, gnu-make, makefile
Solution
Here goes.
Assign simply expanded variables where possible:
SRCS := $(wildcard $(SRC_DIR)/*$(SRC_EXT))
From GNU Make manual:
Another disadvantage [of recursively expanded variables] is that any functions referenced in the definition will be executed every time the variable is expanded. This makes `make` run slower; worse, it causes the `wildcard` and `shell` functions to give unpredictable results because you cannot easily control when they are called, or even how many times.
Use substitution references or `patsubst` function to convert sources into objects:
OBJS := $(SRCS:$(SRC_DIR)/%$(SRC_EXT)=$(OBJ_DIR)/%$(OBJ_EXT))
Specify proper prerequisites in compilation pattern rule. This is mandatory to get Make keeping your object files up to date and updating them on source changes.
$(OBJ_DIR)/%$(OBJ_EXT) : $(SRC_DIR)/%$(SRC_EXT)
@echo "-> compiling $@"
@$(CXX) $(CXXFLAGS) -o $@ -c $<
Compile sources and generate dependency files for them at the same time. Use `-MMD -MP` flags to get things work (just append them to `CXXFLAGS`).
CXXFLAGS += -MMD -MP
-include $(OBJS:$(OBJ_EXT)=.d)
From GCC manual:
`-MD`
`-MD` is equivalent to `-M -MF` file, except that `-E` is not implied. The driver determines file based on whether an -o option is given. If it is, the driver uses its argument but with a suffix of `.d`, otherwise it takes the name of the input file, removes any directory components and suffix, and applies a `.d` suffix.
`-MMD`
Like `-MD` except mention only user header files, not system header files.
`-MP`
This option instructs CPP to add a phony target for each dependency other than the main file, causing each to depend on nothing. These dummy rules work around errors `make` gives if you remove header files without updating the `Makefile` to match.
Also consider studying this article of Paul Smith (he is a maintainer of GNU Make). It gives a rather good overview of different autodep-generation approaches.
Problem
I'm currently trying to build a proper Makefile. What I want is full control of what's happening, so I don't want any third party software. My current attempt seems logic to me, but since the dependency generation is not valid, I'm kind of stuck. For better readabilty, the full Makefile is broken into little pieces. I would appreciate any comment on any section if there's something to improve. First of all, I have the following static definitions ``` CXX = g++ CXXFLAGS = -Wall \ -Wextra \ -Wuninitialized \ -Wmissing-declarations \ -pedantic \ -O3 \ -p -g -pg LDFLAGS = -p -g -pg DEPFLAGS = -MM ``` Afaik this should be fine. It would be perfect to make the profiling flags optional but that's not important. ``` SRC_DIR = ./src OBJ_DIR = ./obj SRC_EXT = .cpp OBJ_EXT = .o TARGET = ./bin/my_target SRCS = $(wildcard $(SRC_DIR)/*$(SRC_EXT)) OBJS = $(subst $(SRC_DIR), $(OBJ_DIR), $(SRCS:$(SRC_EXT)=$(OBJ_EXT))) DEP = depend.main ``` Basically, this should just extract all the `*.cpp` files out of the subfolder `src` and additionally replace `./src` with `./obj` and `.cpp` with `.o` as names of the objects. ``` .PHONY: clean all depend all: $(TARGET) $(TARGET): $(OBJS) @echo "-> linking $@" @$(CXX) $^ $(LDFLAGS) -o $@ $(OBJ_DIR)/%.$(EXT_OBJ): @echo "-> compiling $@" @$(CXX) $(CXXFLAGS) -c $< -o $@ ``` Afaik, this block - provided a valid dependency file exists - should do all necessary compiling and linking. ``` clean: @echo "removing objects and main file" @rm -f $(OBJS) $(TARGET) ``` Should be self-explanatory and correct, or am I missing something here? ``` $(SRC_DIR)/%.$(SRC_EXT): $(CXX) $(DEPFLAGS) -MT \ "$(subst $(SRC_DIR),$(OBJ_DIR),$(subst $(SRC_EXT),$(OBJ_EXT),$@))" \ $(addprefix ,$@) >> $(DEP); clear_dependencies: @echo "-> (re-)building dependencies"; @$(RM) $(DEP) depend: clear_dependencies $(SRCS) ``` This is the non-functional part. What I intend to do is using the `g++` Compiler flag `-MM` to auto-create dependencies and using `-MT` to use a different path than the default one. The resulting dependency should look like ``` ./obj/main.o: ./src/main.cpp ./src/some_header_file.h ``` Unfortunately, this will never be called and I lack the knowledge why this is the case. In a similar question, user Beta gladly provided a temporary solution by adding a `.Phony` but this has the side effect on rebuilding every object without any change. Finally, there is just the one line ``` -include $(DEP) ``` to include the dependency file, once created. Any answer providing some hints about any part are very welcome. So my question is: What can I do better or maybe "cleaner" and why doesn't the dependency generation work?