Makefile:为什么总是使用 `$(MAKE)` 而不是 `make`?

Makefile: why always use `$(MAKE)` instead of `make`?

我通常使用像 cmake 这样的高级构建系统来构建我的 C/C++ 代码。但是由于各种原因我直接使用 GNU make

我正在进行递归构建,其中每个目录都有一个 makefile。

我最近不得不将我所有的 makefile 从使用 make 更改为 $(MAKE),然后并行构建开始工作。

我读过的文献都说 "always use $(MAKE)"(O'Reilly 的书,whosebug.com 上的 5+ 个解决方案来自分数超过 10-40K 的人)。

在您的 makefile 中,为什么总是使用 $(MAKE) 而不是 make

(显然一个原因是因为 $(MAKE) 以某种方式启用了并行构建。)

是否有比 $(MAKE)make 的简单替换更多的事情发生?

在某些系统上,调用 make 的可执行文件不会被调用 make。例如,非 GNU 系统通常有一个不是 GNU Make 的 make 命令,如果用户想使用为 GNU Make 设计的 Makefile,则必须 运行 gmake。如果您在这些系统上以 make 的形式进行递归调用,则递归调用将不会调用与用户键入的顶级可执行文件相同的可执行文件。使用 $(MAKE) 确保递归调用将使用与顶层相同的 "make"。

Matthieu 的回答是正确的,但不完整。

最好的办法是阅读与使用 MAKE 变量相关的 GNU make manual section

除了使用正确的 make 可执行文件(这是足够的理由)之外,GNU make 还尝试了解哪些配方调用 make 的递归实例。任何这样做的食谱都会以几种方式进行特殊处理:

首先,即使您 运行 make -nmake -qmake -t.

也会调用该配方

其次,为了与其子makes通信(例如,为了让jobserver正常工作)make维护了一组打开的文件描述符(用于管道)。对于 "normal"(非递归)食谱,make 将在生成食谱之前关闭那些文件描述符(这样(a)食谱不会意外地弄乱该通信,并且(b)因为一些程序/脚本被写入期望特定的文件描述符未被使用)。对于确定为递归调用的配方,make 不会关闭那些文件描述符。

GNU make 使用两种不同的方法来检测配方是否为递归 make。其中之一是您可以将 + 特殊字符添加到食谱的开头。第二个是配方中存在 $(MAKE)(或 ${MAKE})变量引用。