我正在运行“Lex & Yacc”(John R. Levine、Tony Mason 和 Doug Brown)中的示例:
$ cat ch2-04.l
%{
unsigned verbose;
char *prog_name;
%}
%%
-h |
"-?" |
-help {
printf("usage is: %s [ -help | -h | -? ] [ -verbose | -v ] [ (-file | -f) filename ]\n", prog_name);
}
-v |
-verbose {
printf("verbose mode is on\n"); verbose=1;
}
%%
int main(int argc, char **argv) {
prog_name = *argv;
yylex();
return 0;
}
我尝试使用以下方法编译它:
$ lex ch2-04.l; cc -ll -o ch2-04 lex.yy.c
ld: error: duplicate symbol: main
>>> defined at libmain.c:29 (/usr/src/contrib/flex/src/libmain.c:29)
>>> libmain.o:(main) in archive /usr/lib/libl.a
>>> defined at lex.yy.c
>>> /tmp/lex-f8aca4.o:(.text+0x1D80)
cc: error: linker command failed with exit code 1 (use -v to see invocation)
为什么 main 被报告为已经定义的? 这本书提到了 AT&T lex 版本并使用 K&R C,所以我确实理解 lex 的实现可能存在差异,并且这本书可能引用了旧的 lex 实现。
我目前在 FreeBSD 中使用提供的 lex 版本。
不要使用
-ll
,因为 lex 库包含 main()
函数实现,或者将其放在已提供 main()
例程之后(如您在 lex.yy.c
中提供的那样),因此 lex 的主模块库不包含在链接中。最好的方法是将库放在最后,这样只有具有未定义引用的模块才会链接到程序中。
改变
lex ch2-04.l; cc -ll -o ch2-04 lex.yy.c
进入
lex ch2-04.l; cc -o ch2-04 lex.yy.c -ll
一切都会顺利。
解释: 当链接器看到
-ll
函数时,它已经有一个对 main()
的未解析引用,该引用来自通常首先向编译器指定的 C 运行时环境。所以它包含了Lex库提供的main()
函数。当您链接文件 lex.yy.c
时,会提供 main()
的第二个版本(这次是您在 lex 源中提供的版本)与之前已链接的版本冲突。