为什么不在 makefile 中生成依赖项?

Why aren't dependencies generated inside makefiles?

我最近学习了如何使用 Makefile,我发现 GCC/G++ 为您生成依赖项:

$ g++ -MM file.cpp
file.o: file.cpp file.h

然后我认为显而易见的事情是使用它直接在文件中生成依赖项而不创建依赖项文件:

CXX = g++

SRCS = $(wildcard src/*.cpp)
OBJS = $(SRCS:.cpp=.o)
OCT = $(CXX -MM $(SRCS))
OBJDIR = obj
CPPFLAGS = -Wall -I/usr/local/include -L/usr/local/lib -lGLEW -lglfw -lGL

.PHONY: all
all: $(OBJS)
    $(CXX) $(CPPFLAGS) $(OBJS) -o output

$(OCT)

.PHONY: clean
clean:
    rm -f obj/*

出于某种原因,我从未见过其他人这样做;他们总是生成一个依赖文件。这个系统有问题吗?在我的例子中是——对象不去 OBJDIR,它们去源文件的位置。我确定这可以解决。如果有人知道我该如何解决这个问题以及为什么通常会生成依赖文件,请告诉我。

嗯,人们不这样做的第一个原因是它不可能做到:如果您尝试让您的建议在现实生活中发挥作用,您就会看到这一点。例如,您的示例根本不执行任何操作。这个:

OCT = $(CXX -MM $(SRCS))

(我假设你的意思是 $($(CXX) -MM $(SRCS)) 但无论哪种方式都没有关系)正在将对名为 CXX -MM $(SRCS) 的 make 变量的引用放入变量 OCT 中:您可能认为它使用的是 shell 命令调用语法 $(...) 但这是一个 makefile,而不是 shell 脚本。所以当你写:

$(OCT)

它试图查找显然不存在的 make 变量,因此它扩展为空字符串并且什么也没有发生。如果您实际上尝试通过触摸 header 等来测试您的 makefile,您将看不到任何重建。

你怎么做到的?你做不到。您可以像这样更改变量分配:

OCT = $(shell $(CXX) -MM $(SRCS))

这实际上会 运行 编译器,它会让你朝着正确的方向前进,但是 shell 函数的结果将改变所有换行到空白,所以这个:

$(OCT)

将在一行 上扩展到编译器命令的整个输出 ,并且由于它包含多个冒号,您将遇到语法错误。

您所能做的就是将编译器的输出重定向到一个文件,然后使用 make 的 include 功能来包含该文件。但是现在你基本上回到了场景 suggested in the GNU make manual,除了你的版本效率较低,因为正如上面的评论所指出的,你正在重新生成 all [=每次 运行 生成所有源文件的 46=]s,而不是只为实际更改的文件重新生成 header 信息。

有 better/more 种生成 header 的有效方法,例如 the one used by most GNU packages