了解Makefile(C++)的依赖关系

Understanding the Dependencies of a Makefile (C++)

本文关键字:依赖 关系 C++ Makefile 了解      更新时间:2023-10-16

在处理C++项目时,我注意到我正在对主代码中链接的一个头文件进行更改,但make实用程序没有注册它。考虑到使用"make-B"进行的更改,我不得不强制它以不同的方式编译。

我想知道为什么会出现这种情况;这是因为我的makefile是如何编写的,我的文件是如何相互依赖的,两者都依赖,还是两者都不依赖?

这是我的makefile:

CXXFLAGS = -Wall -Werror -std=c++11 -pedantic -Wvla -g
//CXXFLAGS = -std=c++11
all:    main.o game.o zombie.o
        g++ $(FLAGS)  game.o main.o zombie.o -o main $(CXXFLAGS)
game:   game.cpp 
        g++ $(FLAGS) -c game.cpp $(CXXFLAGS)
zombie: zombie.cpp
        g++ $(FLAGS) -c zombie.cpp $(CXXFLAGS)
main:   main.cpp
        g++ $(FLAGS) -c main.cpp pairing_heap.h $(CXXFLAGS)

我对pairing_heap.h
进行了更改,它包含在我的主文件中。

为什么make没有注意到它应该重新编译?因为我觉得这是一个概念上的误解,所以我觉得当我"做-B"时,没有必要包括我所做的更改或输出差异。它们是一些简单的东西,比如cout和cerr,包含在新的pairing_heap.h中,直到被迫才被提取。

如果我需要提供更多信息,请告诉我。

谢谢。

您在main的配方中列出了pairing_heap.h,这并不使其成为main的依赖项(此外,您永远不应该像这样将头传递给编译器),因此您需要编写如下规则:

main:   main.cpp pairing_heap.h 
        g++ $(FLAGS) -c main.cpp $(CXXFLAGS)

文件中还有许多其他不正确的地方,例如目标不是实际文件(main:应该是main.o:等),并且您没有使用自动变量或模式规则,但用以下替换所有内容可能更容易

CPPFLAGS := -MMD -MP
CXXFLAGS := -Wall -Werror -std=c++11 -pedantic -Wvla -g
SOURCES  := $(wildcard *.cpp)
main: $(SOURCES:.cpp=.o)
-include $(SOURCES:.cpp=.d)

它利用make的隐式规则和gcc/clang的自动依赖生成来生成一个名为CCD_ 6的可执行文件。

Make对任何特定的编程语言或工具都不了解,所以它不理解C/C++文件依赖于头文件和源文件。它只是有形式的规则

target: dependencies
        actions

由此可知,文件target依赖于dependencies中列出的文件,如果这些文件中的任何一个更新,则应运行actions中的命令来更新target。事实就是这样——make所做的一切都来自于目标文件、依赖项和操作的简单概念。

现在还有——make有一组内置规则,用于您经常想做的常见事情,以及指定"模式"规则的方法——目标包含通配符的规则,因此可以用于许多不同的目标,这些目标依赖于具有相关名称的其他文件。

现在,在你的情况下,你有一个规则:

all:    main.o game.o zombie.o
        g++ $(FLAGS)  game.o main.o zombie.o -o main $(CXXFLAGS)

它说要重制文件all,如果它比文件main.ogame.ozombie.o旧,它应该运行该命令。这是文件中的第一条规则,因此当您键入make时,默认情况下会生成它。

现在,您可能没有一个名为all的文件(如果您使用make,则可能不会执行任何操作),但这通常是可以的,就好像它不存在一样,它显然不是最新的,因此需要运行该命令。当一个命令需要运行时,它还会检查任何依赖项,看看它们是否有更旧的依赖项(因此需要重新生成)。由于这些文件都以.o结尾,因此它们与一个内置规则相匹配,该规则知道如何从具有相同名称的文件构建它们,但以.cpp结尾除外,因此,如果(且仅当).cpp文件较新,它会运行这些操作。

现在,你说,"我的其他规则呢——它们做什么?"事实证明,它们什么都不做。它们是构建名为gamezombiemain的文件的规则,由于您从不要求构建这些文件,而且其他文件都不依赖于它们,因此它们什么也不做。你不妨把它们删除。

您还会问"如果头文件发生更改,我如何重建它?"好吧,如果您添加一个没有操作的规则(只有目标和依赖项),它只会将这些依赖项添加到有操作的另一个规则(在本例中是内置的)中。所以,如果你加上一行,比如:

main.o: pairing_heap.h

(无需任何操作),make将把这个依赖项添加到知道如何从main.cpp构建main.o的内置规则中,并且如果main.cpppairing_hep.hmain.o新,则将运行该规则(重新编译main.cpp)——这正是您想要的。