Makefile改进,依赖关系生成不起作用

ste*_*fan 4 c++ makefile gnu-make

我正在尝试构建一个正确的Makefile.

我想要的是完全控制正在发生的事情,所以我不想要任何第三方软件.

我当前的尝试对我来说似乎是逻辑,但由于依赖关系生成无效,我有点卡住了.

为了更好的可读性,完整的Makefile被分成几小块.如果有什么需要改进,我将不胜感激任何评论.

首先,我有以下静态定义

CXX = g++
CXXFLAGS = -Wall \
           -Wextra \
           -Wuninitialized \
           -Wmissing-declarations \
           -pedantic \
           -O3 \
           -p -g -pg
LDFLAGS =  -p -g -pg
DEPFLAGS = -MM
Run Code Online (Sandbox Code Playgroud)

Afaik这应该没问题.使分析标志可选是完美的,但这并不重要.

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
Run Code Online (Sandbox Code Playgroud)

基本上,这应该只是提取所有*.cpp文件出的子文件夹中src,另外更换./src./obj,并.cpp.o作为对象的名称.

.PHONY: clean all depend

all: $(TARGET)

$(TARGET): $(OBJS)
    @echo "-> linking $@"
    @$(CXX) $^ $(LDFLAGS) -o $@

$(OBJ_DIR)/%.$(EXT_OBJ):
    @echo "-> compiling $@"
    @$(CXX) $(CXXFLAGS) -c $< -o $@
Run Code Online (Sandbox Code Playgroud)

Afaik,这个块 - 提供了一个有效的依赖文件 - 应该做所有必要的编译和链接.

clean:
    @echo "removing objects and main file"
    @rm -f $(OBJS) $(TARGET)    
Run Code Online (Sandbox Code Playgroud)

应该是不言自明和正确的,还是我在这里遗漏了什么?

$(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)
Run Code Online (Sandbox Code Playgroud)

这是非功能性部分.我打算做的是使用g++Compiler标志-MM自动创建依赖项并使用-MT与默认路径不同的路径.产生的依赖关系应该是这样的

./obj/main.o: ./src/main.cpp ./src/some_header_file.h
Run Code Online (Sandbox Code Playgroud)

不幸的是,这永远不会被调用,我不知道为什么会这样.在一个类似的问题中,用户Beta很乐意通过添加一个临时解决方案来提供,.Phony但这会对重建每个对象产生副作用,而不会有任何变化.

最后,只有一行

-include $(DEP)
Run Code Online (Sandbox Code Playgroud)

一旦创建,就包含依赖文件.

任何提供任何部分提示的答案都非常受欢迎.所以我的问题是:我能做得更好或者更"干净",为什么依赖生成不起作用?

Eld*_*mov 9

开始.


尽可能简单地分配扩展变量:

SRCS := $(wildcard $(SRC_DIR)/*$(SRC_EXT))
Run Code Online (Sandbox Code Playgroud)

来自GNU Make手册:

[递归扩展变量]的另一个缺点是每次扩展变量时都会执行定义中引用的任何函数.这使得make运行速度变慢; 更糟糕的是,它导致wildcardshell函数产生不可预测的结果,因为你无法轻易控制它们何时被调用,甚至多少次.


使用替换引用patsubst函数将源转换为对象:

OBJS := $(SRCS:$(SRC_DIR)/%$(SRC_EXT)=$(OBJ_DIR)/%$(OBJ_EXT))
Run Code Online (Sandbox Code Playgroud)

在编译模式规则中指定适当的先决条件.这是必须的,以使您的目标文件保持最新并在源更改时更新它们.

$(OBJ_DIR)/%$(OBJ_EXT) : $(SRC_DIR)/%$(SRC_EXT)
    @echo "-> compiling $@"
    @$(CXX) $(CXXFLAGS) -o $@ -c $<
Run Code Online (Sandbox Code Playgroud)

编译源并同时为它们生成依赖文件.使用-MMD -MP标志来使事情有效(只需将它们附加到CXXFLAGS).

CXXFLAGS += -MMD -MP

-include $(OBJS:$(OBJ_EXT)=.d)
Run Code Online (Sandbox Code Playgroud)

GCC手册:

-MD

-MD等同于-M -MF 文件,除非-E不暗示.驱动程序根据是否给出-o选项来确定文件.如果是,则驱动程序使用其参数但后缀为.d,否则它将获取输入文件的名称,删除任何目录组件和后缀,并应用.d后缀.

-MMD

-MD,但仅涉及到用户头文件,而不是系统头文件.

-MP

此选项指示CPP为主文件以外的每个依赖项添加虚假目标,从而使每个依赖项都不依赖.make如果删除头文件而不更新Makefile匹配,这些虚拟规则可以解决错误.

还要考虑学习Paul Smith的这篇文章(他是GNU Make的维护者).它给出了不同自动生成方法的相当好的概述.