Makefile从规则中调用不同的程序

时间:2015-09-28 22:28:06

标签: makefile

我有一个make文件来构建一个使用bison和flex的简单pascal编译器,但是当我从终端运行make时,它显示正在调用yacc而不是bison。

我的Makefile:

all: minipascal

minipascal.tab.h minipascal.tab.c: minipascal.y 
    bison -r all -d minipascal.y

minipascal.flex.c: minipascal.l minipascal.tab.h
    flex -o minipascal.flex.c minipascal.l

calc: minipascal.c minipascal.tab.c minipascal.lex.c
   gcc minipascal.flex.c minipascal.tab.c minipascal.c -lf -o minipascal >& buildlog.txt

clean:
    rm minipascal.tab.h minipascal.tab.c minipascal.lex.c buildlog.txt minipascal minipascal.output

我的路径中有野牛,当我逐行输入命令时,构建按预期工作。文件minipascal.h和minipascal.c存在于我运行make的当前目录中。

make命令的输出:

yacc  minipascal.y 
yacc: e - line 73 of "minipascal.y", syntax error
            %empty                                                                  {$$ = NULL;}
            ^
<builtin>: recipe for target 'minipascal.c' failed
make: *** [minipascal.c] Error 1

1 个答案:

答案 0 :(得分:1)

如果您还有名为foo.cfoo.y的源文件,那么拥有一个名为foo.l的源文件真的不是一个好主意。 make会高兴地覆盖foo.c,让你争先恐后地备份。 (你有备份,对吧?)。如果您想使用其他源文件并且不想考虑其他名称,请使用其他后缀,例如foo.base.c。 (或者您可以使用明确的空规则,如下所述。但是恕我直言,避免这个问题是安全的。)

make中可以将任何在makefile中命名的文件(无论是作为目标还是先决条件)视为可构建的文件。由于minipascal.c被列为先决条件,这意味着minipascal.c位于make准备构建的文件列表中。

您确实没有minipascal.c的任何构建规则。但是make知道如何从%.c%.y构建%.l是一个通配符;它将被替换为目标中的相同字符串,先决条件。)

当make看到它需要minipascal.c时,它首先检查是否有该文件的明确配方(没有),然后查看其默认的配方数据库。在这里,它找到了%.y → %.c食谱和%.l → %.c食谱。幸运的是,.y食谱在其数据库中排在第一位,所以它尝试了。更幸运的是,配方在没有修改“目标”minipascal.c的情况下失败了,因为配方是:

%.c: %.y
#  recipe to execute (built-in):
        $(YACC.y) $< 
        mv -f y.tab.c $@

并且来自yacc的非零退出代码导致配方终止而不执行mv命令。 .l食谱是:

%.c: %.l
#  recipe to execute (built-in):
        @$(RM) $@ 
        $(LEX.l) $< > $@

如果符号不明显,则可以解决:

@rm minipascal.c
lex minipascal.l > minipascal.c

其中@表示rm命令不会回显到屏幕上。并不是说它有很大的不同,因为lex命令中的重定向也会删除minipascal.c,即使lex失败。

当然,make不会无条件地尝试重建minipascal.c。它首先检查时间戳以确保重建是必要的。决定使用%.y规则构建minipascal.c后,它会比较minipascal.cminipascal.y的时间戳。它决定重建minipascal.c,因为野牛来源更新,所以它假设minipascal.c文件已过时。

碰巧,您的all规则取决于minipascal,但没有规则可以构建minipascal。有一条规则可以构建calc,但make无法知道您的意思是minipascal

但这并不会停止make,因为它知道如何从minipascal构建minipascal.c(使用另一个默认规则)。决定这样做之后,它会继续验证minipascal.c是否是最新的,如上所述。如果它确定minipascal.c是最新的,那么它将使用其默认构建规则构建minipascal,这也会因链接器错误而失败,因为它既不是解析器也不是词法分析器(也不是你的-lf库)属于默认构建规则。

您的makefile也不一致地使用minipascal.flex.cminipascal.lex.c。那也会让你感到悲伤。

如果您真的想要一个名为minipascal.c的源文件,那么您需要通过提供一个空的构建规则来保护它免受自动构建:

minipascal.c: ;

但是,正如我所说,这可能不是最佳解决方案。