2

在 C++ 中,可以从动态库中访问外部定义的全局变量吗?

我在头文件中声明了一个全局变量,如下所示;

文件名:TestVariable.hpp

#ifndef TESTVARIABLE_HPP
#define TESTVARIABLE_HPP

extern
int   testVariable;

#endif 

然后在源代码文件中定义如下;

文件名:TestVariable.cpp

int   testVariable;

构成我的动态库的源代码如下;

文件名:插件.cpp

#include <TestVariable.hpp>

#ifdef __cplusplus
extern "C" {
#endif

void *
__attribute__((constructor))
loadLibrary
(
 void
)
{
    testVariable = 100;
}

void *
__attribute__((destructor))
unloadLibrary
(
 void
)
{
}

#ifdef __cplusplus
}
#endif

然后我的主要功能定义如下;

文件名:main.cpp

#include <iostream>
#include <dlfcn.h>
// dlopen
#include <TestVariable.hpp>

using std::cout;
using std::endl;

int main(void)
{
    void * libHandle_p = NULL;


    cout << "Test variable = " << testVariable << endl;

    // Load the dynamic library.

    libHandle_p = dlopen("./.libs/libPlugin.so", RTLD_LAZY);

    if (libHandle_p == NULL)
    {
        cout << "Error loading library" << endl;
        return(-1);
    }

    cout << "Test variable = " << testVariable << endl;
    return(0);
}

我可以使用 GNU Autotools、g++ 和 ld 正确编译和链接所有代码(并且没有任何警告),但是当我运行生成的二进制可执行文件时,它无法 dlopen 动态库文件。但是,如果我注释掉包含函数loadLibrary主体的唯一一行代码,然后重新编译和链接,则程序可以正常工作!

如果我不知道更好,我会说当 dlopen 调用它(库)时,库无法解析其对全局变量testVariable的引用,这就是导致 dlopen 操作失败的原因。链接类型和/或名称修饰可能与此问题有关吗?

如果我在生成的动态库上运行 Linux nm 实用程序,它会通知我符号testVariable未定义,即“U”。如果我在二进制可执行文件上运行 nm 实用程序,它会通知我符号testVariable存在并驻留在未初始化的数据部分中,即“B”。那么为什么dlopen在加载动态库的时候不能解析这个符号呢?

我只从源文件Plugin.cpp生成动态库。二进制可执行文件是从 2 个源代码文件main.cppTestVariable.cpp 生成的。

有人可以帮忙吗。我可以发誓答案是盯着我的脸,但我只是没有看到它。

提前致谢。

4

1 回答 1

2

看来我已经解决了我自己的问题。在编译二进制可执行文件(不是动态库)时将以下参数传递给 GNU g++ 编译器可以解决问题;

-Wl,--export-dynamic

它之所以有效是因为它强制链接器将符号testVariable添加到动态符号表中,并且根据 ld 的手册页(GNU 链接器),动态符号表包含动态对象可见的符号集(我的库在这种情况下)在运行时。

带来不便敬请谅解。

于 2011-03-11T10:46:22.810 回答