简体   繁体   English

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

[英]Makefile improvements, dependency generation not functioning

I'm currently trying to build a proper Makefile. 我正在尝试构建一个正确的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. 为了更好的可读性,完整的Makefile被分成几小块。 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. Afaik这应该没问题。 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. 基本上,这应该只是提取所有的*.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 $@

Afaik, this block - provided a valid dependency file exists - should do all necessary compiling and linking. Afaik,这个块 - 提供了一个有效的依赖文件 - 应该做所有必要的编译和链接。

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. 我打算做的是使用g++ Compiler标志-MM来自动创建依赖项,并使用-MT来使用与默认路径不同的路径。 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. 在一个类似的问题中 ,用户Beta很乐意通过添加.Phony提供临时解决方案,但这对重建每个对象没有任何改变有副作用。

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? 所以我的问题是:我能做得更好或者更“干净”,为什么依赖生成不起作用?

Here goes. 开始。


Assign simply expanded variables where possible: 尽可能简单地分配扩展变量

SRCS := $(wildcard $(SRC_DIR)/*$(SRC_EXT))

From GNU Make manual : 来自GNU Make手册

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; 这使得make运行速度变慢; 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. 更糟糕的是,它会导致wildcardshell函数产生不可预测的结果,因为您无法轻易控制它们何时被调用,甚至无法控制多少次。


Use substitution references or patsubst function to convert sources into objects: 使用替换引用patsubst函数将源转换为对象:

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 ). 使用-MMD -MP标志可以使事情正常工作(只需将它们附加到CXXFLAGS )。

CXXFLAGS += -MMD -MP

-include $(OBJS:$(OBJ_EXT)=.d)

From GCC manual : GCC手册

-MD

-MD is equivalent to -M -MF file , except that -E is not implied. -MD等效于-M -MF 文件 ,但不暗示-E The driver determines file based on whether an -o option is given. 驱动程序根据是否给出-o选项来确定文件。 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. 如果是,则驱动程序使用其参数但后缀为.d ,否则它将获取输入文件的名称,删除任何目录组件和后缀,并应用.d后缀。

-MMD

Like -MD except mention only user header files, not system header files. -MD一样,只提到用户头文件,而不是系统头文件。

-MP

This option instructs CPP to add a phony target for each dependency other than the main file, causing each to depend on nothing. 此选项指示CPP为除主文件之外的每个依赖项添加虚假目标,从而使每个依赖项都不依赖。 These dummy rules work around errors make gives if you remove header files without updating the Makefile to match. 这些假规则将避开错误make如果删除头文件时不更新给Makefile相匹配。

Also consider studying this article of Paul Smith (he is a maintainer of GNU Make). 还要考虑学习Paul Smith的这篇文章 (他是GNU Make的维护者)。 It gives a rather good overview of different autodep-generation approaches. 它给出了不同自动生成方法的相当好的概述。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM