【问题标题】:linking an executable against a shared library将可执行文件链接到共享库
【发布时间】:2023-03-15 22:11:01
【问题描述】:

我有一个基本问题,我无法找到解决方案。 假设我构建了一个共享库toto,由以下头文件和源文件组成:

toto.h

void print();

toto.cpp

#include <iostream>
#include "toto.h"
void print()
{
std::cout<<"WHAT A GREAT LIBRARY"<<std::endl;
}

基于这些文件,我使用创建共享库

g++ -fPIC -shared -I. -c toto.cpp -o libtoto.so

接下来,我想在测试文件中使用我新创建的共享库:

test.cpp

#include "toto.h"

int main()
{
    print();
}

为此,我使用

将我的可执行文件链接到共享库

g++ -I. -L. -ltoto test.cpp

我得到了我的a.out 可执行文件。

当我执行ldd a.out 时,我得到以下输出:

linux-vdso.so.1 =>  (0x00007fff322f5000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fb7e7c24000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb7e7865000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fb7e7568000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fb7e7f4d000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fb7e7352000)

我看不到我的可执行文件对toto 共享库的任何依赖。在链接过程中,一切似乎都像我的库已静态绑定到我的可执行文件一样。我可以从任何地方调用a.out 而无需将LD_LIBRARY_PATH 设置为存储我的libtoto.so 的路径,这似乎证实了这一点。真的是这样吗?如果是这样,我在上述命令中遗漏了什么或误解了什么?

仅供参考,此示例在 ubuntu 12.04、g++ 4.6.3 上运行

编辑:

同时我可以发现这段代码产生了一个“正确的” 可执行文件的意义在于ldd 显示了对libtoto 共享库的依赖关系,并且如果不设置LD_LIBRARY_PATH 变量就无法启动可执行文件:

g++ -I ./mydylib/ -fpic -c mydylib/toto.cpp -o mydylib/toto.o
g++ -shared -o mydylib/libtoto.so mydylib/toto.o
g++ -I ./mydylib/ -L ./mydylib/ test.cpp -ltoto -o ldd_correct

虽然这个仍然会产生具有上述功能的“错误”可执行文件:

g++ -I ./mydylib -fpic -shared -c mydylib/toto.cpp -o mydylib/libtoto.so
g++ -I ./mydylib -L ./mydylib test.cpp -ltoto -o ldd_wrong

【问题讨论】:

  • 看看this question。提供的答案是否解决了您的问题?
  • g++ 的参数顺序很重要。 -ltoto 应该放在源文件(例如toto.cpp)和目标文件之后。
  • 感谢大家的帮助,但不幸的是,您的建议都不能解决问题。这很奇怪。
  • 那么,./a.out 会打印消息吗?如果删除.so 并重新运行,会发生什么? (FWIW,在 Redhat Enterprise Linux Server 5.8 ldd 上显示了预期的依赖关系,表明这可能是对 ld 行为的另一个更改,可能是在 Michael 链接到的更改发生时进行的)。

标签: c++ linker g++


【解决方案1】:

我的猜测是因为它是一个如此简单的库,所以它被优化了。更复杂的库仍然会发生这种情况吗?您是否尝试过传递-O0 标志?

我已经尝试过,但无法重现结果 - 我的 ldd 显示

linux-vdso.so.1 =>  (0x00007fffb79fe000)
libtoto.so (0x00007f8a78316000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8a77f2e000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f8a77c2a000)
/lib64/ld-linux-x86-64.so.2 (0x00007f8a7851a000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f8a77924000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f8a7770d000)

在 Ubuntu 14.04 gcc 版本 4.8.2

但是,正如我所料,g++ -I. -L. -ltoto test.cpp 不起作用 - 我不得不运行 g++ -I. -L. test.cpp -ltoto

【讨论】:

  • 我试图链接到boost-date-time,实际上我得到了libboost_date_time.so.1.55.0 出现在我的ldd 呼叫中。但是,使用 -O0 标志编译对我的个人库没有帮助。
  • 有趣。尝试使您自己的库更复杂(将一些复杂代码从其他地方复制粘贴到其中)并查看它是否仍然不在ldd 输出中。如果不是,这意味着可能是由于您链接库的方式。如果它在那里,那么你当前的简单库就是这么简单,它真的被优化了。
【解决方案2】:

我终于找到了问题的原因:

在单个 GCC 步骤中编译和链接我的共享库时,我为我的 toto.cpp 源文件添加了错误的 -c 标志。通过比较以下三种构建模式,您可以看到这似乎破坏了可执行文件的构建:

为共享库构建两个 GCC 步骤

g++ -I. -fpic -c toto.cpp -o toto.o
g++ -shared -o libtoto.so toto.o
g++ -I. -L. test.cpp -ltoto -o ldd_correct

构建共享库的单一 GCC 步骤

g++ -I. -fpic -shared -o libtoto.so toto.cpp
g++ -I. -L. test.cpp -ltoto -o ldd_also_correct

构建共享库的单个 GCC 步骤 --> -c 破坏了一些东西

g++ -I. -fpic -shared -o libtoto.so -c toto.cpp
g++ -I. -L. test.cpp -ltoto -o ldd_wrong

【讨论】:

  • 我的看法:-c 告诉编译器生成一个.o 目标文件,-o libtoto.so 给它一个文件名,因为它不在“.so”中,所以会产生误导内部共享库格式。当-c 也被指定时,似乎-shared 标志被忽略了。因此,您的 -ltoto 最终会找到 libtoto.so 文件,然后将其静态链接,因为这是文件内容所支持的。可惜它没有打印错误消息并退出....
猜你喜欢
  • 2021-06-16
  • 1970-01-01
  • 2015-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-11
  • 2018-06-23
相关资源
最近更新 更多