主库和共享库之间的全局名称不可见

时间:2013-05-24 06:39:55

标签: c++ shared-libraries

我用gcc编译了一个共享库,并将它链接到我的main。主类应该初始化一个logger类,该类应该在共享库中可见,但看起来好像共享库有它自己的实例。

包含文件如下所示:

extern Log gLog;

主要是声明。

Log gLog(new StreamWriter());

当我尝试链接它时,我在共享库中收到链接器错误undefined symbol _gLog。我认为这可能是因为它是一个类实例,所以我把它改成了一个指针,但我得到了同样的结果。更糟糕的是,我想我可以创建一个小的虚拟模块,我在共享库中创建相同的全局变量,然后调用一个函数来初始化它。但是对于这个函数,我也会得到一个链接器错误,因为它在main中不可见。

在共享库中:

Log *gLogger;

int initLibrary(Log *pLogger)
{
    gLogger = pLogger;
}

主要是:

Log gLog(new StreamWriter());
int initLibrary(Log *pLogger);
main()
{
    initLibrary(&gLog);
}

我再次在链接器中获得一个未定义的符号,这次是我的initLibrary函数。

现在我通过创建一个有效的虚拟类来解决问题。但是,我想知道如何在共享库边界之间正确定义符号,因为我的理解似乎是错误的。

使用谷歌时,我在这里找到了一些帖子Using a global variable in a shared libraryGlobal variables, shared libraries and -fPIC effect作为示例(此问题还有其他几个)。但是我尝试使用-fpic重新编译所有内容,也是主模块,但仍然无效。 -rdynamic选项未知,因此我不知道它来自何处。

我可以使用共享库中的类,反之亦然,因此这只会影响全局符号。那么主要代码和共享库无法看到彼此的符号,我做错了什么呢?

3 个答案:

答案 0 :(得分:1)

正确的方法是使用全局变量(如果封装在命名空间中更好)或Singleton类,在共享库中创建Logger 的实例。然后让你的主程序使用它。

答案 1 :(得分:0)

您需要使用默认可见性声明变量,以使其对其他共享库或主程序可见。您似乎正在使用-fvisibility=hidden进行编译,因此库中的符号无法解析为主程序或其他库中的定义,反之亦然。使用GCC的visibility属性,您可以反转此效果。

简而言之

  • 范围单个对象文件(全局,本地,..)实体的声明可见性
  • 链接多个目标文件(外部,内部)实体的声明可见性
  • 可见性跨不同共享库的实体(默认,隐藏)的声明的可见性。

另一种可能性是你正在混合使用C和C ++代码并弄乱语言链接。

答案 2 :(得分:0)

我终于找到了为什么这对全局符号不起作用的问题(类没有问题)。

我正在cygwin下编译,显然共享对象被编译为DLL。我试图查看库并注意它是EXE格式而不是ELF。所以我尝试使用Microsoft DLL语法导出符号,突然它起作用了。在符号中添加__declspec(dllexport)就可以了。

我预计我必须在主项目中使用__declspec(dllimport)来导入符号,但这不起作用。不确定我是否错过了解这个参数,或者gg的cygwin版本是否做了一些神奇的工作。

因此,当您在cygwin下编译共享库时,如果要导出符号,它必须如下所示。

共享库foo.h:

__declspec(dllexport) int foo(int a);

共享库foo.cpp:

int foo(int a)
{
 ....
}

在可执行文件foo.h中:

int foo(int a);

在可执行文件main.cpp中:

main()
{
     foo(1);
}

共享库必须使用-fpic开关进行编译,并与-shared链接。