简体   繁体   English

“符号未找到/预期位于:平面名称空间”实际上是什么意思?

[英]What does "Symbol not found / Expected in: flat namespace" actually mean?

When I import a module I built, I get this boost-python related error:当我导入我构建的模块时,出现与 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

What does this actually mean?这到底是什么意思? Why was this error raised?为什么会出现这个错误?

Description描述

The problem was caused by mixing objects that compiled with libc++ and object that compiled with libstdc++ .该问题是由使用libc++编译的对象和使用libstdc++编译的对象混合引起的。

In our case, the library myMod.so (compiled with libstdc++ ) need boost-python that compiled with libstdc++ ( boost-python-libstdc++ from now).在我们的例子中,该库myMod.so (编译libstdc++ )需要boost-python是编译libstdc++boost-python-libstdc++从现在起)。 When boost-python is boost-python-libstdc++ , it will work fine.boost-pythonboost-python-libstdc++ ,它会正常工作。 Otherwise - on computer that its boost-python has compiled with libc++ (or another c++ library), it will have a problem loading and running it.否则 - 在它的boost-pythonlibc++ (或另一个 c++ 库)编译的计算机上,加载和运行它会出现问题。

In our case, it happens because that libc++ developers intentionally changed the name of all of their symbols to prevent you (and save you) from mixing code from their library and code from a different one: myMod.so need a function that take an argument from the type.在我们的例子中,发生这种情况是因为libc++开发人员有意更改了他们所有符号的名称,以防止您(并保存您)将来自他们库的代码和来自不同库的代码混合在一起: myMod.so需要一个带参数的函数从类型。 In libc++ , this type's name is std::__1::pair .libc++ ,这种类型的名称是std::__1::pair Therefore, this symbol was not found.因此,没有找到这个符号。

To understand why mixing two version of the same API is bad, consider this situation: There are two libraries: Foo and Bar .要理解为什么混合使用相同 API 的两个版本是不好的,请考虑这种情况:有两个库: FooBar They both have a function that takes a std::string and uses it for something but they use a different c++ library.它们都有一个接受std::string的函数,并将其用于某些目的,但它们使用不同的 C++ 库。 When a std::string that has been created by Foo will be passed to Bar , Bar will think that this is an instance of its c++ library's std::string and then bad things can happen (they are a completely different objects).Foo创建的std::string将传递给BarBar会认为这是其 c++ 库的std::string的实例,然后可能会发生不好的事情(它们是完全不同的对象)。

Note : In some cases, there would be no problem with two or more different versions of the same API in a completely different parts of a program.注意:在某些情况下,同一 API 的两个或多个不同版本在程序的完全不同的部分中是没有问题的。 There will be a problem if they will pass this API's objects between them.如果它们在它们之间传递这个 API 的对象,就会出现问题。 However, checking that can be very hard, especially if they pass the API object only as a member of another object.但是,检查可能非常困难,尤其是当他们仅将 API 对象作为另一个对象的成员传递时。 Also, a library's initialization function can do things that should not happen twice.此外,库的初始化函数可以做不应发生两次的事情。 Another version may do these things again.另一个版本可能会再次做这些事情。

