【问题标题】:Self-contained shared library自包含共享库
【发布时间】:2016-02-22 22:09:36
【问题描述】:

我需要创建一个共享库,它自己的依赖项(包括 libc/libstdc++)必须静态链接到它以生成一个独立的二进制文件。我试着这样做

g++ -c -fpic -o foo.o foo.cpp
g++ -static -shared -o foo.so foo.o

失败:

/usr/bin/ld.bfd.real: /usr/local/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/crtbeginT.o: relocation R_X86_64_32 against `__TMC_END__' can not be      used when making a shared object; recompile with -fPIC
/usr/local/lib/gcc/x86_64-unknown-linux-gnu/5.2.0/crtbeginT.o: could not read symbols: Bad value
collect2: error: ld returned 1 exit status

谁能告诉我我做错了什么?

【问题讨论】:

  • -fPIC 可能区分大小写。不知道是不是这个问题。
  • @Simple:我尝试使用-fPIC,但仍然遇到同样的错误。
  • 试试-static-libstdc++。有关相关链接选项,请参阅 gcc.gnu.org/onlinedocs/gcc/Link-Options.html
  • @Simple,如果-fpic 无效,则会出现错误。它区分大小写,但-fpic-fPIC 都是有效选项(某些目标略有不同,请参阅手册)。

标签: c++ shared-libraries static-linking


【解决方案1】:

您可以使用-static-libstdc++ 选项静态链接libstdc++。如果您正在制作动态库,您可能不应该静态链接到libc(或libgcc,如果需要,您可以静态链接到-static-libgcc);您需要选择加载共享库的应用程序的 libc 版本。

可以在GCC manual 中找到控制静态链接的其他选项。您还可以通过将参数传递给链接器(-Wl,<argument>,或直接调用ld)来实现所需的结果。 LD manual 列出了允许的选项。


例子:

我写了以下代码

#include <iostream>

extern "C" void do_something() {
    std::cout << "Doing something!\n";
}

并编译成.o文件如下:

g++ -fPIC -c -o tmp.o tmp.cpp

然后我从中生成了两个共享库。一种带有-static-libstdc++,一种没有:

g++ -shared -o tmp-shared.so tmp.o
g++ -shared -static-libstdc++ -o tmp-static.so tmp.o

为了比较,ldd tmp-shared.so:

linux-vdso.so.1 =>  (0x00007fffc6dfd000)
libstdc++.so.6 => /usr/lib64/libstdc++.so.6 (0x00002b708cb43000)
libm.so.6 => /lib64/libm.so.6 (0x00002b708ce4c000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00002b708d0cf000)
libc.so.6 => /lib64/libc.so.6 (0x00002b708d2dd000)
/lib64/ld-linux-x86-64.so.2 (0x00000035c6c00000)

ldd tmp-static.so:

linux-vdso.so.1 =>  (0x00007fff99bfd000)
libm.so.6 => /lib64/libm.so.6 (0x00002acbec030000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00002acbec2b3000)
libc.so.6 => /lib64/libc.so.6 (0x00002acbec4c1000)
/lib64/ld-linux-x86-64.so.2 (0x00000035c6c00000)

【讨论】:

  • 你还需要-static-libgcc来移除libgcc_s.so.1的依赖。
  • @MaximEgorushkin 当然,如果你想删除依赖。答案现在提到了这一点,尽管通常最好允许从系统中提取libclibgcc(当然,除非目标系统上不存在动态libgcc)。
  • @Andrew:谢谢!你是否也碰巧知道我如何做一个完整的静态链接(包括 libc 和 libm)。我知道这可能不被推荐,但我需要为研究原型这样做。
  • @Andrew libgcc 实现了 C++ 异常,因此如果一个静态链接到 libstdc++ 则意味着 libgcc 也需要静态链接。不过,您对 libc 的看法是正确的。
  • @MaximEgorushkin 你是对的,但是如果允许异常跨越库边界,你必须确保两边的 libgcc 版本相同。最简单的方法是让它在目标系统上动态加载!如果您不跨库边界抛出异常(无论如何这不是一个好主意!),那么您可以静态链接到libgcc。 (或者如果主应用程序也静态链接到相同的libstdc++libgcc)。
【解决方案2】:

我需要创建一个共享库,它自己的依赖项(包括 libc/libstdc++)必须静态链接到它以生成一个独立的二进制文件

要拥有一个独立的二进制文件,您不一定需要静态链接。由于不同的原因,某些库无法编译为静态库。

许多商业应用程序使用$ORIGIN 链接器功能。您可以将所有必需的共享库与可执行文件一起复制到一个目录中,并使用额外的链接器标志链接您的可执行文件。见man ld.so:

$ORIGIN 和 rpath

ld.so 理解字符串$ORIGIN(或等效的${ORIGIN}) rpath 规范(DT_RPATHDT_RUNPATH)表示包含应用程序可执行文件的目录。因此,一个应用程序位于 somedir/app 可以用gcc -Wl,-rpath,'$ORIGIN/../lib' 编译所以 无论如何它都会在 somedir/lib 中找到关联的共享库 其中 somedir 位于目录层次结构中。这有利于 创建不需要的“交钥匙”应用程序 安装到特殊目录,但可以解压到 任何目录,仍然可以找到自己的共享库。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-02
    • 2014-11-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多