1

我有这个非常基本的示例 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 时,我看到 bison 被调用了两次。我假设每个目标 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

这会导致并行构建出现问题。如何修改 makefile 以使依赖项与上述相同,但仅调用一次 bison 即可生成两个目标文件。

4

4 回答 4

2

如果您想真正测试发生了什么,您必须提供实际创建目标文件的命令。#bison -d calc.y是一个注释,所以它首先运行以“创建” y.tab.h,因为它的依赖关系,lex.yy.o并且由于 noy.tab.c是从中创建的,它再次运行以创建y.tab.c,因为 . 的依赖关系y.tab.o。可以使用更真实的模拟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.h可能y.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
    :
于 2013-11-06T08:07:30.047 回答
1

至少如果您使用 GNU make,这个困境的最佳答案是使用模式规则。这确实意味着您不能调用输出y.tab.cy.tab.h; 您需要输出名称是输入名称的派生词。假设calc.y你想生成calc.tab.cand calc.tab.h; 那么你会写:

%.tab.c %.tab.h: %.y
        bison $<

all: calc.tab.o

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

于 2013-11-06T13:09:39.563 回答
0

要执行一些不并行的目标,您可以使用 .NOTPARALLEL 内置标记 -
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

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

于 2013-11-06T07:42:44.907 回答
0

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

如果你使用makepp就不会出现这个问题,它确实将其视为多目标规则。makepp 对谁构建什么也非常精确(因为它会跟踪它以供将来构建,而不是被时间戳所欺骗)。这是它可以提供它所承诺的可靠性的唯一方法。

于 2013-11-06T11:04:58.603 回答