python - 从 C++ 应用程序中的嵌入式 Python 调用时,多数组扩展库上的 Numpy 导入失败

标签 python c++ python-3.x numpy python-embedding

我正在运行一个 C++ 应用程序,它尝试使用 https://docs.python.org/3.5/extending/embedding.html 运行 python函数调用。这是应用程序错误消息管道给我的错误。

class 'ImportError': Importing the multiarray numpy extension module failed. Most likely you are trying to import a failed build of numpy. If you're working with a numpy git repo, try git clean -xdf (removes all files not under version control). Otherwise reinstall numpy.

Original error was: /usr/local/lib/python3.5/site-packages/numpy/core/multiarray.cpython-35m-x86_64-linux-gnu.so: undefined symbol: PyExc_UserWarning



我很困惑,因为只有在 C++ 中嵌入 Python 时才会发生这种情况,因为当我通过解释器使用它时,导入工作。我对增加我理解的答案更感兴趣,而不是快速做这个或做那个修复。我在下面列出了一些系统/问题信息,以及我正在考虑发布的关于同一主题的一些其他问题。任何指导表示赞赏!

系统/问题信息:
  • Ubuntu 16.04,64 位
  • 编译 Python 3.5.5,启用共享
  • numpy 导入适用于解释器(python3.exe 和 python3.5.exe)
  • 我已经确保 PySys_SetPath() 设置了与解释器输出相同的 sys.path:import sys , sys.path
  • 我可以导入其他模块,如 PIL 和 datetimeutil;但是,numpy 和 pandas 不可导入(pandas 使用 numpy 或似乎可以)
  • 嵌入式 Python 使用以下命令:Py_Import_Import() , Py_Initialize() (我确定。它只被调用一次。)等等,但它没有在解释器上获得全局锁定。
  • 该应用程序是使用 CMake 构建系统构建的,该系统为我的系统编译为 MakeFiles。
  • 使用 pip3.5 install numpy 使用 pip 9.0.0 安装 numpy-1.14.2命令
  • 导致此错误的 python 脚本有一行:import numpy ...
  • 我没有要从中导入文件的 .zip 文件。
  • 嵌入在 C++ 中的 Python 使用的 .exe 位于/usr/local/bin/python3 (使用 Py_GetProgramName() 来确定这一点)。这个 .exe 链接到 libpython3.5m.so.1.0,缺少的符号位于 libpython3.5m.so.1.0 (ran nm)
  • multiarray.cpython-35m-x86_64-linux-gnu.so 上的 ldd 显示:
    ldd multiarray.cpython-35m-x86_64-linux-gnu.so

    linux-vdso.so.1 => (0x00007ffd9e36b000)

    libopenblasp-r0-39a31c03.2.18.so => /usr/local/lib/python3.5/site-packages/numpy/core/./../.libs/libopenblasp-r0-39a31c03.2.18.so (0x00007fdbe149b000)

    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fdbe1192000)

    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fdbe0f75000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fdbe0bab000) /lib64/ld-linux-x86-64.so.2 (0x00007fdbe3ed5000)

    libgfortran-ed201abd.so.3.0.0 => /usr/local/lib/python3.5/site-packages/numpy/core/./../.libs/libgfortran-ed201abd.so.3.0.0 (0x00007fdbe08b1000)


  • 我可以/可能会尝试通过不同的方式重新安装 numpy,但我无法跟踪为什么这可能会起作用。

    在这一点上,我假设我的知识存在一些漏洞。我查看了很多关于在 C++ 中嵌入 Python 时无法导入多数组组件和 numpy 的类似帖子;但是,要么它们都不符合我的具体情况,要么正如我所说的那样存在漏洞。以下是我可能会问的子问题列表,是否没有人在此设置中看到任何明显相关的内容。当/如果我问他们(在我润色之后),我可能会用链接更新问题。
  • numpy multiarray.so 如何链接到 pythonX.X.so 以进行符号解析? ldd 似乎并没有暗示它曾经这样做过。在此问这个问题 link
  • CMake 问题非相关问题已在此解决 question 2018 年 4 月 12 日提问,2018 年 4 月 16 日回答。
  • 在 .bashrc 中设置 PYTHONPATH 似乎没有更新 Py_GetPath() 返回的内容,我不得不通过与 sys.path 不同的方法添加站点包以进行导入。它可能只更新不影响 C++ 的 bash 脚本环境变量。

  • 在这一点上,我不是在寻求上述问题列表的答案,而是提供更多关于我的知识差距可能在哪里的线索。

    感谢您抽出宝贵的时间阅读这个问题。任何帮助表示赞赏。

    编辑:4/17/18:

    嗯,我找到了一个解决方法,我目前正在使用它。沙丘问题开始让我更仔细地思考 undefined symbol ,以及它如何可能是链接器/编译器错误,或者 numpy 导入总是期望一个环境,这些符号已经加载到内存中。这让我尝试安装不同版本的 numpy 以查看是否有任何旧版本有所不同。他们没有,但它确实使抛出的错误略有不同。当我用谷歌搜索时,这个 question appeared .接受的答案通过将这两行添加到 pythonInterface.cpp 给了我一个解决方法:
  • #include <dlfcn.h>
  • dlopen("libpython3.5m.so.1.0", RTLD_LAZY | RTLD_GLOBAL)

  • 这些命令添加了要加载的共享库并可用于 cpython.multiarray.so。

    这不是指向特定 .so 的理想解决方案,这可能因机器而异。它暂时解决了这个问题,但它也可能导致错误,如果 pythonInterface.so 的链接库发生更改,并且此行未更新,则在 python 调用过程中可能会发生共享库不匹配的错误。我相信如果这个 sub-question 可以得到更好的答案已回答,所以我目前正在等待提交或接受答案,直到那时。谢谢!

    最佳答案

    根本原因

    发生此错误的原因是 multiarray.cpython-35m-x86_64-linux-gnu.so numpy 中的模块取决于 libpythonx.x.so ,如果不是显式链接libpythonx.x.so .所以如果你使用 ldd -d multiarray.cpython-35m-x86_64-linux-gnu.so您不会在列表中看到 python。

    Python 没有问题,因为 Python 二进制文件依赖于 libpython.x.x.so ,所以当 numpy 加载 multiarray.cpython-35m-x86_64-linux-gnu.so通过使用 dlopen . libdl.so将尝试通过检查 python 主程序的依赖共享库来解析 undefined symbol 。它将在 libpython.x.x.so 中找到它.

    解决方案

    知道根本原因后解决方法很简单,只需要帮助libdl.so能够找到libpython.x.x.so .至少有两种方法可以实现:

  • 使用 dlopen("libpythonx.x.so", RTLD_GLOBAL) .打开后使用 RTLD_GLOBAL标志,它使 libpythonx.x.so 中的符号可用于随后加载的共享对象的符号解析。
  • 在嵌入python的主程序中,添加libpythonx.x.so进入它的依赖库。
  • 关于python - 从 C++ 应用程序中的嵌入式 Python 调用时,多数组扩展库上的 Numpy 导入失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49784583/

    相关文章:

    python - 使用两列连接多个 CSV 文件

    python - 使用 Paramiko (Python) 通过 SSH 执行 smartctl 命令时没有输出

    python - 动态重新定义 numpy 数组

    python - 无法使用网络摄像头读取帧。错误-2147483638

    python - 如何从递归函数中获取数据?

    C++:如何在控制台中输入文本并将其保留在底部

    python - 在两个连续执行的函数之间添加延迟

    c++ - 在新 [] : with or without user destructor 之后删除

    c++ - 使用 MinGW 在 Windows 上编译到 Linux?

    python - 将输入列表中的字典元素附加到元组列表