How to solve that?如何解决?

  • You can always recompile your libraries and make them match each other.您可以随时重新编译您的库并使它们相互匹配。

  • You can link boost-python to your library as a static library.您可以将boost-python作为静态库链接到您的库。 Then, it will work on almost every computer (even one that doesn't has boost-python installed).然后,它几乎可以在每台计算机上运行(即使是没有安装boost-python )。 See more about that here . 在此处查看更多相关信息。

Summary概括

myMod.so need another version of boost-python , one that compiled with a specific c++ library. myMod.so需要另一个版本的boost-python ,一个使用特定 C++ 库编译的版本。 Therefore, It would not work with any another version.因此,它不适用于任何其他版本。

Symbol not found means the definition of the declared function or variable was not found.未找到符号表示未找到声明的函数或变量的定义。 When a header file of a shared object is compiled with your program, linker adds symbols of declared functions and objects to your compiled program.当共享对象的头文件与您的程序一起编译时,链接器会将声明的函数和对象的符号添加到您编译的程序中。 When your program is loaded by the OS's loader, the symbols are resolved so that their definition will be loaded.当您的程序由操作系统的加载器加载时,符号将被解析,以便加载它们的定义。 It is only at this time where if the implementation is missing, loader complains it couldn't find the definition due to may be failing to resolve the actual path to the library or the library itself wasn't compiled with the implementation/source file where the definition of the function or object resides.只是此时如果缺少实现,加载器会抱怨它找不到定义,因为可能无法解析到库的实际路径,或者库本身没有与实现/源文件一起编译,其中函数或对象的定义驻留。 There is a good article on this on the linux journal http://www.linuxjournal.com/article/6463 .在 linux 期刊http://www.linuxjournal.com/article/6463上有一篇关于此的好文章。

I encounter the same problem.我遇到了同样的问题。

Expected in: flat namespace

Add the linker flag fixes the problem添加链接器标志修复了问题

-lboost_python37

change the dynamic library name to the one installed on the os.将动态库名称更改为安装在操作系统上的名称。

By the way, my os is macOS High Sierra and I use brew to install boost_python3 .顺便说一下,我的操作系统是 macOS High Sierra,我使用 brew 来安装boost_python3

In my case I was just failing to import all the required sources (c++ files) when compiling with Cython.在我的情况下,我只是在使用 Cython 编译时未能导入所有必需的源(c++ 文件)。

From the string after "Symbol not found" you can understand which library you are missing.从“找不到符号”之后的字符串中,您可以了解您缺少哪个库。

Here's what I've learned (osx):这是我学到的东西(osx):

If this is supposed to work (ie it works on another computer), you may be experiencing clang/gcc issues.如果这应该可以工作(即它可以在另一台计算机上工作),则您可能遇到了 clang/gcc 问题。 To debug this, use otool -l on the .so file which is raising the error, or a suspect library (in my example it's a boost-python dylib file) and examine the contents.要对此进行调试, otool -l在引发错误的 .so 文件或可疑库(在我的示例中它是 boost-python dylib 文件)上使用otool -l并检查内容。 Anything in the /System/ folder is built with clang, and should be installed somewhere else with the gcc compiler. /System/ 文件夹中的任何内容都是使用 clang 构建的,并且应该使用 gcc 编译器安装在其他地方。 Never delete anything in the /System folder.切勿删除 /System 文件夹中的任何内容。

.so files are dynamic libraries (so = shared object). .so文件是动态库(so = 共享对象)。 On Windows they are called .dll (dynamic-link library).在 Windows 上,它们被称为.dll (动态链接库)。 They contain compiled code which contains functions available for usage to any executable which links them.它们包含已编译的代码,其中包含可用于链接它们的任何可执行文件的函数。

What is important to notice here is that those .so are not Python files.这里需要注意的重要一点是那些.so不是 Python 文件。 They were probably compiled from C or C++ code and contain public functions which can be used from Python code (see documentation on Extending Python with C or C++ ).它们可能是从 C 或 C++ 代码编译的,并且包含可以从 Python 代码中使用的公共函数(请参阅关于用 C 或 C++ 扩展 Python 的文档)。

On your case, well, you have a corrupt .so .在你的情况下,你有一个损坏的.so Try reinstalling the affected libraries, or Python, or both.尝试重新安装受影响的库或 Python,或两者。

Problem问题

I had this same issue when running puma as part of Rails app作为 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): symbol not found in flat namespace '_ERR_load_crypto_strings' 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 /Users/alucard/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/puma-5.6.4/lib/puma/puma_http11.bundle

Solution解决方案

It was solved just by installing puma gem again gem install puma只需再次安装 puma gem 即可解决gem install puma

In my case I was receiving:就我而言,我收到了:

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'

BACKGROUND:背景:

M1 MacBook Pro with Montery M1 MacBook Pro 带蒙特利

I was working with a python virtualenv (using pyenv) to use an earlier version of python3.8 (3.8.2), while my system had 3.8.10 installed natively.我正在使用 python virtualenv(使用 pyenv)来使用早期版本的 python3.8 (3.8.2),而我的系统本机安装了 3.8.10。

While I was in the activated 3.8.2 virtualenv I noticed the path in dlopen() was pointing to the package in the native python install NOT the virtualenv install.当我在激活的 3.8.2 virtualenv 中时,我注意到 dlopen() 中的路径指向本机 python 安装中的包,而不是 virtualenv 安装。

SOLUTION:解决方案:

In my case, I did not need the native 3.8 version at all so I simply removed it and this solved the problem.就我而言,我根本不需要原生 3.8 版本,所以我只是将其删除,这解决了问题。

One of the solutions I found was to uninstall and reinstall it using the no-binary flag, which forces pip to compile the module from source instead of installing from precompiled wheel.我找到的解决方案之一是使用 no-binary 标志卸载并重新安装它,这会强制 pip 从源代码编译模块,而不是从预编译的 wheel 安装。

pip install --no-binary :all: <name-of-module>

Found this solution here 在这里找到这个解决方案

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM