rpath在动态库和可执行文件中进行编码,可帮助链接程序找到所需的共享库。
如果我们有一个可执行文件my_exe,它需要一个共享库shared_lib_1,而shared_lib_1又需要另一个shared_lib_2。
因此,rpaths值为:
文件 | rpath |
---|---|
my_exe | /path/to/shared_lib_1 |
shared_lib_1 | /path/to/shared_lib_2 |
shared_lib_2 |
在Linux中,如果链接器在rpath中找不到库,它将在系统默认路径(LD_LIBRARY_PATH…等)中继续搜索。在OSX中,如果链接器检测到无效的rpath(文件在那里不存在),它将失败。
默认Conan方法
具有共享库的依赖项的使用者项目需要将它们导入可执行文件目录才能运行它:
conanfile.txt
[requires]
poco/1.9.4
[imports]
bin, *.dll -> ./bin # Copies all dll files from packages bin folder to my "bin" folder
lib, *.dylib* -> ./bin # Copies all dylib files from packages lib folder to my "bin" folder
在Windows上,此方法效果很好,将共享库导入包含可执行文件的目录是一个非常常见的过程。
在Linux上,还有另外一个问题,默认情况下动态链接器不在可执行文件目录中,因此您需要调整LD_LIBRARY_PATH环境变量,如下所示:
LD_LIBRARY_PATH=$(pwd) && ./mybin
在OSX上,如果绝对rpaths硬编码在可执行文件或共享库中,并且不存在,则可执行文件将无法运行。 当我们在与生成工件不同的环境中重用软件包时,这是最常见的问题。
因此,对于OSX,柯南,默认情况下,当使用CMake构建库时,将生成没有任何路径的rpath:
文件 | rpath |
---|---|
my_exe | shared_lib_1.dylib |
shared_lib_1.dylib | shared_lib_2.dylib |
shared_lib_2.dylib |
conan_basic_setup()宏将在OSX中设置集合(CMAKE_SKIP_RPATH 1)。
您可以通过将KEEP_RPATHS参数传递给conan_basic_setup宏来跳过此默认行为:
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(KEEP_RPATHS)
add_executable(timer timer.cpp)
target_link_libraries(timer ${CONAN_LIBS})
如果您使用的是自动工具,柯南将不会自动调整rpaths的行为。 如果要遵循此默认行为,则可能需要替换配方中configure或MakeFile生成的文件中的install_name,以不使用$ rpath:
replace_in_file("./configure", r"-install_name \$rpath/", "-install_name ")
不同的方法
您可以按照更适合您的需求的方式调整rpath。
如果您使用的是CMake,请参阅CMake RPATH处理指南。
请记住将KEEP_RPATHS变量传递给conan_basic_setup:
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(KEEP_RPATHS)
然后,例如,可以使用OSX中的@executable_path和Linux中的$ ORIGIN来调整可执行文件的相对路径。 另外,启用CMAKE_BUILD_WITH_INSTALL_RPATH将使用CMAKE_INSTALL_RPATH的RPATH值来构建应用程序,并避免在安装时需要重新链接。
if (APPLE)
set(CMAKE_INSTALL_RPATH "@executable_path/../lib")
else()
set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib")
endif()
set(CMAKE_BUILD_WITH_INSTALL_RPATH ON)
您可以在使用者项目中使用以下import语句:
[requires]
poco/1.9.4
[imports]
bin, *.dll -> ./bin # Copies all dll files from packages bin folder to my "bin" folder
lib, *.dylib* -> ./lib # Copies all dylib files from packages lib folder to my "lib" folder
lib, *.so* -> ./lib # Copies all so files from packages lib folder to my "lib" folder
您的最终应用程序可以遵循以下布局:
bin
|_____ my_executable
|_____ mylib.dll
|
lib
|_____ libmylib.so
|_____ libmylib.dylib
您可以将整个应用程序文件夹移动到任何位置,共享库将被正确定位。