混合 C/C++ 代码可产生"undefined symbol"共享库



这个问题困扰了我一周了,所以我想也许终于到了向你们寻求帮助的时候了。以下是一个简单的故事:

我们正在内部使用Qt/C++开发嵌入式服务器。这是一个非常简单的服务器,它处理客户端请求,并通过dlopen()/dlsim()调用加载适当的函数来执行特定于供应商的操作。这意味着供应商只需按照我们定义的方式向我们提供一个C语言的.so文件及其功能(对我们来说是透明的)。这将用C编写,因为它需要做很多低级别的事情,而我们的服务器是Qt,因为我们计划最终拥有它的前端

这里有一些伪代码:

在我们的main.cpp文件中(这是以C语言编写的,但使用Qt mkspec中定义的g++编译器,使用-ldl和-rdynamic编译以导出所有符号):

  • dlopen()vendor.so文件(同时使用RTLD_NOW和RTLD_LAZY尝试)
  • dlsym()vendor.so init()方法(这将调用供应商的init方法,该方法将通过我们代码中的setter方法设置这个"供应商插件"的名称/属性,调用这个plugin_set_name(args…))

在共享头文件(shared.h)中(两个代码库都会使用这个;我们的代码库会有完整的结构定义,供应商只会有setter/getter的原型):

  • extern"C"int plugin_set_name(args…)

在供应商主.c文件中(使用gcc、-fPIC和-shared编译)

  • 上面提到的init()函数的实现

因此,从本质上讲,C++代码将使用dl调用从C.So库加载init()函数,然后C.So库将调用C++代码中定义的函数(在本例中为plugin_set_name)。这可能吗?两者都不相互关联,因为它们是相互独立地使用不同的编译器编译的(gcc与g++)。

我在运行时遇到的错误是:"未定义的符号:plugin_set_name"(所以它可以很好地找到并进入库的init()方法)。当我使用gcc和纯C代码来做任何事情时,它都能完美地工作,所以我知道这不是代码,而是混合了C/C++的东西。我也理解使用外部"C"来防止名称篡改,并使用nm/readelf来确定不存在任何类型的篡改。有什么想法吗?对此,最好的方法是什么?

不知怎么的,这在今天神奇地起了作用。我无法解释。我只是在共享标头周围有外部的"C"声明,所以在shared.h:中

#ifdef __cplusplus
extern "C" {
#endif
plugin_set_name(args...)
other_shared_functions
#ifdef __cplusplus
}
#endif

然而,我一直都是这样。无论哪种情况,它现在都可以使用C编译供应商插件,使用Qt和C++编译服务器。我认为问题在于将所有外部元素以及g++链接标志放在哪里(rddynamic在其中至关重要)。谢谢把这个放在这里,以防其他人遇到同样的问题。

最新更新