C++ 为什么在linux(cmake)中加载共享库时安装的程序出错

C++ 为什么在linux(cmake)中加载共享库时安装的程序出错,c++,linux,cmake,C++,Linux,Cmake,我有一个问题,关于如何在依赖于一些外部库的情况下使用cmake安装构建的可执行程序。假设我的可执行文件是abc,它依赖于两个外部库:lib1.so和lib2.so。这些守则的结构如下: -......... |----bin (lib1.so lib2.so) |----include(lib1.h lib2.h) |----src(main.cpp) 使用以下cmake命令安装可执行程序时: INSTALL(TARGETS ${Exe_Name} RUNTIME DEST

我有一个问题,关于如何在依赖于一些外部库的情况下使用cmake安装构建的可执行程序。假设我的可执行文件是abc,它依赖于两个外部库:lib1.so和lib2.so。这些守则的结构如下:

-.........
  |----bin (lib1.so lib2.so)
  |----include(lib1.h lib2.h)
  |----src(main.cpp)
使用以下cmake命令安装可执行程序时:

INSTALL(TARGETS ${Exe_Name}
    RUNTIME DESTINATION Path to bin
    LIBRARY DESTINATION Path to bin)
我希望可执行程序将与lib1.so和lib2.so位于同一目录中。但是,当我在安装文件夹中执行内置程序时,遇到以下错误:

error while loading shared libraries: lib1 can not open shared object file No such file or directory
如果使用ldd检查可执行文件,则发现lib1.so和lib2.so未找到。在寻找可能的解决方案后,我发现如果我以这种方式调用可执行文件,那么它就起作用了:

LD_LIBRARY_PATH=./ ./my_program_run

然后我的问题是,我如何让我的可执行程序在安装cmake时知道共享库的位置?谢谢

在预定义位置搜索库,其中包括使用ld.so.conf和ld_library_PATH配置的标准库路径。您也可以尝试使用-rpath编译您的应用程序,但某些开发人员不推荐使用它。我建议您创建一个包装器脚本,它将设置LD_LIBRARY_PATH并像这样运行实际应用程序:

应用程序脚本:

#!/bin/sh
dir="`dirname \"$0\"`"
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}"$dir"
exec "$dir/theapp.real" # your real application

应用程序、脚本和库应位于bin/

下的同一位置。在预定义位置搜索库,其中包括使用ld.so.conf和ld_library_PATH配置的标准库路径。您也可以尝试使用-rpath编译您的应用程序,但某些开发人员不推荐使用它。我建议您创建一个包装器脚本,它将设置LD_LIBRARY_PATH并像这样运行实际应用程序:

应用程序脚本:

#!/bin/sh
dir="`dirname \"$0\"`"
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}"$dir"
exec "$dir/theapp.real" # your real application

应用程序、脚本和库应位于bin/

下的同一位置。如果要将应用程序干净地安装到标准linux发行版,则应将支持的共享库安装到标准位置/usr/lib,或者将库位置添加到ld.so配置中,通过创建一个/etc/ld.so.conf.d/myprogram.conf文件,其中包含库所在目录的名称


如果安装是临时的或更特别的,那么设置LD_LIBRARY_路径的脚本是合适的。

如果应用程序要干净地安装到标准linux发行版,那么您应该将支持的共享库安装到标准位置/usr/lib,或者,您应该通过创建包含库所在目录名称的/etc/ld.so.conf.d/myprogram.conf文件,将库位置添加到ld.so配置中


如果安装是临时的或更特别的,那么设置LD_LIBRARY_路径的脚本是合适的。

这最好通过最终可执行文件的RPATH来解决。RPATH是可执行文件本身的硬编码搜索路径,允许使用字符串$ORIGIN,它在运行时扩展到可执行文件的位置。见本参考资料:

CMake在安装时剥离二进制文件的rpath,以避免二进制文件拾取散落在开发树周围的库。但它也提供了一种简单的方法来修改安装路径,正是出于这个原因。以下是简短的答案:

IF(UNIX)
  SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH}:\$ORIGIN/../bin:\$ORIGIN")
ENDIF()
此特定示例附加到现有rpath,并添加了。和../bin到搜索路径,都与二进制文件的位置相关


一些开发人员声称调整二进制文件的RPATH不是一个好主意。在理想情况下,所有库都将位于系统库目录中。但是如果你把这一点发挥到极致,你最终会使用Windows,至少是旧的Windows,其中c:\Windows\system32充满了来自谁知道在哪里的垃圾,可能与其他软件冲突,也可能与其他软件冲突,等等。使用rpath并在一个地方安装所有东西似乎是一个很好的解决方案。

这最好用最终可执行文件的rpath来解决。RPATH是可执行文件本身的硬编码搜索路径,允许使用字符串$ORIGIN,它在运行时扩展到可执行文件的位置。见本参考资料:

CMake在安装时剥离二进制文件的rpath,以避免二进制文件拾取散落在开发树周围的库。但它也提供了一种简单的方法来修改安装路径,正是出于这个原因。以下是简短的答案:

IF(UNIX)
  SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH}:\$ORIGIN/../bin:\$ORIGIN")
ENDIF()
此特定示例附加到现有rpath,并添加了。和../bin到搜索路径,都与二进制文件的位置相关

一些开发人员声称调整二进制文件的RPATH不是一个好主意。在理想情况下,所有库都将位于系统库目录中。但如果你把这一点发挥到极致,你最终会看到Windows——至少是旧版本的Windows,其中c:\Windows\system32充满了来自谁也不知道从哪里来的垃圾,可能会也可能不会与其他版本发生冲突
软件等。使用rpath并在一个地方安装所有东西似乎是一个很好的解决方案。

这是一个解决方案,用于其他人提供的坏程序,也不是从头开始构建软件。这是一个解决方案,用于其他人提供的坏程序,也不是从头开始构建软件。我在回答中忘记了rpath。最好使用DT_运行路径而不是DT_RPATH,因为前向性较低,因此允许LD_LIBRARY_路径重写。见曼恩·尔德,或。我不知道如何在CMake中指定它。我同意DT_运行路径更好。但是CMake没有很好的设置方法,所以DT_RPATH应该适用于大多数情况。根据,CMake_INSTALL_RPATH是一个分号分隔的列表,而上面的冒号用于分隔路径。我会使用:listpappend-CMAKE\u-INSTALL\u-RPATH${CMAKE\u-INSTALL\u-PREFIX}/lib/我在回答中忘记了RPATH。最好使用DT_运行路径而不是DT_RPATH,因为前向性较低,因此允许LD_LIBRARY_路径重写。见曼恩·尔德,或。我不知道如何在CMake中指定它。我同意DT_运行路径更好。但是CMake没有很好的设置方法,所以DT_RPATH应该适用于大多数情况。根据,CMake_INSTALL_RPATH是一个分号分隔的列表,而上面的冒号用于分隔路径。我会使用:listpappend-CMAKE\u-INSTALL\u-RPATH${CMAKE\u-INSTALL\u-PREFIX}/lib/