使用运行路径进行 C++ 辅助依赖项解析
c++ secondary dependency resolution with runpath
我有以下问题:
我正在尝试使用默认的 gnu 编译器 (gcc-7( 和可用的链接器版本在 Ubuntu18 上构建软件。
现在我们有了这样的情况,可执行文件可以链接一个共享库,而共享库又链接了另一个共享库。因此,可执行文件具有辅助依赖项。但次要依赖项仅从 rpath 中获取,而不是从运行路径中获取。因此,即使将辅助依赖项放置在可执行文件的 runpath 文件夹中,也不会找到它。
当将googletest与cmake结合使用时,发现了这个问题。在那里,由于找不到辅助依赖项,因此无法编译测试。因此,设置LD_LIBRARY_PATH
可能不是一种选择,或者至少会使一切复杂化很多。
以下是 Ubuntu18 系统上 gcc-7 出现问题的示例(但在 Ubuntu16 系统上使用 gcc-5 工作正常(:
中学.hpp
#include <string>
class World{
public:
std::string world();
};
次要的.cpp
#include "secondary.hpp"
std::string World::world(){
return "world";
}
主要.hpp
#include <string>
class Hello{
public:
std::string helloWorld();
};
主要.cpp
#include "primary.hpp"
#include "secondary.hpp"
#include <sstream>
std::string Hello::helloWorld(){
std::stringstream strm;
World world;
strm << "hello ";
strm << world.world();
strm << "!";
return strm.str();
}
并像这样编译这两个库
mkdir build
cd build
gcc -shared -o libsecondary.so -fPIC ../secondary.cpp
gcc -shared -o libprimary.so -fPIC ../primary.cpp -lsecondary -L$(pwd)
如果我现在从以下文件构建可执行文件
主.cpp
#include "primary.hpp"
#include <iostream>
int main(int argc, char** argv){
Hello hello;
std::cout << hello.helloWorld() << std::endl;
}
通过在新的构建目录中执行以下操作(与上一个目录并行(
cd ..
mkdir build_app
cd build_app
gcc -o app ../main.cpp -L../build -lstdc++ -lsecondary -lprimary -Wl,-rpath=$(pwd)/../build
如果我现在这样做ldd app
我看到,找不到那个libsecondary.so
linux-vdso.so.1 (0x00007fff0cf8c000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f9e86fe7000)
libprimary.so => <some_path>/libprimary.so (0x00007f9e86de5000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f9e86bcd000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9e867dc000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9e8643e000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9e87573000)
libsecondary.so => not found
并且应用程序的运行路径是(通过运行readelf -d app
(
Dynamic section at offset 0x1d40 contains 31 entries:
Tag Type Name/Value
0x0000000000000001 (NEEDED) Shared library: [libstdc++.so.6]
0x0000000000000001 (NEEDED) Shared library: [libprimary.so]
0x0000000000000001 (NEEDED) Shared library: [libgcc_s.so.1]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x000000000000001d (RUNPATH) Library runpath:[<some_path>/build]
问题是,ld
为什么不把libsecondary.so
从app
的跑道上带走?libprimary.so
和libsecondary.so
都放在同一个文件夹中,但只能找到libprimary.so
。
该问题的一个解决方案是使用--disable-new-dtags
进行编译,它将使用 rpath 而不是 runpath,并且是 Ubuntu16 上 gcc-5 的默认版本。但是,rpath 的使用似乎已从 ld 中弃用。
那么,将运行路径与辅助依赖项一起使用的正确方法是什么?
libprimary
负责加载libsecondary
,而不是app
。这意味着app
的DT_RUNPATH条目不适用。
由于您可以控制所有库,因此您也可以向编译语句添加-Wl,-rpath=...
以进行libprimary
和libsecondary
。
- 如何从C++中的依赖类型中获得它所依赖的类型
- 将--whole archive链接器选项与CMake和具有其他库依赖项的库一起使用
- 将依赖名称显式标记为类型名和模板的奇怪之处
- 在 Windows 上,是否可以让 dll 在不使用 PATH 环境变量的情况下在另一个文件夹中查找依赖项?
- C++GTKMM gui循环依赖关系
- 通过ccmake在cmake中缓存依赖选项
- 当基类是依赖类型时,这是一个缺陷吗
- 从不同的附加依赖项中识别等同命名的函数
- 如何在 CMake 中对目标依赖项进行分组?
- 是否可以依赖函数范围的静态变量来执行程序关闭期间调用的方法?
- 为什么构建目录中新构建的共享库与安装目录中的副本具有不同的依赖项集?
- VS 2015 链接错误 无法构建依赖于 libcurl 的项目
- 通过依赖类型使用非类型模板参数的单类型模板参数类模板的部分专用化
- 为什么内存屏障依赖于变量?
- node-gyp 的先有鸡还是先有蛋的问题:指向依赖项中的头文件
- 反转依赖于 end() 的迭代器
- GCC,CMake,预编译标头和维护依赖项
- 使用 'typename' 关键字将非类型视为依赖上下文中的类型
- 使用 Git 处理 C++ Visual Studio 2019 解决方案的外部依赖项源代码管理的最佳方法是什么?
- 为什么依赖模板类型在部分专用化中不可推导?