我正在尝试在Linux上使用gcc 4.6构建一个动态加载的共享库,与许多网站文章和之前的问题描述一样,在库中提供c风格的工厂方法来创建和销毁对象。代码的最小形式如下:
base.h:
class base {
public:
base();
virtual ~base();
virtual int value() = 0;
};
base.cpp:
#include "base.h"
base::base() {}
base::~base() {}
main.cpp:
#include "base.h"
#include <dlfcn.h>
#include <iostream>
int main() {
void* handle = dlopen("liblib.so", RTLD_NOW);
if(handle == NULL) std::cout << dlerror() << std::endl;
// dlsym, ...
}
lib.cpp:
class derived : public base {
public:
derived() {}
virtual ~derived() {}
virtual int value() { return 42; }
};
extern "C" derived* create_object() {
return new derived();
}
它可以正常编译:
g++ -shared -fPIC lib.cpp -o liblib.so
g++ base.cpp main.cpp -ldl -o app
但在运行时,由于缺少类型信息符号而导致崩溃。
liblib.so: undefined symbol: _ZTI4base
在此前我在这里找到的问题中,通常是由于某些缺少 "= 0;" 或缺少虚函数定义所致。然而,在上述例子中,base::value 是纯虚拟的,并且析构函数具有定义。奇怪的是,nm 报告 ZTI4base 在 app 中已被定义。
$ nm app | grep _ZTI4base
0000000000601050 V _ZTI4base
那么为什么链接器没有使用这个定义呢?
到目前为止,我发现使代码工作的唯一方法是在头文件中实现构造函数和析构函数。然而,在这样做之后,基类的相应符号被 nm 报告在 liblib.so 中,并从 app 中完全消失,这可能意味着它们的定义被编译到库中而不是 app 中,这不是我想要实现的。有人知道如何在不这样做的情况下使上述内容起作用吗?
nm
命令加上--demangle
参数可以查看函数的反汇编名称。 - Shahbaz