簡體   English   中英

“符號未找到/預期位於:平面名稱空間”實際上是什么意思?

[英]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-pythonboost-python-libstdc++ ,它會正常工作。 否則 - 在它的boost-pythonlibc++ (或另一個 c++ 庫)編譯的計算機上,加載和運行它會出現問題。

在我們的例子中,發生這種情況是因為libc++開發人員有意更改了他們所有符號的名稱,以防止您(並保存您)將來自他們庫的代碼和來自不同庫的代碼混合在一起: myMod.so需要一個帶參數的函數從類型。 libc++ ,這種類型的名稱是std::__1::pair 因此,沒有找到這個符號。

要理解為什么混合使用相同 API 的兩個版本是不好的,請考慮這種情況:有兩個庫: FooBar 它們都有一個接受std::string的函數,並將其用於某些目的,但它們使用不同的 C++ 庫。 Foo創建的std::string將傳遞給BarBar會認為這是其 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.

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