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

Makefile:为什么总是使用“$(MAKE)”而不是“MAKE”?,makefile,gnu-make,parallel-builds,Makefile,Gnu Make,Parallel Builds,我通常使用像cmake这样的高级构建系统来构建我的C/C++代码。但是由于各种原因,我使用的是直接GNUmake 我正在进行递归构建,其中每个目录都有一个makefile 我最近不得不将我所有的makefile从使用make更改为$(make),然后并行构建开始工作 我读过的文献都说“始终使用$(MAKE)”(O'Reilly book,stackoverflow.com上的5+解决方案,来自积分超过10-40K的人) 在makefile中,为什么总是使用$(MAKE)而不是MAKE? (显然,

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

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

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

我读过的文献都说“始终使用
$(MAKE)
”(O'Reilly book,stackoverflow.com上的5+解决方案,来自积分超过10-40K的人)

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

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


除了用
MAKE
简单地替换
$(MAKE)
之外,还有更多的事情发生吗?

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

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

Matthieu的答案是正确的,但不完整

最好的方法是读取与使用
MAKE
变量相关的

除了使用正确的
make
可执行文件(这是很有道理的),GNU还尝试了解哪些配方调用make的递归实例。任何这样做的配方都会通过以下几种方式进行特殊处理:

首先,即使运行
make-n
make-q
、或
make-t
,也会调用该配方

其次,为了与其子make通信(例如,允许jobserver正常工作)
make
维护一组打开的文件描述符(用于管道)。对于“普通”(非递归)配方,make将在生成配方之前关闭这些文件描述符(以便(a)配方不会意外地扰乱通信,以及(b)因为编写某些程序/脚本时预期特定的文件描述符未使用)。对于确定为递归调用的配方,
make
不会关闭这些文件描述符


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

Matthieu的答案是正确的,但不完整

最好的方法是读取与使用
MAKE
变量相关的

除了使用正确的
make
可执行文件(这是很有道理的),GNU还尝试了解哪些配方调用make的递归实例。任何这样做的配方都会通过以下几种方式进行特殊处理:

首先,即使运行
make-n
make-q
make-t
,也会调用该配方

其次,为了与其子make通信(例如,允许jobserver正常工作)
make
维护一组打开的文件描述符(用于管道)。对于“普通”(非递归)配方,make将在生成配方之前关闭这些文件描述符(以便(a)配方不会意外地扰乱通信,以及(b)因为编写某些程序/脚本时预期特定的文件描述符未使用)。对于确定为递归调用的配方,
make
不会关闭这些文件描述符

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