TLDR:在python中导入pybind 11模块时,如何链接.so/import依赖项?
我试图构建一个pybind 11模块,它部分依赖于另一个python库的C++部分,在Linux上,我可以使用target_link_libraries
在CMake中链接该库--这不适用于macOS(can't link with bundle (MH_BUNDLE) only dylibs (MH_DYLIB) file
)上的.so库。
当在macOS上导入pybind 11生成的模块而没有在Python中链接时,我得到了一个ImportError: dlopen(/path/to/my_module.cpython-38-darwin.so, 0x0002): symbol not found in flat namespace (__<mangled symbol that is part of the library my module depends on>)
。这可以通过在导入我自己的模块之前在Python中导入依赖本身来防止。
有没有办法链接那个库,或者确保Python在运行import my_module
时,在加载我的二进制文件之前导入依赖项?
我尝试将共享库文件放在一个文件夹中,该文件夹包含__init__.py
,它首先导入依赖项,然后从.so导入*
--但这导致一些导入不再工作(例如,import my_module.my_submodule
失败)。
编辑:一个可行的,但麻烦的,直接的解决方案是添加一个虚拟模块到管道中,也就是说,将原来的my_module
重命名为_my_module
,并创建一个虚拟的my_module
,除了导入依赖项之外什么也不做:
#include <Python.h>
PyMODINIT_FUNC
PyInit_my_module(void)
{
PyImport_ImportModule("the_dependency");
return PyImport_ImportModule("_my_module");
}
1条答案
按热度按时间goucqfw61#
这不是一个理想的解决方案,但似乎是解决import-before-binary问题的最佳方法,同时还保留了以正常情况下相同的方式使用导入模块的能力,这是通过在导入原始模块之前使用一个伪模块导入python依赖项(其中包含相关的C++依赖项.so)来实现的。
假设使用CMake来编译项目,下面是如何完成的。
1.如果模块是为macOS编译的,则有条件地将模块名称设置为_my_module而不是my_module:
1.添加一个使用原始名称的伪模块,然后使用该模块导入依赖项并加载实际模块
1.在你的原始模块中定义一个
PYBIND11_MODULE
,它使用伪名称,这样Python以后就可以正确地导入它(也就是说,让Pybind声明PyInit_
函数),同时保留你的原始PYBIND11_MODULE
(使用原始名称):1.实现实际的伪模块,也就是使用Python的导入机制导入依赖项,找到原始模块并假装一直是原始模块:
以及相关的报头:
就是这样,从现在开始,假设两个生成的.so文件都在路径中,那么在原始名称下导入模块也会导入依赖项。