7

我正在尝试在 Linux 上使用 gcc 4.6 构建一个共享库,该库是动态加载的。正如网络上的许多文章以及之前的问题中所述,我在库中提供了 c 风格的工厂方法来创建和销毁对象。代码 - 以最小形式 - 如下所示:

基地.h:

class base {
public:
  base();
  virtual ~base();
  virtual int value() = 0;
};

基础.cpp:

#include "base.h"
base::base() {}
base::~base() {}

主.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

但是在运行时它会因为缺少 typeinfo 符号而崩溃

liblib.so: undefined symbol: _ZTI4base

在我在这里找到的之前的问题中,这个错误通常是由于缺少一些“= 0;” 或缺少虚函数的定义。然而,在上面的例子中,base::value 是纯虚函数,析构函数有一个定义。奇怪的是,nm 报告了应用程序中定义的 _ZTI4base:

$ nm app | grep _ZTI4base
0000000000601050 V _ZTI4base

那么为什么链接器不使用这个定义呢?

到目前为止,我发现让代码正常工作的唯一方法是在头文件中实现构造函数和析构函数。然而,在这样做之后,base 的相应符号在 liblib.so 中由 nm 报告,并且完全从 app 中消失,这可能意味着它们的定义被编译到库中而不是 app 中,这不是我想要实现的。有没有人知道如何在不这样做的情况下使上述工作?

4

1 回答 1

2

链接程序时需要该-rdynamic选项,以导出其符号并使它们可用于加载dlopen().

于 2012-07-30T22:22:46.500 回答