c-当链接到包含全局变量的静态库时,clang和gcc-10之间的行为不同



我有一个静态链接的库,其中包含一个全局变量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: %dn", 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中的所有变量?我该如何防止这种情况发生?

正如@EricPostpischil在本评论中所观察到的,问题是clang默认将barvar视为一个公共符号。将int barvar;更改为int barvar = 0;,或使用-fno-common进行编译,都可以解决此问题。

从gcc-10开始,gcc的默认行为是-fno-common,而不是-fcommon

最新更新