【发布时间】:2020-12-19 06:27:18
【问题描述】:
我有一个静态链接库,其中包含一个全局变量barvar。我可以使用 gcc-10 或 clang(这是在 macOS Catalina 上)毫无问题地编译该库。有趣的是,当我尝试将其链接到使用该库的程序时,两者的行为有所不同。代码如下:
在globvars.h 中,声明了int barvar:
#ifndef H_GLOBVARS_H
#define H_GLOBVARS_H
extern int barvar;
#endif
在globvars.c 中,定义了int barvar:
#include "globvars.h"
int barvar;
在foo.c 中,函数foo 设置并打印barvar:
#include <stdio.h>
#include "globvars.h"
void foo()
{
barvar = 10;
printf("barvar is: %d\n", barvar);
return;
}
这里是test.c,使用该库的程序:
void foo();
int main(int argc, char **argv)
{
foo();
return 0;
}
当我用 gcc-10 编译和链接时,没有问题:
gcc-10 -c foo.c -o foo.o
gcc-10 -c globvars.c -o globvars.o
gcc-10 -c test.c -o test.o
gcc-ar-10 rcs liblinktest.a foo.o globvars.o
gcc -o testlinkrun test2.o -L. -llinktest
当我用clang编译和链接时,我在最后一步得到一个未定义的符号错误:
cc -c foo.c -o foo.o
cc -c globvars.c -o globvars.o
cc -c test.c -o test.o
ar rcs liblinktest.a foo.o globvars.o
cc -o testlinkrun test2.o -L. -llinktest
有错误:
Undefined symbols for architecture x86_64:
"_barvar", referenced from:
_foo in liblinktest.a(foo.o)
有什么想法吗?有趣的是,似乎必须使用 gcc-10 完成的唯一步骤是编译 globvars.c。我可以在所有其他步骤中使用 clang 和 clang 链接器,一切都很好。 clang 是否有可能优化掉globvars.c 中的所有变量?我怎样才能防止这种情况发生?
【问题讨论】:
-
您查看导出的符号了吗?是否自动添加下划线前缀可能会有所不同。
-
显示的命令使用目标文件作为链接的输入,
test2.o,这不是任何先前命令的输出。您是否将错误的文件链接到程序中? -
int barvar;为barvar创建一个暂定定义,编译器和链接器将其视为“通用符号”。看起来链接器没有从库中获取通用符号来满足对它的未定义引用。我不知道这是什么原因。一种解决方法是将int barvar;更改为int barvar = 0;以使其成为常规定义。 -
@EricPostpischil 就是这样;
int barvar = 0或使用-fno-common编译修复它。我知道从 gcc-9 到 gcc-10 的默认行为从-fcommon更改为-fno-common;我可能会看到 gcc-9 是否以类似于 clang 的方式失败。如果我有代表,我会支持你的评论!谢谢!