是否有理由使用"$(MAKE)目标"作为配方?



我正在处理一个相当复杂且有些旧的makefile(因此随着时间的推移,它可能会消失(,并注意具有此配方模式的规则:

SUBDIRS = lib1 lib2 lib3
all:    prerequisites
$(MAKE) subdirs
subdirs: $(SUBDIRS)
# (empty recipe body)

是否有(或曾经(有任何理由以这种方式编写all规则,而不是简单地

all:    prerequisites subdirs
# (empty recipe body)

两者之间有微妙的区别吗?我同时运行GNU make 4.1,并且没有看到任何差异。

makefile是针对Linux和OS/X的,应该支持一些过时的设置,但不是很(首先,我们需要gcc 4.7,这是3年的历史(。

有一个巨大而重要的区别: 将其编写为三个单独的目标可使-j标志正常工作。make -j9告诉 make 保持 9 个作业同时运行,如果您有 8 个 CPU,那就太好了。

这是对任何制作文件的一个很好的测试,也是我直言的全部意义。

您提供的模式是尝试确保在子目录开始构建之前完成先决条件。当然,还有一种更直接的写作方式:

all: ${SUBDIRS}
echo $@ Success
${SUBDIRS}: prerequisites
echo Building $@...
subdirs: ${SUBDIRS} ; # Empty symbolic target

subdirs目标只是为了方便任何希望键入make subdirs的人。

当然,应酌情添加PHONY:

有微妙的差异,但这肯定不重要,也不是故意的,与你的具体情况。

包括但不限于,这里有一些细微的区别。

第一个区别:gmake有一个特殊功能,可以在开始时定义(如果尚未完成(并增加变量MAKELEVEL。因此,以下两个生成文件具有不同的结果:

SUBDIRS = lib1 lib2 lib3
all: prerequisites
$(MAKE) subdirs
subdirs: $(SUBDIRS)
lib3:
echo $(MAKELEVEL)

运行此生成文件将显示:

1

但有以下几点:

SUBDIRS = lib1 lib2 lib3
all: prerequisites subdirs
subdirs: $(SUBDIRS)
lib3:
echo $(MAKELEVEL)

运行此生成文件将显示:

0

因此,如果MAKELEVEL将用于您的Makefile,则构建方式可能不同。例如,以这种方式定义变量会产生一些影响:

ifeq (1,${MAKELEVEL})
CFLAGS=-g
endif

第二个区别:如 gmake 手册中所述,默认情况下,只有来自环境或命令行的变量才会传递给递归调用。但是很少产生影响,因为如果变量的定义不依赖于上下文,那么变量将在内部调用中使用相同的值定义(要产生影响,您应该设置一个上下文相关变量,并在首次运行 Makefile 和运行递归调用时遇到不同的上下文(。

无论如何,当子目录中有其他 Makefile 时,人们经常使用递归调用(但这显然不是您的情况(。所以,我们经常遇到这个:

SUBDIRS = lib1 lib2 lib3
all:    prerequisites
$(MAKE) -C subdirs

当然,这不能用all: prerequisites $SUBDIRS代替,这是没有意义的。但这也许就是为什么有人写了你遇到的东西,而不是相反,没有内心的调用,错误地认为这是一种更常见的写东西的方式。

相关内容

最新更新