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

时间:2014-04-07 19:51:32

标签: makefile jobs

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

我的第一个猜测是使用名为“.PARALLEL”的不存在的目标,我将其中提到的对象文件作为这样的依赖:

SRC=$(wildcard *.c)
OBJ=$(SRC:.c=.o)           

.PARALLEL: $(OBJ)

%.o: %.c
    gcc –c –o$@ $< -M

a.out: $(OBJ)
    gcc –o$@ $^

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

%.o: %.c
    $(CC) –c –o$@ $< -M

MyObjects: 
    $(MAKE) -j $(OBJ)

a.out: MyObjects
    $(CC) –o$@ $(OBJ)

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

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))
DUM = $(addsuffix .dummy,$(OBJ))

all: a.out

$(SRC):%.c: 
    touch $@

$(OBJ):%.o: %.c
    cp $< $@
    touch $(addsuffix .dummy, $@)

$(DUM):
    $(MAKE) -j8 $(OBJ)

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

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

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

P.S。 MadScientist,谢谢你的建议。

1 个答案:

答案 0 :(得分:2)

这真的不对:

MyObjects: $(OBJ)
        $(MAKE) -j $(OBJ)

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

你想要这样的东西:

MyObjects:
        $(MAKE) -j5 $(OBJ)

至于你关于尝试重建目标的第二个问题,如果没有某种具体的例子,我们就无法提供帮助。通常会发生这种情况,因为您的规则编写错误,而且实际上并没有更新您告诉他们的目标。例如,您有一个目标recipe_a,但recipe_a的规则更新了其他一些目标,而不是recipe_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:之类的模式规则,那就告诉它可以通过运行创建一个.c扩展名的任何文件那个命令。那么,您要求构建的目标之一是all目标。由于您没有将其声明为.PHONY目标,因此请尝试构建它。通常,尝试失败是因为make无法找到任何知道如何构建all的规则,所以没有任何反应,但是在你告诉make如何从无到有(无先决条件)构建.c文件之后,那么当make想要构建all时,它会在其预定义规则的内部数据库中查找并查看模式规则% : %.c,它告诉如何从具有相同名称的源文件构建可执行文件(在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