C语言 并行构建期间 Lex/Yacc 生成文件的依赖性问题



我有一个非常基本的示例 Makefile,用于编译 lex yacc 项目。

all: y.tab.o lex.yy.o
lex.yy.c: calc.l
    #flex calc.l
y.tab.c y.tab.h: calc.y
    #bison -d calc.y
lex.yy.o: lex.yy.c y.tab.h
    #gcc -c lex.yy.c
y.tab.o: y.tab.c
    #gcc -c y.tab.c

然而,当我运行make时,我看到野牛被叫了两次。我假设每个目标 y.tab.c 和 y.tab.h 只有一次。

#bison -d calc.y
#gcc -c y.tab.c
#flex calc.l
#bison -d calc.y
#gcc -c lex.yy.c

这会导致并行生成中出现问题。如何修改生成文件,使依赖项与上述相同,但只调用一次 bison 来生成两个目标文件。

如果你想真正测试正在发生的事情,你必须提供实际创建目标文件的命令。 #bison -d calc.y是一个注释,因此由于lex.yy.o的依赖关系,它首先运行以"创建"y.tab.h,并且由于没有从中创建y.tab.c,因此由于y.tab.o的依赖性,因此再次运行以创建y.tab.c。更真实的模拟可以使用touch来创建文件:

all: y.tab.o lex.yy.o
lex.yy.c: calc.l
    #flex calc.l
    @touch $@
y.tab.c y.tab.h: calc.y
    #bison -d calc.y
    @touch y.tab.c y.tab.h
lex.yy.o: lex.yy.c y.tab.h
    #gcc -c lex.yy.c
    @touch $@
y.tab.o: y.tab.c
    #gcc -c y.tab.c
    @touch $@
create:
    touch calc.l calc.y
clean:
    rm y.tab.o lex.yy.o lex.yy.c y.tab.c y.tab.h lex.yy.o y.tab.o calc.l calc.y

使用此设置,make仅按预期"启动"bison一次。

#bison -d calc.y
#gcc -c y.tab.c
#flex calc.l
#gcc -c lex.yy.c

请注意,这可能无法解决您的问题 make -j ,因为在这种情况下,y.tab.hy.tab.c的创建可以独立安排。一种解决方案是 只y.tab.c依赖于 calc.yy.tab.h依赖于y.tab.c,配方什么都不做,如下所示:

y.tab.c: calc.y
    #bison -d calc.y
    @touch y.tab.c y.tab.h
y.tab.h: y.tab.c
    :

解决这个困境的最佳答案,至少如果你使用的是GNU make,就是使用模式规则。 这确实意味着您无法调用输出y.tab.cy.tab.h;您需要输出名称是输入名称的派生。 假设您想生成calc.tab.ccalc.tab.h calc.y;然后你会写:

%.tab.c %.tab.h: %.y
        bison $<
all: calc.tab.o

具有多个目标的模式规则完全符合您的要求:它们告诉 GNU 使规则的一次调用构建两个目标。 这可确保并行构建正常工作,而无需.NOTPARALLEL等。

您的问题是看起来像多目标规则的行y.tab.c y.tab.h: calc.y。 但实际上,它是两个单独规则的简写。 因为传统的制作对文件的来源很草率,所以这通常效果很好。 但在平行的情况下,正如维吉尔指出的那样,它可能不是。

如果你使用makepp,你就不会有这个问题,它实际上将其视为多目标规则。 此外,makepp 对谁构建了什么非常精确(因为它会跟踪它以供将来构建,而不是被时间戳所愚弄)。 这是它能够提供其承诺的可靠性的唯一途径。

要执行一些不并行的目标,可以使用 .NOTPARALLEL 内置 taget -
http://www.gnu.org/software/make/manual/html_node/Special-Targets.html

all: y.tab.o lex.yy.o
lex.yy.c: calc.l
    #flex calc.l
y.tab.c y.tab.h: calc.y
    #bison -d calc.y
lex.yy.o: lex.yy.c y.tab.h
    #gcc -c lex.yy.c
y.tab.o: y.tab.c
    #gcc -c y.tab.c
.NOTPARALLEL : y.tab.c y.tab.h

.不平行

如果。NOTPARALLEL 被提及为目标,那么这个调用 make 将串行运行,即使给出了"-j"选项。任何 递归调用的make命令仍将并行运行配方 (除非其生成文件也包含此目标)。任何先决条件 此目标将被忽略。

最新更新