【问题标题】:Missing symbols from a dylibdylib 中缺少符号
【发布时间】:2015-10-06 01:58:53
【问题描述】:

我正在尝试围绕 C++ 库制作 C api,以便以后可以将其包装在 Golang 中。我首先简单地生成一个具有一个函数的 dylib,以便我有一个参考。然后我围绕我想使用的实际库做了一个包装。当我从简单的 dylib 生成所有符号时,我得到了这个:

MacbookMainframe:c hydroflame$ nm -a clib/libxyz.dylib 
0000000000000f90 T _Hello
                 U dyld_stub_binder

我只声明了一个名为 Hello 的函数,到目前为止一切顺利

当我做了我认为与实际库等效的操作时,go wrapper 无法编译并且符号在哪里生成

MacbookMainframe:c hydroflame$ nm -a ../luxengine.net/steamc/libsteam.dylib 
                 U _SteamAPI_Init
0000000000000f60 T __Z14SteamCAPI_Initv
                 U dyld_stub_binder

我期待的符号是_SteamCAPI_Init(带有下划线,因为显然Hello 生成了_Hello,但我得到了一些奇怪的东西。

是我的编译错误,还是应该生成的正常符号?

源文件在这里(只有大约 30 行重要的行):
https://github.com/luxengine/steam
https://github.com/luxengine/steamc

编辑(供未来的读者使用):

我在撰写本文时的问题是我的头文件声明有 extern "C" { 但我的源文件没有,所以 gcc 无论如何都会破坏名称而 cgo 找不到它。

MacbookMainframe:steamc hydroflame$ nm -a libsteam.dylib 
                 U _SteamAPI_Init
0000000000000f60 T _SteamCAPI_Init
                 U dyld_stub_binder

【问题讨论】:

    标签: c++ c go cgo


    【解决方案1】:

    首先,dyld_stub_binder 是编译 C++ 时默认生成的符号。你不需要关心它。

    其次,__Z14SteamCAPI_Initv 实际上是正确的符号。由于 C++ 支持重载,因此 C++ 函数使用重载符号名称进行编译,因此函数名称不会相互冲突。例如,您有两个函数void do_something(int a)void do_something(int a, int b),如果函数名称没有被破坏,链接器将如何解析符号名称。

    有关 C++ 名称修改的信息可以在 here 找到。

    【讨论】:

    • 嗯,即使我 export "C" ... bool SteamCAPI_Init ... } 也可以?因为这就是我正在做的事情,所以认为它不会破坏名称。如果是,任何不破坏它们的方法,以便 go 编译器可以通过 SteamCAPI_Init 检索名称?
    • export "C"是为了让C知道函数是C++,不影响编译。
    • 如果您希望符号为SteamCAPI_Init,则需要为__Z14SteamCAPI_Initv 创建一个C 包装器。
    • 所以SteamAPI_Init 是一个 C++ 函数,那么我需要创建 SteamCAPI_Init,一个围绕 SteamCAPI_Init 的包装器,然后是另一个围绕 SteamCAPI_init 的 C 包装器。我肯定错过了一些东西:\ 我的目标是 SteamCAPI_Init 是包装器
    • 如果您坚持使用未损坏的符号名称,我只是说一种可能的方式。通常我们不需要关心那个。只要函数在头文件中使用 export "C" 声明,它应该能够被 C 和 C++ 调用。不知道为什么你不希望符号名称被破坏。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-21
    • 2020-05-13
    • 1970-01-01
    相关资源
    最近更新 更多