【问题标题】:gcc - A static library with undefined symbols?gcc - 带有未定义符号的静态库?
【发布时间】:2016-02-24 09:05:37
【问题描述】:

我正在尝试使用静态库构建项​​目,以便即使未安装库也可以使用二进制文件。但是,当我尝试这样做时,会收到很多关于未定义符号的错误。

查看库,我发现它有大量未定义的符号,即使它是 .a 静态库:

nm - u /usr/local/lib/libthis.a
....
U EVP_DigestFinal_ex
U EVP_DigestInit_ex
U EVP_DigestUpdate
U EVP_MD_CTX_cleanup
U EVP_MD_CTX_init

那些似乎来自openssl;其他的似乎来自 libbzip2;等等

问题: 1. 为什么静态(.a)库依赖于非静态编译的共享对象(例如 libopenssl)? 2. 我该如何解决这个问题?尝试手动添加 -lssl 似乎不起作用。如何让二进制文件编译并且没有外部依赖?

【问题讨论】:

  • 静态库应该有很多未定义的符号(它们毕竟只是一堆 .o 文件,没有任何额外的东西)。这些不是对共享对象的依赖,它们只是普通的未定义符号。当您构建最终的可执行文件时,您将不得不与大量库链接以解析所有符号。

标签: gcc linker shared-libraries static-libraries static-linking


【解决方案1】:

为什么静态 (.a) 库依赖于非静态编译的共享对象(例如 libopenssl)?

您可以构建的每个静态库都会有未解析的符号,例如

int my_open_for_read(const char *filename)
{
  return open(filename, O_RDONLY);  // unresolved reference to open
}

正如 Marc Glisse 指出的,这是一个普通的未解析符号,不是依赖于 libc.so

  1. 我该如何解决这个问题?

这里没有要解决的问题。链接二进制文件时,您可以决定哪些库要静态链接,哪些要动态链接。

尝试手动添加 -lssl 似乎不起作用。

这应该可行:

gcc main.o -lthis -lssl

可能你做了类似的事情

gcc main.o -lssl -lthis

这是错误的:链接行matters上的库顺序。

如何让二进制文件编译并且没有外部依赖?

大多数操作系统都支持使用完全静态的二进制文件。一般来说,这应该是您的目标:它使 less 可移植二进制文件,强烈建议不要使用它们。

如果您确实想生成完全静态的二进制文件,请将其与-static 标志链接。

你为什么说全静态不那么便携?

因为they are

如果用户没有完全相同的库版本,则二进制文件将不能与共享库一起移植,但可以与静态库一起移植。

这是不正确的:大多数共享库都支持向后兼容性,例如libc.so.6 2.22 版将愉快地运行与 10 年前的 2.3.6 版链接的可执行文件。

如果你使用 ldd firefox

你需要注意你在做什么:

file -L `which /usr/bin/firefox`
/usr/bin/firefox: POSIX shell script, ASCII text executable

如果您查看 shell 脚本,您会发现它调用了/usr/lib/firefox/firefox,并且该二进制文件是动态链接的:

ldd /usr/lib/firefox/firefox
    linux-vdso.so.1 =>  (0x00007ffca278d000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f511731b000)
    libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f5117117000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f5116e13000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f5116b0d000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f51168f7000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5116532000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f5117757000)

【讨论】:

  • 谢谢。你为什么说全静态是less可移植的?由于 Linux 使用 .so 而不是 DLL,如果用户没有完全相同的 lib 构建,则二进制文件将无法与共享库一起移植,但可以与静态一起移植。例如,如果你使用ldd firefox,你会看到它是完全静态的——你怎么能在 Linux 上拥有一个可移植的二进制文件?
  • 不错的更新,尤其是抓到了 firefox 脚本!但是 libs ldd 显示的是所有系统库,我知道 a) 不能是静态的并且 b) 通常是向后兼容的。我的观点仍然适用于非系统库(例如 zlib ssl 和更多);请注意,Firefox 使用这些静态,我认为这是唯一的便携方式
  • @SRobertJames 我只反对完全静态的二进制文件。只要您继续动态使用系统库,静态链接非系统库就可以了。对您的问题的字面阅读:“如何......没有外部依赖”意味着完全静态链接。
  • @SRobertJames 您关于使用非静态系统库的观点非常好。
猜你喜欢
  • 2015-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-18
  • 2016-09-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多