简体   繁体   English

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

[英]Global names between main and shared library not visible

I compiled a shared library with gcc and linked it to my main. 我用gcc编译了一个共享库,并将其链接到我的主库。 The main class should initialize a logger class, which should be visible inside the shared library, but it looks as if the shared library has it's own instance of it. 主类应该初始化一个记录器类,该类在共享库中应该可见,但是看起来共享库拥有它自己的实例。

The include file looks like this: 包含文件如下所示:

extern Log gLog;

In main it is declared. 主要是声明。

Log gLog(new StreamWriter());

When I try to link it, I get linker errors undefined symbol _gLog in the shared library. 当我尝试链接它时,在共享库中出现undefined symbol _gLog链接器错误。 I thought that it might be because it is a class instance, so I changed it to a pointer, but I get the same. 我以为可能是因为它是一个类实例,所以我将其更改为指针,但是我得到了相同的结果。 To make it worse, I figured I could create a small dummy module where I create the same global variable in the shared library and then call a function to initialize it. 更糟糕的是,我认为可以创建一个小的虚拟模块,在其中在共享库中创建相同的全局变量,然后调用一个函数对其进行初始化。 But for this function I also get a linker error because it is not visible in main. 但是对于此功能,我也会收到一个链接器错误,因为它在main中不可见。

In the shared library: 在共享库中:

Log *gLogger;

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

And in main: 而在主要方面:

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

Again I get an undefined symbol in the linker, this time for my initLibrary function. 再次,我的initLibrary函数在链接器中得到一个未定义的符号。

For now I solve the problem by creating a dummy class, which works. 现在,我通过创建一个可以正常工作的虚拟类来解决该问题。 However, I would like to know how to properly define symbols across shared library boundaries, as my understanding seems to be wrong about it. 但是,我想知道如何跨共享库边界正确定义符号,因为我的理解似乎是错误的。

When using google I found some threads here Using a global variable in a shared library and Global variables, shared libraries and -fPIC effect as examples (there are several others as well with this problem). 使用谷歌时,我在这里发现了一些线程,这些线程在共享库中使用全局变量,并在全局变量,共享库和-fPIC效果中作为示例(此问题还有其他几个)。 However I tried to recompile everything with -fpic , also the main module and it still doesn't work. 但是,我尝试使用-fpic (也是主模块)重新编译所有-fpic ,但仍然无法正常工作。 The -rdynamic option is unknown so I don't know where this comes from. -rdynamic选项是未知的,所以我不知道它来自哪里。

I can use classes from the shared library and vice versa, so this affects only global symbols. 我可以使用共享库中的类,反之亦然,因此这仅影响全局符号。 So what am I doing wrong that the main code and the shared library can not see symbols from each other? 那么,我的主代码和共享库看不到彼此的符号,那我在做错什么呢?

The right approach is to create the instance of the Logger inside the shared library, using either a global variable (better if encapsulated in a namespace) or a Singleton class. 正确的方法是创建共享库内部的记录器的情况下,使用一个全局变量(更好,如果封装在命名空间)或一个单独的类。 Then let your main program use it. 然后让您的主程序使用它。

You need to declare you variables with default visibility to make it visible to other shared libraries or the main program. 您需要声明具有默认可见性的变量,以使其对其他共享库或主程序可见。 It appears that you are compiling with -fvisibility=hidden , so that a symbol in the library does not resolve to a definition in the main program or other libraries and vice versa. 看来您正在使用-fvisibility=hidden进行编译,因此库中的符号不​​会解析为主程序或其他库中的定义,反之亦然。 With the visibility attribute of GCC, you can reverse this effect. 使用GCC的可见性属性,您可以取消此效果。

In a nutshell 简而言之

  • scope visibility of a declaration across entities of a single object file (global, local, ..) 跨单个对象文件(全局,本地,..)的实体的声明的作用域可见性
  • linkage visibility of a declaration across entities of multiple object files (external, internal) 跨多个对象文件(外部,内部)的实体的声明的链接可见性
  • visibility visibility of a declaration across entities of different shared libraries (default, hidden). 可见性声明在不同共享库的实体之间的可见性(默认,隐藏)。

Another possibility is that you are mixing C and C++ code and messing up with the language linkage. 另一种可能性是您正在混合C和C ++代码并弄乱了语言链接。

I finally found the problem why this didn't work for global symbols(no problem with classes). 我终于找到了一个问题,为什么这不适用于全局符号(类没有问题)。

I'm compiling under cygwin, and apparently the shared object is compiled as a DLL. 我在cygwin下进行编译,显然共享对象被编译为DLL。 I tried to look into the library and notized that it is an EXE format and not ELF. 我试图查看该库,并通知它是EXE格式而不是ELF。 So I tried to use the Microsoft DLL syntax for exporting symbols and suddenly it worked. 因此,我尝试使用Microsoft DLL语法导出符号,然后突然起作用。 Adding a __declspec(dllexport) to the symbol did the trick. 向符号添加__declspec(dllexport)可以达到目的。

I expected that I would have to use __declspec(dllimport) in the main project for importing the symbols, but this doesn't work. 我希望我必须在主项目中使用__declspec(dllimport)来导入符号,但这是行不通的。 Not sure if I missunderstood this parameter or if the cygwin version of gcc does some magic work. 不知道我是否误解了此参数,或者cygwin版本的gcc是否做了一些魔术。

So when you compile a shared library under cygwin it must look like this if you want to export symbols. 因此,当您要导出符号时,在cygwin下编译共享库时,它必须看起来像这样。

Shared library foo.h: 共享库foo.h:

__declspec(dllexport) int foo(int a);

Shared library foo.cpp: 共享库foo.cpp:

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

In the executable foo.h: 在可执行文件foo.h中:

int foo(int a);

In the executable main.cpp: 在可执行文件main.cpp中:

main()
{
     foo(1);
}

The shared library must be compiled with the -fpic switch and linked with -shared . 共享库必须与编译-fpic交换机与链接-shared

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM