打包可执行文件、共享库和 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 绑定时,我的问题出现了。我发现两个独立但相关的问题。
- 如果我安装到 Anaconda 环境中,模块能够解析共享库的路径并通过测试,但可执行文件不解析库的路径。
- 另一方面,如果我使用
python -m venv
安装到虚拟环境中,模块和可执行文件都无法解析共享库的路径。
四处搜索,我发现 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_PATH
或 DYLD_LIBRARY_PATH
的动态搜索)。
我有一个项目,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 绑定时,我的问题出现了。我发现两个独立但相关的问题。
- 如果我安装到 Anaconda 环境中,模块能够解析共享库的路径并通过测试,但可执行文件不解析库的路径。
- 另一方面,如果我使用
python -m venv
安装到虚拟环境中,模块和可执行文件都无法解析共享库的路径。
四处搜索,我发现 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_PATH
或 DYLD_LIBRARY_PATH
的动态搜索)。