将静态库链接到共享库中?

6

背景:

我想将一些静态库链接到一个共享库中。原因是我希望我的应用程序使用我已经测试过的特定库版本。我不想将静态版本作为共享库与我的应用程序一起发布。我创建了这个示例库和应用程序,以尽可能简化。在链接期间,我希望继续将共享库链接到应用程序。

问题:

为什么我会收到下面列出的错误消息?我做错了什么?也许这不是在Linux上通常的做法,但是是否有可能这样做?这是boost特定的吗?

---- 库

//example.cpp
#include <boost/thread.hpp>
void doit()
{
    boost::thread t1;
}

#build script
g++ -Wall -fPIC -I/usr/include -c example.cpp -o example.o
g++ -shared /usr/lib/libboost_thread.a /usr/lib/libboost_system.a 
    example.o -o libexample.so
#build OK. 

---- 示例应用

//main.cpp
#include <iostream>
void doit();
int main()
{
    std::cout << "main\n";
    doit();
    return 0;
};

#build script.
g++ -Wall -c main.cpp -o main.o
g++ libexample.so main.o -o main

#error message.
libexample.so: undefined reference to `boost::thread::thread()'
libexample.so: undefined reference to `boost::thread::~thread()'
collect2: ld returned 1 exit status

所有源代码位于同一目录下。Boost已安装在/usr/lib和/usr/include中。在ubuntu 10.04机器上使用apt-get安装了版本号为1.40的Boost。

谢谢!


不要这样做:静态库通常包含普通对象成员,而共享库包含位置无关代码。 - Basile Starynkevitch
但是如果我使用-fPIC重新编译静态库,会有帮助吗? - mantler
1个回答

2
我认为最简单的方法是使用--whole-archive链接器开关(有更多关于此主题的SO问题,请参见此处如何在gcc中将静态库链接到动态库)。
缺点是,您的共享库将导出来自Boost静态库的所有符号,如果您在使用Boost(但版本不同或使用不同的开关编译)的应用程序中使用.so,可能会遇到奇怪的问题。
因此,您需要使用版本脚本隐藏从库中导出的内容(请参见如何在共享库中隐藏导出的符号名称,还可以搜索链接器版本脚本),仅保留doit()可见。在您的情况下,这样的版本脚本可能如下所示:
{
global:
    doit*;
local:
    *;
}      

您还需要确保您链接的静态库使用-fPIC编译(如果您没有调整其构建标志,则不太可能),否则在i386上会有性能损失,并且在amd64上可能无法链接。


谢谢,我会尝试一下。我只需要先下载并重新编译boost。 - mantler
这个答案进一步解释了一下:https://dev59.com/MHE85IYBdhLWcg3wtV1T#2649792 - matiu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接