【问题标题】:C++ Statically linked shared libraryC++ 静态链接共享库
【发布时间】:2011-07-09 11:13:36
【问题描述】:

我有一个共享库被我无法控制的另一个应用程序使用,它需要 *.so 对象。我的库使用了需要与其静态链接的 sqlite3(我绝对需要一个独立的二进制文件)。

当我尝试编译和链接我的库时:

-fpic -flto -pthread -m64
-flto -static -shared

我最终得到以下错误:

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

recompile with -fPIC 与什么有关?我的代码还是 CRT?

我已经尝试使用 -fPIC 编译我的对象,结果相同。

谢谢。

编辑:

问题似乎与 SQLite3 无关。

我编写了一个简单的单行无操作库,它可以像这样编译和链接:

g++ -c -fPIC -o bar.o bar.cpp
g++ -shared -o bar.so bar.o

但不是这样:

g++ -c -fPIC -o bar.o bar.cpp
g++ -static -shared -o bar.so bar.o

问题似乎与 CRT (crtbeginT.o) 有关。我应该重新编译 GCC --with-pic 还是什么?

【问题讨论】:

  • 这有点令人困惑。您是想将您的库链接到静态 sqlite 库,还是尝试做其他事情?
  • PIC = 位置无关代码,共享库需要(我猜在大多数架构上)
  • @nos 尝试将我的共享库与 sqlite3.a 链接
  • @Petr 在这种情况下,您至少应该删除 -static 标志,如果您也有共享库版本的 sqlite,请使用 -Wl,-Bstatic -lsqlite3 -Wl,-Bdynamic 使其获取静态版本libsqlite.
  • @nos 谢谢。 -Bstatic 似乎有效。真的不知道为什么,因为它应该与 -static 相同(至少根据手册)。如果你愿意,你可以写一个答案,这样我就可以标记它已解决。

标签: c++ static-libraries crt dynamic-library


【解决方案1】:

创建共享库时不应使用-static 标志,它用于创建静态链接的可执行文件。

如果您只有库的静态版本,则可以使用 -lsqlite3 将其链接。但如果同时存在动态版本 (.so) 和静态版本,则链接器将更喜欢动态版本。

要指示链接器选择静态链接器,请给链接器-Bstatic 标志,并使用-Bdynamic 使其切换回其他内容的动态链接(如libc 和动态运行时支持)。也就是说,您使用标志:

 -Wl,-Bstatic -lsqlite3 -Wl,-Bdynamic 

或者,您可以指定 .a 文件的完整路径,例如/usr/lib/libsqlite3.a 而不是任何编译器/链接器标志。

使用 GNU ld,您还可以使用 -l:libsqlite3.a 代替 -lsqlite3。这将强制使用库文件libsqlite3.a,而不是链接器默认使用的libsqlite3.so

记得确保 .a 文件已使用 -fpic 标志编译,否则您通常无法将其嵌入到共享库中。

【讨论】:

  • 我在这里遇到了同样的问题,不知道如何编译不会动态链接到 libc/libstdc++ 等依赖于分发的人员的共享库 - -Bstatic 确实提供动态链接的共享库。奇妙的是,在 Windows 上使用 MinGW,我可以将 .dll 与 -static 正确链接(仅取决于 Windows dll,而不是 mingw 的)。有没有办法静态链接.so???
  • 没有。 unix 共享库的工作方式与 Windows dll 非常不同。
  • -l:libsqlite3.a 技巧也适用于 eclipse cdt。在 Properties->C/C++ Build->Settings->GCC C Linker->Libraries 中输入 :libsqlite3.a,构建将静态链接到库。
  • 完整路径通常可以在没有任何废话的情况下完成技巧,而旧版本的ld 似乎一直失败。尽管用-L 将它指向正确的文件夹并在链接器命令行上使用-Bstatic -lname -Bdynamic,但我无法让它在FreeBSD 8.4 上与古老的ld 一起工作。但是,完整路径始终有效。
【解决方案2】:

任何会以某种方式进入动态库的代码都应该是可重定位的。这意味着与您的.so 链接的所有内容,无论是静态的还是动态的,都应该使用-fPIC 进行编译。具体来说,静态sqlite库也应该用-fPIC编译。

PIC 含义的详细信息在这里:http://en.wikipedia.org/wiki/Position-independent_code

【讨论】:

  • 发布您执行的完整链接命令,以便我们进一步分析)
【解决方案3】:

我遇到了同样的问题。显然 -static 与 -Bstatic 不同。我切换到 -Bstatic 并且一切正常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-17
    • 2012-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多