[英]Embedded python in C++: importerror importing numpy.core.multiarray
[英]Numpy import fails on multiarray extension library when called from embedded Python within a C++ application
我正在運行一個 C++ 應用程序,它嘗試使用https://docs.python.org/3.5/extending/embedding.html函數調用運行 python。 這是應用程序錯誤消息管道給我的錯誤。
“ImportError”類:導入多數組 numpy 擴展模塊失敗。 很可能您正在嘗試導入失敗的 numpy 構建。 如果您正在使用 numpy git repo,請嘗試
git clean -xdf
(刪除所有不受版本控制的文件)。 否則重新安裝numpy。原始錯誤是:/usr/local/lib/python3.5/site-packages/numpy/core/multiarray.cpython-35m-x86_64-linux-gnu.so:未定義符號:PyExc_UserWarning
我很困惑,因為只有在 C++ 中嵌入 Python 時才會發生這種情況,因為當我通過解釋器使用它時,導入工作。 我對增加我理解的答案更感興趣,而不是快速做這個或做那個修復。 我在下面列出了一些系統/問題信息,以及我正在考慮發布的關於同一主題的一些其他問題。 任何指導表示贊賞!
系統/問題信息:
import sys
, sys.path
Py_Import_Import()
、 Py_Initialize()
(我確定。它只被調用一次。)等,但它沒有在解釋器上獲得全局鎖。pip3.5 install numpy
命令使用 pip 9.0.0 安裝 numpy-1.14.2import numpy
...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 (0x00007fdbe0bab6400) /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 導入總是期望一個環境中這些符號已經加載到內存中。 這讓我嘗試安裝不同版本的 numpy 以查看是否有任何舊版本有所不同。 他們沒有,但它確實使拋出的錯誤略有不同。 當我用谷歌搜索時, 出現了這個問題。 接受的答案通過將這兩行添加到 pythonInterface.cpp 給了我一個解決方法:
#include <dlfcn.h>
dlopen("libpython3.5m.so.1.0", RTLD_LAZY | RTLD_GLOBAL)
這些命令添加了要加載的共享庫並可用於 cpython.multiarray.so。
這不是指向特定 .so 的理想解決方案,這可能因機器而異。 它暫時解決了這個問題,但它也可能導致錯誤,如果 pythonInterface.so 的鏈接庫發生更改,並且此行未更新,則在 python 調用過程中可能會發生共享庫不匹配的錯誤。 我相信如果回答了這個子問題,可以得到更好的答案,所以我目前正在等待提交或接受答案。 謝謝!
根本原因
發生此錯誤是因為 numpy 中的multiarray.cpython-35m-x86_64-linux-gnu.so
模塊依賴於libpythonx.x.so
,如果它不是顯式鏈接libpythonx.x.so
。 因此,如果您使用ldd -d multiarray.cpython-35m-x86_64-linux-gnu.so
您將不會在列表中看到 python。
Python 沒有問題,因為 python 二進制文件依賴於libpython.xxso
,所以當 numpy 使用dlopen
加載multiarray.cpython-35m-x86_64-linux-gnu.so
時。 libdl.so
將嘗試通過檢查主程序 python 的依賴共享庫來解析未定義的符號。 它將在libpython.xxso
找到它。
解決方案
知道根本原因后,解決方案很簡單,只需幫助libdl.so
即可找到libpython.xxso
。 至少有兩種方法可以實現:
dlopen("libpythonx.x.so", RTLD_GLOBAL)
。 打開它后,使用RTLD_GLOBAL
標志,它使 libpythonx.x.so 中的符號可用於隨后加載的共享對象的符號解析。libpythonx.x.so
添加到其依賴庫中。我在將應用程序鏈接到 libpython3.5m.a(存檔,非動態)時遇到了類似的錯誤。 一旦它加載了像multiarray.cpython-35m-x86_64-linux-gnu.so
這樣的東西,它就會期望像PyFloat_Type
這樣的符號存在。
在診斷為什么可以直接調用 Python 並且它可以工作,但我的應用程序不能運行時,我注意到readelf -s myapplication
在.symtab
表中有一個 PyFloat_Type 符號,但在.dynsym
表中沒有。
但是, readelf -s /asb/path/to/python3
在兩個表中都有一個 PyFloat_Type 符號。
在 CMake 中添加: target_link_options(myapplication PUBLIC "LINKER:-export-dynamic")
確保所需的符號也在.dynsym
表中可用。 在此之后,應用程序正常工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.