除某些规则外,并行执行 Makefile

now*_*wox 5 jobs makefile

我有一个复杂的 makefile,其中有很多食谱。除了生成对象文件之外,我想在不并行执行的情况下运行它们。我注意到 .NOTPARALLEL 目标不能满足任何先决条件,否则解决我的问题会容易得多。

\n\n

我的第一个猜测是使用一个名为“.PARALLEL”的不存在的目标,我将使用它来将对象文件作为依赖项提及,如下所示:

\n\n
SRC=$(wildcard *.c)\nOBJ=$(SRC:.c=.o)           \n\n.PARALLEL: $(OBJ)\n\n%.o: %.c\n    gcc \xe2\x80\x93c \xe2\x80\x93o$@ $< -M\n\na.out: $(OBJ)\n    gcc \xe2\x80\x93o$@ $^\n
Run Code Online (Sandbox Code Playgroud)\n\n

我发现的一个更实用的解决方案是使用中间目标。然而,由于 MyObjects 没有依赖关系,make 将始终调用 MyObjects 并重新创建 a.out。

\n\n
%.o: %.c\n    $(CC) \xe2\x80\x93c \xe2\x80\x93o$@ $< -M\n\nMyObjects: \n    $(MAKE) -j $(OBJ)\n\na.out: MyObjects\n    $(CC) \xe2\x80\x93o$@ $(OBJ)\n
Run Code Online (Sandbox Code Playgroud)\n\n

为了避免这种情况,我发现没有什么比使用虚拟文件更好的了。我写了这个例子来说明它:

\n\n
NAMES = 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16\n\nSRC = $(addsuffix .c, $(NAMES))\nOBJ = $(patsubst %.c,%.o,$(SRC))\nDUM = $(addsuffix .dummy,$(OBJ))\n\nall: a.out\n\n$(SRC):%.c: \n    touch $@\n\n$(OBJ):%.o: %.c\n    cp $< $@\n    touch $(addsuffix .dummy, $@)\n\n$(DUM):\n    $(MAKE) -j8 $(OBJ)\n\na.out: $(DUM) $(OBJ)\n    zip $@ $(OBJ)    \n\nclean: \n    -rm *.o\n    -rm *.out\n    -rm *.c \n    -rm *.dummy \n
Run Code Online (Sandbox Code Playgroud)\n\n

我确信这不是我能得到的最佳解决方案。我很高兴得到一些帮助。

\n\n

PS MadScientist,谢谢你的建议。

\n

Mad*_*ist 4

这确实是不对的:

MyObjects: $(OBJ)
        $(MAKE) -j $(OBJ)
Run Code Online (Sandbox Code Playgroud)

这意味着在make 尝试构建目标之前MyObjects,它将首先尝试更新所有文件$(OBJ)。一旦这一切完成,它将尝试MyObjects通过递归调用 make 来再次重建它们来构建目标。显然这不是你想要的。另外,您使用的-j基本上是“无限并行”,并且很可能(如果您有足够的目标文件)使您的系统崩溃。

你想要这样的东西:

MyObjects:
        $(MAKE) -j5 $(OBJ)
Run Code Online (Sandbox Code Playgroud)

至于你关于尝试重建目标的第二个问题,如果没有某种具体的例子,我们无法提供帮助。通常会发生这种情况,因为您的规则编写不正确,并且它们实际上并未更新您告诉的目标。例如,您有一个目标,但更新某些其他目标recipe_a的规则,而不是。recipe_arecipe_a

我将根据你的第二个问题添加一些注释。如果在此之后您没有得到它,您应该将其从 StackOverflow 中删除并在 help-make@gnu.org 邮件列表上询问,或者考虑将其分解并询问几个特定的​​ StackOverflow 问题。

首先,为什么你会看到make[1]: '15.o' 是最新的。对于递归 make 中的每个文件:因为 make 总是在命令行上为每个目标打印该消息,所以如果您运行make 1.o 2.o 3.o ...(无论您-j是否使用或-j使用什么值),您都会收到该消息每个不需要重建的目标。就像您make自己从命令行运行相同的命令一样。

其次,为什么你没有得到a.out is up to date,因为它a.out不是最新的。这取决于build目标,并且该文件build不存在,因此它已经过时,因此每次都必须重新构建。这意味着任何依赖于build目标的东西,比如a.out,每次都必须重建。这解释了为什么它总是重新运行该zip命令。

第三,这样做的行为all.c是因为如果您创建一个%.c:没有先决条件的模式规则,它会告诉 make 它可以.c通过运行该命令来创建任何带有扩展名的文件。好吧,您要求 make 构建的目标之一就是all目标。由于您没有将其声明为.PHONY目标,因此 make 会尝试构建它。通常这种尝试会失败,因为 make 找不到任何知道如何构建的规则,all所以什么也没有发生,但是当你告诉 make 如何.c从无到有构建一个文件(没有先决条件)之后,当 make 想要构建时,all它会在其内部查找预定义规则的数据库并看到一个模式规则% : %.c,它告诉 make 如何从具有相同名称的源文件构建可执行文件(在 UNIX 系统上,可执行文件没有任何后缀,例如.exe:它们只是makecc等等)所以,make尝试执行这些规则但它们失败了。

对于任何您不希望实际创建的目标,例如allclean等,您应该声明它们,.PHONY以便 make 不会尝试构建它们。

至于你的问题。我认为最简单的做法是将 zip 文件的整个构建推送到递归 make 中,而不是尝试仅在递归 make 中构建对象。像这样的东西:

NAMES = 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

SRC = $(addsuffix .c,$(NAMES))
OBJ = $(patsubst %.c,%.o,$(SRC))

all: recurse

recurse: non-parallel-targets
        $(MAKE) -j8 a.out PARALLEL=true

ifneq($(PARALLEL),true)
.NOTPARALLEL:
endif

%.o: %.c
        cp $< $@

a.out: $(OBJ)
        zip $@ $(OBJ)

init: $(SRC)

clean: 
        -rm *.o
        -rm *.out

.PHONY: all clean init
Run Code Online (Sandbox Code Playgroud)