簡體   English   中英

在 C++ 應用程序中從嵌入式 Python 調用時,Numpy 導入在多數組擴展庫上失敗

[英]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 時才會發生這種情況,因為當我通過解釋器使用它時,導入工作。 我對增加我理解的答案更感興趣,而不是快速做這個或做那個修復。 我在下面列出了一些系統/問題信息,以及我正在考慮發布的關於同一主題的一些其他問題。 任何指導表示贊賞!

系統/問題信息:

  • Ubuntu 16.04,64 位
  • 使用 enabled-shared 編譯 Python 3.5.5
  • numpy import 在解釋器中工作(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 (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 multiarray.so 如何鏈接到 pythonX.X.so 以進行符號解析? ldd 似乎並沒有表明它曾經這樣做過。 在這個鏈接上問了這個問題
  • 在這個解決問題的CMake不相關的問題的問題問及18年4月12日,並回答了在18年4月16日。
  • 在 .bashrc 中設置 PYTHONPATH 似乎沒有更新 Py_GetPath() 返回的內容,我不得不通過與 sys.path 不同的方法添加站點包以進行導入。 它可能只更新不影響 C++ 的 bash 腳本環境變量。

在這一點上,我不是在尋求上述問題列表的答案,而是提供更多關於我的知識差距可能在哪里的線索。

感謝您抽出寶貴的時間閱讀這個問題。 任何幫助表示贊賞。

編輯:4/17/18:

好吧,我找到了一個解決方法,我目前正在使用它。 沙丘問題開始讓我更仔細地思考未定義的符號,以及它如何可能是鏈接器/編譯器錯誤,或者 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 至少有兩種方法可以實現:

  1. 使用dlopen("libpythonx.x.so", RTLD_GLOBAL) 打開它后,使用RTLD_GLOBAL標志,它使 libpythonx.x.so 中的符號可用於隨后加載的共享對象的符號解析。
  2. 在嵌入python的主程序中,將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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM