从 C++ 共享库调用 Python 代码

kat*_*z77 4 python boost numpy cmake

我在共享库插件中使用 boost::python 来运行一些 python 代码。我的主程序使用 boost::dll::shared_library API 在运行时将共享库作为插件加载。即我的主程序没有与共享库插件链接。我的代码在 Ubuntu 20.04 上运行。

我将我的共享库与 Python 链接:
my_shared_lib/CMakeLists.txt:

find_package(Python3 COMPONENTS Development NumPy REQUIRED)
target_link_libraries(${PROJECT_NAME} PRIVATE ${Python3_LIBRARIES} Python3::NumPy)
Run Code Online (Sandbox Code Playgroud)

当从我的共享库运行以下代码时,我收到导入错误:

#include <boost/python.hpp>
Py_Initialize();
namespace np = boost::python::numpy;
np::initialize(); //ImportError here
Run Code Online (Sandbox Code Playgroud)

我收到以下错误: ImportError:/home/myuser/.local/lib/python3.8/site-packages/numpy/core/_multiarray_umath.cpython-38-x86_64-linux-gnu.so:未定义符号:PyObject_SelfIter

我验证了我的 LD_LIBRARY_PATH 上有 /usr/lib/x86_64-linux-gnu/libpython3.8.so 。

当我的主程序与 Python 链接时,程序正常运行,没有 ImportError main_program/CMakeLists.txt:

find_package(Python3 COMPONENTS Development NumPy REQUIRED)
target_link_libraries(${PROJECT_NAME} PRIVATE ${Python3_LIBRARIES} Python3::NumPy)
Run Code Online (Sandbox Code Playgroud)

我这里的结论是,在运行时加载共享库插件似乎没有加载libpython3.8.so,而在主程序中加载libpython3.8.so使其可供共享库插件使用。

如果我像这样在共享库中手动加载 libpython3.8.so

#include <boost/python.hpp>
#include <dlfcn.h>
dlopen("/usr/lib/x86_64-linux-gnu/libpython3.8.so", RTLD_LAZY | RTLD_GLOBAL);
Py_Initialize();
namespace np = boost::python::numpy;
np::initialize();
Run Code Online (Sandbox Code Playgroud)

在此过程中,我进一步遇到了不同的错误:
Traceback(最近一次调用最后):文件“/home/myuser/.local/lib/python3.8/site-packages/numpy/core/ init .py”,第23行,在从. 导入多数组文件“/home/myuser/.local/lib/python3.8/site-packages/numpy/core/multiarray.py”,第 10 行,来自 . 导入覆盖文件“/home/myuser/.local/lib/python3.8/site-packages/numpy/core/overrides.py”,第 6 行,来自 numpy.core._multiarray_umath import ( ImportError: PyCapsule_Import 无法导入模块“约会时间”

如何让我的共享库插件在加载时自动加载 libpython3.8.so?

*** 编辑 ***
使用 gdb 我发现我最初的假设是错误的。当主应用程序加载我的共享库插件时,它还会加载 libpython3.8.so.1.0。已加载已加载'/home/myuser/.vs/mainapp/build/plugins/libap_python_ detector.so'。符号已加载。已加载“/usr/local/3rdparty/hpc/5.13.0-39_AMD_EPYC/boost176/build/lib/libboost_numpy38.so.1.76.0”。符号已加载。已加载“/lib/x86_64-linux-gnu/libpython3.8.so.1.0”。符号已加载。已加载“/usr/local/3rdparty/hpc/5.13.0-39_AMD_EPYC/boost176/build/lib/libboost_python38.so.1.76.0”。符号已加载。

那么加载 numpy 出了什么问题呢?

rel*_*t95 5

目前,NumPy 不支持从嵌入共享库的 Python 解释器加载 NumPy 的设计。(请参阅对 ImportError 进行故障排除 。它不涵盖您的情况。)

发生错误的原因是 NumPy 共享库几乎没有链接到 Python 运行时库。(您可以使用ldd检查它。)

但至少在 Linux 上,您可以通过使用 RTLD_GLOBAL 标志手动加载 Python 运行时库来解决此问题,如下例所示。(在主程序中加载运行时库,而不是在插件中。当然,只有在加载依赖于 Numpy 的插件时才需要这样做。)

#include <dlfcn.h>
int main()
{
    ...
    // When you load a NumPy-dependent plugin, do the following just before that.
    dlopen("libpython3.8.so", RTLD_LAZY | RTLD_GLOBAL);
    ...
}
Run Code Online (Sandbox Code Playgroud)

但我不确定它将来不会被打破。