CMake:MacOS上的动态链接资源的运行时错误(dyld:库未加载) [英] CMake: Run-time error (dyld: Library not loaded) for dynamically linked resources on MacOS

查看:172
本文介绍了CMake:MacOS上的动态链接资源的运行时错误(dyld:库未加载)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在MacOS上,我在运行时依赖于动态链接资源的CMake项目遇到链接问题-但仅在安装该项目之后!当我只安装二进制文件而不安装它时,不会发生此问题.

On MacOS, I get linking problems at runtime for a CMake project that depends on dynamically linked resources – but only after installing the project! The problem does not occur when I only build the binary without installing it.

$ ./testapp
Hello world!
$ $INSTALLDIR/testapp
dyld: Library not loaded: @rpath/libvtkDomainsChemistryOpenGL2-7.1.1.dylib
  Referenced from: /Users/normanius/workspace/installdir/testapp
  Reason: image not found
[1]    76964 trace trap  /Users/normanius/workspace/installdir/testapp   

最小示例

我能够以由CMakeLists.txtmain.cpp组成的最小设置重现该问题.我链接到的库称为 VTK (v7.1.1),该库是使用共享库构建的(请参见以获得更多详细信息).

Minimum example

I am able to reproduce the problem in a minimal setup consisting of CMakeLists.txt and main.cpp. The library I am linking to is called VTK (v7.1.1) which has been built with shared libs (see below for further details).

# CMakeLists.txt
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(test)

# Test application.
add_executable(testapp
               main.cpp)

# Find vtk (library that has to be linked to dynamically).
find_package(VTK REQUIRED)
include(${VTK_USE_FILE})
target_link_libraries(testapp ${VTK_LIBRARIES}) # <---- this causes the problem

# Install instructions.
install(TARGETS testapp DESTINATION "${CMAKE_INSTALL_PREFIX}")

main.cpp甚至没有使用任何VTK对象.

The main.cpp not even makes use of any VTK objects.

// main.cpp
#include <iostream>

int main (int argc, char* argv[])
{
    std::cout << "Hello world!" << std::endl;
    return 0;
}

我使用以下命令构建项目.我设置的标志CMAKE_PREFIX_PATH向CMake提供了有关在哪里可以找到VTK库的提示.

I build the project with the following commands. The flag CMAKE_PREFIX_PATH I set to give CMake a hint about where to find the VTK library.

$ INSTALLDIR="path/to/installation"
$ mkdir build && cd build
$ cmake .. -DCMAKE_PREFIX_PATH="$DEVPATH/lib/vtk/cmake" \
           -DCMAKE_BUILD_TYPE=Release \
           -DCMAKE_INSTALL_PREFIX="$INSTALLDIR" 
$ make
$ make install

在build文件夹中执行testapp时,一切看起来都很好:

When executing the testapp in the build folder, everything looks fine:

$ ./testapp
Hello world!
$ cp testapp $INSTALLDIR/testapp
$ $INSTALLDIR/testapp
Hello world!

但是,如果我在INSTALLDIR中运行可执行文件,则会收到运行时错误:

However, if I run the executable in the INSTALLDIR I get a run-time error:

$ $INSTALLDIR/testapp
dyld: Library not loaded: @rpath/libvtkDomainsChemistryOpenGL2-7.1.1.dylib
  Referenced from: /Users/normanius/workspace/installdir/testapp
  Reason: image not found
[1]    76964 trace trap  /Users/normanius/workspace/installdir/testapp    

自然地,如果我删除了CMakeLists.txt中的target_link_libraries()指令,问题就消失了.

Naturally, the problem goes away if I remove the target_link_libraries() instruction in the CMakeLists.txt.

那么在安装CMake项目时究竟发生了什么?我的情况出了什么问题?我测试了不同的CMake版本(3.5、3.9和3.10)-但行为是相同的.

So what exactly happens when installing a CMake project? And what goes wrong in my case? I tested different CMake versions (3.5, 3.9 and 3.10) - but the behaviour is the same.

显然,该示例未正确设置MacOS上的RPATH机制.

Apparently, the RPATH mechanism on MacOS is not properly set up for the example.

这是testapp二进制文件的链接结构的摘录:

This is an excerpt of the linking structure of the testapp binary:

$ otool -L testapp
testapp:
    @rpath/libvtkDomainsChemistryOpenGL2-7.1.1.dylib (compatibility version 0.0.0, current version 0.0.0)
    @rpath/libvtkFiltersFlowPaths-7.1.1.dylib (compatibility version 0.0.0, current version 0.0.0)
    @rpath/libvtkFiltersGeneric-7.1.1.dylib (compatibility version 0.0.0, current version 0.0.0)
    @rpath/libvtkFiltersHyperTree-7.1.1.dylib (compatibility version 0.0.0, current version 0.0.0)
...

因为它可能在构建VTK库(另一个CMake项目)的过程中发挥了作用:为了获得python支持,必须设置项目标志VTK_WRAP_PYTHON=ONBUILD_SHARED_LIBS=ON.安装前缀设置为CMAKE_INSTALL_PREFIX="$VTK_INSTALL_DIR".为了确保在运行时找到资源,必须另外通过CMAKE_MACOSX_RPATH=ONCMAKE_INSTALL_RPATH="$VTK_INSTALL_DIR/lib"启用RPATH支持.

