然后我运行make scanner,它将一个名为scanner.c的源文件转换为编译,它应该只运行cc lex.yy.c scanner.c -o scanner,但它会这样做:
lex -t scanner.l > scanner.c cc lex.yy.c scanner.c -o scanner
为什么它决定运行lex -t scanner.l并将其输出到scanner.c有效地覆盖我的代码?没有该死的想法,这让我发疯了.
我的makefile:
scanner: scanner.h scanner.c lex.yy.c cc lex.yy.c scanner.c -o scanner lex: scanner.l lex scanner.l > lex.yy.c clean: rm lex.yy.c rm scanner
出了什么问题?
解决方法
Why does it decide to run lex -t scanner.l and output it to scanner.c effectively overwritting my code?
每当发生这种情况时,您在构建目录中都有一个scanner.c
扫描仪.l比scanner.c更新
当您运行make scanner时,配方:
scanner: scanner.h scanner.c lex.yy.c cc lex.yy.c scanner.c -o scanner
要求其先决条件scan.c应为uptodate.您
没有提供这样做的配方,所以要回落
在其内置食谱数据库.
通过运行make -p来检查那些内置的配方,你会发现:
%.c: %.l # recipe to execute (built-in): @$(RM) $@ $(LEX.l) $< > $@
这个内置配方将通过运行以下命令从匹配的file.l生成file.c:
rm file.c # Not echoed lex -t file.l > file.c
Make发现此配方的模式规则 – %.c:%.l – 已满足
通过scanner.c,因为scanner.l存在,并且比scanner.c更新.
所以它使用这个配方来使scan.c uptodate:
lex -t scanner.l > scanner.c
从而破坏了你的扫描仪.
如果你不想让make永远地应用这个内置配方,你可以明确地
通过只写规则取消它:
%.c: %.l
在没有任何配方的makefile中.
您还可以通过传递–no-builtin-rules来禁用所有内置配方
制作命令行.
但是,每当你对makefile的行为有所期望
被内置食谱破坏它强烈表明你的期望
对于从输入文件制作输出文件的常用方法,他们并不了解情况
使用makefile调用的工具.
制作Catalogue of Built-In Rules:
%.<target-type>: %.<prereq-type> <command> ...
体现了制作< target-type>的规范方式来自< prereq-type>的文件
make文件,这样你就不必自己写这个食谱了
你的文件.例如,能够胜任GNU make的C和C程序员
不要编写从.c文件或.cpp文件制作.o文件的配方,除了
极端情况,因为他们知道make的方式会自动完成
通常是他们想要的方式.
Make的内置配方为%.c:%.l规则表达了规范的方式
在给出file.l的情况下制作file.c所以问问自己:如果你不想要scanner.c
要像scan.l那样制作,如果你想要lex.yy.c
可以从scanner.l制作,对你调用的文件是必要的还是有用的
scan.l被调用,当你还有一个非常独立的源文件
叫scan.c?
假设你在这个玩具示例中利用了make的内置配方:
lexer.l
%{ #include <stdio.h> %} %% [ \t] ; [0-9]+\.[0-9]+ { printf("Found a floating-point number: [%s]\n",yytext); } [0-9]+ { printf("Found an integer: [%s]\n",yytext); } [a-zA-Z0-9]+ { printf("Found a string: [%s]\n",yytext); } %%
scanner.c
#include "scanner.h" int main(void) { yylex(); return 0; }
scanner.h
#ifndef SCANNER_H #define SCANNER_H extern int yylex(void); #endif
然后你的makefile可能只是:
Makefile文件
SRCS := scanner.c lexer.c OBJS := $(SRCS:.c=.o) LDLIBS := -lfl .PHONY: all clean all: scanner scanner: $(OBJS) $(LINK.o) -o $@ $^ $(LDLIBS) scanner.o: scanner.h clean: rm -f scanner *.o
运行方式如下:
$make cc -c -o scanner.o scanner.c lex -t lexer.l > lexer.c cc -c -o lexer.o lexer.c cc -o scanner scanner.o lexer.o -lfl rm lexer.c
请注意,make运行所有这些命令:
cc -c -o scanner.o scanner.c lex -t lexer.l > lexer.c cc -c -o lexer.o lexer.c
没有你的lexer.c,lexer.o和scanner.o
写下任何告诉它如何做的食谱.它也是自动的
通知lexer.c是一个中间文件 – 生成的文件
只需要存在从lexer.l到lexer.o – 所以它删除
它在最后:
rm lexer.c
没有被告知.
这个扫描仪运行如下:
$./scanner hello Found a string: [hello] 42 Found an integer: [42] 42.42 Found a floating-point number: [42.42] ^C