【问题标题】:What's the order for gcc to link unresolved symbol in static librarygcc在静态库中链接未解析符号的顺序是什么
【发布时间】:2013-09-04 12:11:53
【问题描述】:

在调试函数符号冲突问题时,我发现 gcc 的一个奇怪行为我无法理解,通过以下示例代码说明:

main.c

#include <stdio.h>
int  main()
{
   b();
   a();
}

交流

#include <stdio.h>
void  a(void)
{
   printf("func a in a\n");
}

b.c

#include <stdio.h>

void a()
{
   printf("func a in b\n");
}
void b()
{
  printf( "func b try to call a  \n");
  a();
}

编译:

gcc -c a.c
gcc -c b.c
ar -cr liba.a a.o
ar -cr libb.a b.o
gcc main.c liba.a libb.a

执行:

./a.out
func b try to call a  
func a in b
func a in b   

我的问题是:

  • 为什么在main函数中调用函数aa in b.c而不是a in a.c
  • 更改库顺序后:gcc main.c libb.a liba.a,结果是一样的。为什么?
  • 为什么在这种情况下链接器不报告符号冲突?

【问题讨论】:

  • 试试 gcc -c main.c liba.a libb.a
  • @LidongGuo 我试过了,请看我的第二个问题。
  • 您在main.c 编译命令行中看到-c 了吗?你没有链接你的程序,你只是编译 main.c。如果您还要链接,请在最终编译中丢失-c。正如您所写的那样,您的命令甚至不会生成 a.out,所以我对您如何运行 anything 感到有些困惑。
  • @WhozCraig 这是一个打字错误,我修复它。

标签: c gcc shared-libraries unix-ar


【解决方案1】:

在传递给链接器的选项中,按照目标文件出现的顺序(从左到右)搜索要解析的符号。

假设已运行以下内容以准备链接:

gcc -c main.c
gcc -c a.c
gcc -c b.c
ar -cr liba.a a.o
ar -cr libb.a b.o

那么这个

gcc -o main main.o liba.a libb.a

会产生:

libb.a(b.o): In function `a':
b.c:(.text+0x0): multiple definition of `a'
liba.a(a.o):a.c:(.text+0x0): first defined here
collect2: ld returned 1 exit status

链接器做了以下事情:

main.o 需要 a()b ()。首先搜索liba:找到a(),没有找到b()。所以其次搜索libb。找到了b(),但也找到了另一个 a(),导致上面显示的链接器错误。

如果这样做:

gcc -o main main.o libb.a liba.a

没有给出错误并创建main

链接器做了以下事情:

main.o 需要 a()b ()。首先搜索libb:找到a()b()。因为没有什么要解决的了 libb liba 甚至没有被查看/查看。

在后一种情况下,程序 (main's) 的输出是:

func b try to call a  
func a in b
func a in b

对于main.oliba.alibb.a 的所有其他可能排列,链接器将执行/显示的操作留给读者作为练习。 ;-)

【讨论】:

  • 但是我需要澄清你答案的第一部分。你可以看到我在 main.c 中首先调用了 b,所以 "gcc -o main main.o liba.a libb.a" 不要报告我的情况下的任何错误,我在 Mac os 上使用了 llvm-gcc-4.2。
  • @James.xu:在翻译单元中调用函数的顺序(这里:main.c)根本不影响链接。链接器对哪个单元需要和/或提供哪个功能感兴趣。
  • 在您的系统上,从我的答案链接对 gcc 的最终调用的两种变体都没有错误?
  • 是的。没有报错。如果我改变函数顺序,先调用a,报冲突错误。
  • 第二种情况的解释现在读作“因为没有什么要解决的了不再有 liba 甚至没有被查看/进入”。
【解决方案2】:

您没有在main.c 中包含ab 函数声明。如果这样做,在将其传递给链接器之前,您会从编译器获得多个声明错误。你一定是在main.c做错了什么。

【讨论】:

  • 是的,我没有包含 a 和 b 函数声明,但是编译器没有报错。其实不影响结果,我可以用extern来声明外部函数。
  • @James.xu:如果你在 (-Wall) 上运行 gcc 并带有(大多数)警告,它会声明 a()b() 的隐式声明,以及缺少的返回价值。
猜你喜欢
  • 2016-01-19
  • 2017-04-13
  • 1970-01-01
  • 1970-01-01
  • 2020-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多