在 Ubuntu 系统中链接动态库时未定义引用

undefined reference when linking dynamic library in Ubuntu system

我在我的Ubuntu系统中写过这样的代码:

my.h

#include <stdio.h>
int a;
int set(void);

lib.c

#include "my.h"
int set(void) {
  a = 100;
  return 0;
}

main.c

#include "my.h"

int main(void){
  set();
  printf("a = %d\n", a);
  return 0;
}

然后我使用以下命令来构建它们:

gcc -shared -fPIC -o libmy.so -I. lib.c

gcc -L. -lmy -I. -o test main.c

当我构建测试时,我得到错误信息:

main.c:(.text+0x5):undefined reference to 'set'
collect2: error: ld returned 1 exit status

but when i use the same code run in Fedora23 and Fedora24, it works well.

所以我想知道为什么会这样? Ubuntu系统有什么限制吗?

您违反了link年龄惯例之间的差异 Fedora 的 GCC 构建和 Debian/Ubuntu 的 GCC 构建。

当您调用 gcc 来执行 C 可执行文件的 linkage 时,它​​又会调用系统 linker ld,将其传递给您的命令行 linkage 选项并默默地添加到 他们有大量 "boilerplate" linkage 选项是不变的 对于 C 语言 linkages(对于 g++ 和 C++ 语言 linkages 也是如此)。

那些不变的 linkage 选项由您的发行版决定并配置 进入他们的GCC构建。所以它们不是跨发行版不变。

Debian/Ubuntu GCC 默默地将 --as-needed 添加到 linkage 选项 输入文件和库之前的位置。 Fedora 的 GCC 没有。

--as-needed的作用是让linker link成为共享库 它在 linkage 序列 只有 中发现 linker 已经找到一个或多个符号的定义 未定义的引用(即在早期的目标文件或库中 在 link 年龄序列中)。此行为在任何情况下都适用于静态库。 因此 --as-needed 使静态和共享的 linkage 规则相似 图书馆 - 这可能被认为对普通用户有帮助。

此差异是发行版之间的link年龄政策差异。什么 对你来说意味着 link 在 Ubuntu 上成功,你的 linkage 命令行 必须在 之后提及任何库 任何目标文件或依赖的其他库 在上面。如果你在一个命令中是compiling-and-linking,那么你必须 在 之后提及任何库 其对应目标文件的任何源文件 取决于那个图书馆。所以在 ubuntu 上,你的问题命令行应该是:

gcc -I. -o test main.c -L. -lmy

成功。这当然也适用于 Fedora。

如果您有兴趣检查link年龄中隐藏的差异 两个发行版之间的选项你可以通过添加 -Wl,-v 来显示它们 compile-and-link 命令获得详细的 linker 输出。