Because it may play a role how the VTK library (another CMake project) was built: For python support, one has to set the project flags VTK_WRAP_PYTHON=ON and BUILD_SHARED_LIBS=ON. The installation prefix was set to CMAKE_INSTALL_PREFIX="$VTK_INSTALL_DIR". To make sure that the resources are found at runtime, one has to additionally enable RPATH support via CMAKE_MACOSX_RPATH=ON and CMAKE_INSTALL_RPATH="$VTK_INSTALL_DIR/lib".

我在概念上犯了什么错误?使用make install安装项目时会发生什么? CMake可以解决此问题吗?还是仅与VTK以及共享库的构建方式有关?

What do I conceptually get wrong? What happens when installing the project with make install? Can this problem be solved within CMake? Or is it related only to VTK and how the shared libs were built?

推荐答案

CMake在运行make install时更改所有已安装目标的RPATH.

CMake changes the RPATH for all installed targets upon running make install.

想象一下,在同一个CMake项目中同时构建共享库和可执行文件.为了能够运行可执行文件,它必须能够在运行时动态加载共享库.因此,默认情况下,CMake将完整(绝对)路径添加到可执行文件的rpath中,该路径是构建树中动态库的全部路径.这对于开发非常方便,因为我们可以直接从构建树中运行可执行文件,但是我们可能不希望以这种方式发布可执行文件.

Imagine building both a shared library and an executable as part of the same CMake project. In order to be able to run the executable, it has to be able to dynamically load the shared library at runtime. Therefore, CMake by default adds the full (absolute) path to the dynamic library in the build tree to the executable's rpath. This is very convenient for developing, as we can run the executable straight from the build tree, but we probably would not want to ship the executable that way.

这就是为什么CMake在安装时会将rpath更改为仅包含 portable 路径(即,删除指向构建树的条目)的原因.也就是说,除非将共享库放入系统默认位置之一,否则可执行文件在安装后将不再找到.

That's why CMake will change the rpath upon install to only contain portable paths (ie. remove the entry pointing to the build tree). That is, unless you put your shared library into one of the system default locations, the executable won't find it anymore after installing.

CMake确实允许您指定安装rpath,该安装rpath将用您指定的r替换已删除的构建树条目.请参见 INSTALL_RPATH INSTALL_RPATH_USE_LINK_PATH 目标属性以获取详细信息.

CMake does allow you though to specify an install rpath that will replace the removed build tree entry with your specified one. See the INSTALL_RPATH and INSTALL_RPATH_USE_LINK_PATH target properties for details.

由于所有这些rpath内容都是100%与平台相关的,因此OSX带有自己的特殊规则.可以在(很遗憾,但已过时) CMake Wiki :

Since all of this rpath stuff is 100% platform-dependent, OSX comes with its own, special rules. A pretty comprehensive explanation can be found on the (unfortunately rather outdated) CMake wiki:

与其他UNIX不同,Darwin链接器dyld定位依赖 动态库,使用每个dylib的完整路径.例如,在 可执行文件"foo",记录的完整路径是以下文件的安装名称: 每个依赖的dylib.并且库"/usr/lib/libSystem.dylib"具有 由"otool"指定的"/usr/lib/libSystem.B.dylib"安装名称 -D.当链接到" foo时," foo对"/usr/lib/libSystem.B.dylib具有依赖关系.可以通过" otool看到此依赖关系 -L foo".对于可重定位的二进制文件,可以使用@ executable_path,@ loader_path和@rpath.在"foo"示例中,@ executable_path 和@loader_path代替"foo"的位置. @rpath是 用"foo"中的RPATH替换以找到依赖的dylib.因此 RPATH机制发挥作用.链接器将搜索 @ rpath/依存关系的顺序如下:

Unlike other UNIXes, the Darwin linker, dyld, locates dependent dynamic libraries using the full path to each dylib. For example, in an executable "foo", the full paths recorded are the install names for each dependent dylib. And the library "/usr/lib/libSystem.dylib" has an install name of "/usr/lib/libSystem.B.dylib" as given by "otool -D". When linked into "foo", "foo" has a dependency on "/usr/lib/libSystem.B.dylib". This dependency can be seen with "otool -L foo". For relocatable binaries, @executable_path, @loader_path and @rpath are available to use. In the "foo" example, @executable_path and @loader_path are substituted for the location of "foo". @rpath is substituted with the RPATHs in "foo" to locate dependent dylibs. Thus the RPATH mechanism comes into play. The linker will search for @rpath/ dependencies in the following order:

  • DYLD_LIBRARY_PATH-一个 环境变量,其中包含目录列表
  • RPATH-列表 链接到可执行文件的目录.这些可以包含 @loader_path和@executable_path.
  • 内置目录-/lib/usr/lib
  • DYLD_FALLBACK_LIBRARY_PATH-一个环境变量,其中包含一个 目录列表
  • DYLD_LIBRARY_PATH - an environment variable which holds a list of directories
  • RPATH - a list of directories which is linked into the executable. These can contain @loader_path and @executable_path.
  • builtin directories - /lib /usr/lib
  • DYLD_FALLBACK_LIBRARY_PATH - an environment variable which holds a list of directories

您应该能够通过调整各自的目标属性来解决此问题,但这很不明智,而且做起来很痛苦.

You should be able to solve this by tuning the respective target properties, but it is rather fiddly and can be quite a pain to get right.

这篇关于CMake:MacOS上的动态链接资源的运行时错误(dyld:库未加载)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