[英]What does "Symbol not found / Expected in: flat namespace" actually mean?
當我導入我構建的模塊時,出現與 boost-python 相關的錯誤:
Traceback (most recent call last):
File "<string>", line 1, in <module>
ImportError: dlopen(./myMod.so, 2): Symbol not found: __ZN5boost6python7objects15function_objectERKNS1_11py_functionERKSt4pairIPKNS0_6detail7keywordES9_E
Referenced from: ./myMod.so
Expected in: flat namespace
in ./myMod.so
這到底是什么意思? 為什么會出現這個錯誤?
該問題是由使用libc++
編譯的對象和使用libstdc++
編譯的對象混合引起的。
在我們的例子中,該庫myMod.so
(編譯libstdc++
)需要boost-python
是編譯libstdc++
( boost-python-libstdc++
從現在起)。 當boost-python
是boost-python-libstdc++
,它會正常工作。 否則 - 在它的boost-python
用libc++
(或另一個 c++ 庫)編譯的計算機上,加載和運行它會出現問題。
在我們的例子中,發生這種情況是因為libc++
開發人員有意更改了他們所有符號的名稱,以防止您(並保存您)將來自他們庫的代碼和來自不同庫的代碼混合在一起: myMod.so
需要一個帶參數的函數從類型。 在libc++
,這種類型的名稱是std::__1::pair
。 因此,沒有找到這個符號。
要理解為什么混合使用相同 API 的兩個版本是不好的,請考慮這種情況:有兩個庫: Foo
和Bar
。 它們都有一個接受std::string
的函數,並將其用於某些目的,但它們使用不同的 C++ 庫。 當Foo
創建的std::string
將傳遞給Bar
, Bar
會認為這是其 c++ 庫的std::string
的實例,然后可能會發生不好的事情(它們是完全不同的對象)。
注意:在某些情況下,同一 API 的兩個或多個不同版本在程序的完全不同的部分中是沒有問題的。 如果它們在它們之間傳遞這個 API 的對象,就會出現問題。 但是,檢查可能非常困難,尤其是當他們僅將 API 對象作為另一個對象的成員傳遞時。 此外,庫的初始化函數可以做不應發生兩次的事情。 另一個版本可能會再次做這些事情。
您可以隨時重新編譯您的庫並使它們相互匹配。
您可以將boost-python
作為靜態庫鏈接到您的庫。 然后,它幾乎可以在每台計算機上運行(即使是沒有安裝boost-python
)。 在此處查看更多相關信息。
myMod.so
需要另一個版本的boost-python
,一個使用特定 C++ 庫編譯的版本。 因此,它不適用於任何其他版本。
未找到符號表示未找到聲明的函數或變量的定義。 當共享對象的頭文件與您的程序一起編譯時,鏈接器會將聲明的函數和對象的符號添加到您編譯的程序中。 當您的程序由操作系統的加載器加載時,符號將被解析,以便加載它們的定義。 只是此時如果缺少實現,加載器會抱怨它找不到定義,因為可能無法解析到庫的實際路徑,或者庫本身沒有與實現/源文件一起編譯,其中函數或對象的定義駐留。 在 linux 期刊http://www.linuxjournal.com/article/6463上有一篇關於此的好文章。
我遇到了同樣的問題。
Expected in: flat namespace
添加鏈接器標志修復了問題
-lboost_python37
將動態庫名稱更改為安裝在操作系統上的名稱。
順便說一下,我的操作系統是 macOS High Sierra,我使用 brew 來安裝boost_python3
。
在我的情況下,我只是在使用 Cython 編譯時未能導入所有必需的源(c++ 文件)。
從“找不到符號”之后的字符串中,您可以了解您缺少哪個庫。
這是我學到的東西(osx):
如果這應該可以工作(即它可以在另一台計算機上工作),則您可能遇到了 clang/gcc 問題。 要對此進行調試, otool -l
在引發錯誤的 .so 文件或可疑庫(在我的示例中它是 boost-python dylib 文件)上使用otool -l
並檢查內容。 /System/ 文件夾中的任何內容都是使用 clang 構建的,並且應該使用 gcc 編譯器安裝在其他地方。 切勿刪除 /System 文件夾中的任何內容。
.so
文件是動態庫(so = 共享對象)。 在 Windows 上,它們被稱為.dll
(動態鏈接庫)。 它們包含已編譯的代碼,其中包含可用於鏈接它們的任何可執行文件的函數。
這里需要注意的重要一點是那些.so
不是 Python 文件。 它們可能是從 C 或 C++ 代碼編譯的,並且包含可以從 Python 代碼中使用的公共函數(請參閱關於用 C 或 C++ 擴展 Python 的文檔)。
在你的情況下,你有一個損壞的.so
。 嘗試重新安裝受影響的庫或 Python,或兩者。
作為 Rails 應用程序的一部分運行 puma 時,我遇到了同樣的問題
LoadError:dlopen(/Users/alucard/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/puma-5.6.4/lib/puma/puma_http11.bundle,0x0009):找不到符號在平面命名空間“_ERR_load_crypto_strings”中
- /Users/alucard/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/puma-5.6.4/lib/puma/puma_http11.bundle
只需再次安裝 puma gem 即可解決gem install puma
就我而言,我收到了:
ImportError: dlopen(/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/xmlsec.cpython-38-darwin.so, 0x0002): symbol not found in flat namespace '_xmlSecDSigNs'
背景:
M1 MacBook Pro 帶蒙特利
我正在使用 python virtualenv(使用 pyenv)來使用早期版本的 python3.8 (3.8.2),而我的系統本機安裝了 3.8.10。
當我在激活的 3.8.2 virtualenv 中時,我注意到 dlopen() 中的路徑指向本機 python 安裝中的包,而不是 virtualenv 安裝。
解決方案:
就我而言,我根本不需要原生 3.8 版本,所以我只是將其刪除,這解決了問題。
我找到的解決方案之一是使用 no-binary 標志卸載並重新安裝它,這會強制 pip 從源代碼編譯模塊,而不是從預編譯的 wheel 安裝。
pip install --no-binary :all: <name-of-module>
在這里找到這個解決方案
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.