【问题标题】:Different behavior between clang and gcc-10 when linking to static library containing global variables链接到包含全局变量的静态库时,clang 和 gcc-10 之间的行为不同
【发布时间】: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 的方式失败。如果我有代表,我会支持你的评论!谢谢!

标签: c macos gcc clang


【解决方案1】:

正如@EricPostpischil 在this comment 中观察到的那样,问题在于clang 默认将barvar 视为通用符号。将int barvar; 更改为int barvar = 0;,或者使用-fno-common 进行编译,解决问题。

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

【讨论】:

  • 不过,我想知道链接器不引入满足引用的对象模块的基本原理是什么。也许是更喜欢可能在以后的模块中出现的硬定义,但这意味着一些可能成功的链接(库模块中的暂定/通用定义并且没有以后的定义)失败。
  • @EricPostpischil 我自己对此很好奇。你对我在哪里可以找到答案有什么建议吗?我应该为它提出一个新问题吗? stackoverflow 的老读者,第一次发帖,仍在尝试了解最佳实践。
  • 我认为提出一个问题来询问这种行为的基本原理是合理的。我不能保证选民会同意。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-09-07
  • 2021-07-02
  • 2018-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-23
相关资源
最近更新 更多