打包可执行文件、共享库和 Python 绑定未找到库

Packaging executable, shared library, and Python bindings not finding library

我有一个项目,cloudgen, that I would like to add bindings for Python so I can access some of the underlying functions. I have stubbed out the initial work on a branch. Because the main executable is built with cmake, I decided to use scikit-build to manage the build and use pybind11 to deal with the binding (following this example repo)。

当我 运行 pip install . 在虚拟环境中时,一切似乎都按预期工作。我发现可执行文件安装到 <prefix>/bin,库安装到 <prefix>/lib,模块安装到 <prefix>/lib/pythonX.Y/site-packages/cloudgen。事实上,如果我 运行 pip uninstall cloudgen,所有正确的文件都被卸载了。但是,当我开始测试 Python 绑定时,我的问题出现了。我发现两个独立但相关的问题。

四处搜索,我发现 this question which notes I could manipulate LD_LIBRARY_PATH (or equivalently DYLD_LIBRARY_PATH on macOS or PATH on Windows), but that is normally frowned upon. That question references an open issue that refers to including additional build products (which as I said appears to not be my problem) but doesn't address the library path resolution. I also came across this question asking about distributing the build products using scikit-build and this question 直接使用 setuptools。问题或答案均未解决库路径解析问题。

我的问题是:分发包含可执行文件、共享库和 Python 绑定模块并具有路径解析 Just Work™ 的包的正确方法是什么?

一个最小的工作示例有点多,但我 created a gist 来演示行为。

经过更多挖掘(仔细阅读 CMake documentation on RPATH), the correct answer appears to be explicitly setting RPATH on installation. The relevant change to the linked gist 是在创建目标后将以下内容添加到 CMakeLists.txt(改编自链接的 Wiki):

if (SKBUILD)
    find_package(PythonExtensions REQUIRED)
    set(lib_path "${PYTHON_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
else()
    set(lib_path "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}")
endif()
list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${lib_path}" is_system)
if ("${is_system}" STREQUAL "-1")
    set_target_properties(mwe.exe PROPERTIES
        INSTALL_RPATH_USE_LINK_PATH TRUE
        INSTALL_RPATH "${lib_path}")
    # The following is necessary for installation in a virtual
    # environment `python -m pip venv env`
    set_target_properties(_mwe PROPERTIES
        INSTALL_RPATH_USE_LINK_PATH TRUE
        INSTALL_RPATH "${lib_path}")
endif()

这确实需要遵循有关设置 RPATH 的其余详细信息,例如包括(字面上来自链接的 CMake Wiki):

# use, i.e. don't skip the full RPATH for the build tree
set(CMAKE_SKIP_BUILD_RPATH FALSE)

# when building, don't use the install RPATH already
# (but later on when installing)
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)

set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")

# add the automatically determined parts of the RPATH
# which point to directories outside the build tree to the install RPATH
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)

早于 CMakeLists.txt。最终结果是这应该禁用对已安装的可执行文件和 Python 模块的库路径(LD_LIBRARY_PATHDYLD_LIBRARY_PATH 的动态搜索)。