"Symbol not found / Expected in: flat namespace" 到底是什么意思?

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

这到底是什么意思?为什么会出现此错误?

这是我学到的东西 (osx):

如果这应该有效(即它在另一台计算机上有效),您可能会遇到 clang/gcc 问题。要对此进行调试,请在引发错误的 .so 文件或可疑库(在我的示例中是一个 boost-python dylib 文件)上使用 otool -l 并检查其内容。 /System/ 文件夹中的任何内容都是用 clang 构建的,应该使用 gcc 编译器安装在其他地方。切勿删除 /System 文件夹中的任何内容。

.so 文件是动态库(所以 = 共享对象)。在 Windows 上,它们被称为 .dll(动态-link 库)。它们包含已编译的代码,其中包含可供 link 包含它们的任何可执行文件使用的函数。

这里需要注意的是那些 .so 不是 Python 文件。它们可能是从 C 或 C++ 代码编译而来的,并且包含 public 可以从 Python 代码中使用的函数(参见 Extending Python with C or C++ 上的文档)。

在你的情况下,嗯,你有一个腐败的 .so。尝试重新安装受影响的库,或 Python,或两者。

未找到符号表示未找到声明的函数或变量的定义。当共享对象的头文件与您的程序一起编译时,链接器将声明的函数和对象的符号添加到您编译的程序中。当您的程序被 OS 的加载程序加载时,符号将被解析以便加载它们的定义。只有在这个时候,如果缺少实现,加载程序会抱怨找不到定义,因为可能无法解析库的实际路径,或者库本身没有用 implementation/source 编译函数或对象的定义所在的文件。 linux 期刊 http://www.linuxjournal.com/article/6463.

上有一篇关于此的好文章

描述

问题是由于混合使用 libc++ 编译的对象和使用 libstdc++ 编译的对象引起的.

在我们的例子中,库 myMod.so(用 libstdc++ 编译)需要用 [编译的 boost-pythonlibstdc++boost-python-libstdc++ 从现在开始)。当 boost-pythonboost-python-libstdc++ 时,它将正常工作。否则 - 在其 boost-python 已使用 libc++(或其他 c++ 库)编译的计算机上,加载和 运行 将出现问题。

在我们的案例中,这是因为 libc++ 开发人员故意更改了所有符号的名称,以防止您(并拯救您)将代码与他们的库和代码来自不同的库和代码:myMod.so 需要一个从类型中获取参数的函数。在libc++中,这个类型的名字是std::__1::pair。因此,找不到此符号。

要理解为什么混合使用相同 API 的两个版本是不好的,请考虑这种情况:有两个库:FooBar。它们都有一个接受 std::string 并将其用于某些用途的函数,但它们使用不同的 c++ 库。当 Foo 创建的 std::string 将传递给 Bar 时,Bar 会认为这是其 c++ 库的 std::string 的实例,然后可能会发生坏事(它们是完全不同的对象)。

注意:在某些情况下,在程序的完全不同部分中使用相同 API 的两个或多个不同版本不会有问题。如果他们在他们之间传递这个 API 的对象,就会有问题。但是,检查可能非常困难,尤其是当它们仅将 API 对象作为另一个对象的成员传递时。此外,库的初始化函数可以做一些不应该发生两次的事情。另一个版本可能会再次做这些事情。

如何解决?

  • 您可以随时重新编译您的库并使它们相互匹配。

  • 你可以linkboost-python把你的库作为静态库。然后,它几乎可以在每台计算机上运行(即使是没有安装 boost-python 的计算机)。查看更多相关信息 here.

总结

myMod.so 需要另一个版本的 boost-python,一个用特定的 c++ 库编译的版本。因此,它不适用于任何其他版本。

我遇到了同样的问题

Expected in: flat namespace

添加链接器标志修复了问题

-lboost_python37

将动态库名称更改为安装在 os 上的名称。

顺便说一下,我的 os 是 macOS High Sierra,我使用 brew 安装 boost_python3

在我的例子中,我只是在使用 Cython 编译时未能导入所有必需的源代码(c++ 文件)。

从"Symbol not found"后面的字符串可以了解到你缺少的是哪个库。

就我而言,我收到了:

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'

背景:

配备 Montery 的 M1 MacBook Pro

我正在使用 python virtualenv(使用 pyenv)来使用 python3.8 (3.8.2) 的早期版本,而我的系统本机安装了 3.8.10。

当我在激活的 3.8.2 virtualenv 中时,我注意到 dlopen() 中的路径指向本机 python 安装中的包,而不是 virtualenv 安装。

解决方案:

在我的例子中,我根本不需要原生的 3.8 版本,所以我简单地删除了它,这就解决了问题。

问题

当 运行 puma 作为 Rails 应用程序的一部分时,我遇到了同样的问题

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): symbol not found in flat namespace '_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