共享对象中的符号名称与 .cpp 文件中的函数不同

symbol name in shared object differs from function in .cpp file

在项目环境中,我想将共享对象的源文件从c 更改为cpp。我也确保更改了 CMakeLists.txt 中的条目:

add_library(*name* SHARED *mysource*.cpp)
target_link_libraries(*name as target* *item*)

构建过程运行良好。不幸的是,当我尝试使用它时,我收到一条错误消息,指出无法找到 .so 中的函数。

使用objdump -T查看共享库中的动态符号table,发现符号名称与源文件中的不同。 例如

int sr_plugin_init_cb(sr_session_ctx_t *session, void **private_ctx);

变成

_Z17sr_plugin_init_cbP16sr_session_ctx_sPPv

在我的 visual studio 代码中,它说它可以正确构建对象和 link 共享库,并且它还在输出中从 C 更改为 CXX,即使没有给我任何错误一些代码仅是 C++。

为什么符号名称会改变?

Why do the symbol names change?

C++ 有一个叫做函数重载的特性。基本上发生的事情是你声明了两个名称相同但略有不同的函数:

int sr_plugin_init_cb(sr_session_ctx_t *session, void **private_ctx);
int sr_plugin_init_cb(sr_session_ctx_t *session, void **private_ctx, int some_arg);

或更糟的情况:

struct A {
    # each of these functions can be different depending on the object
    void func();
    void func() const;
    void func() volatile;
    void func() volatile const;
};

函数名称相同。链接器看不到 C++ 源代码,但它仍然必须将这两个函数与 link 区分开来。因此 C++ 编译器 "mangles" 函数名称,以便 linker 可以区分它们。为了简单起见,它可能看起来像:

sr_plugin_init_cb_that_doesnt_take_int_arg
sr_plugin_init_cb_that_takes_int_arg
A_func
A_func_but_object_is_const
A_func_but_object_is_volatile
A_func_but_object_is_volatile_and_const

名称修改的规则很复杂,要使名称尽可能短。他们必须考虑任意数量的模板、参数、对象、名称、限定符、lambda、重载、运算符等,并生成一个唯一的名称,并且他们必须仅使用与 linker 兼容的字符特定的架构。例如 here 是 gnu g++ 编译器使用的名称修饰的参考。

符号名称 _Z17sr_plugin_init_cbP16sr_session_ctx_sPPv 是您的函数的编译器名称所破坏的。

非常感谢您的详细解答。我现在明白了这个问题。 快速搜索后,我找到了解决问题的方法。像这样封装函数原型可以避免名称混淆。

extern "C" {
    // Function prototypes
};