当.so尝试使用主可执行文件中的类时,dlopen()给出未解析的符号错误.为什么?

den*_*s90 2 c++ plugins shared-libraries

我在Linux上,问题是关于C++类的共享对象.

当我的共享对象尝试使用链接到主可执行文件的资源时,问题就出现了.我有以下代码:

loader.cpp:

#include <dlfcn.h>
#include <iostream>
#include "CommonInfo.h"

using namespace std;

int main(int argc, char** argv) {
    for(int i=1; i<argc; ++i) {
        string pth = "./";
        pth.append(argv[i]);
        void* dh = dlopen(pth.c_str(), RTLD_NOW);
        if(dh==NULL) {
            cerr << dlerror() << endl;
            return 1;
        }

        CommonInfo::GetInfoFunc getInfo = (CommonInfo::GetInfoFunc)(dlsym(dh,"getInfo"));
        if(getInfo==NULL) {
            cerr << dlerror() << endl;
            return 1;
        }

        CommonInfo* info = getInfo();
        cout << "INFO: " << info->getX() << endl;
        delete info;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

CommonInfo.h:

#include <string>

class CommonInfo {
    public:
        typedef CommonInfo* (*GetInfoFunc)();
    private:
        std::string x;
    public:
        CommonInfo(const std::string& nx);
        std::string getX() const;
};
Run Code Online (Sandbox Code Playgroud)

编辑:我不小心忘记了ctrl-c + ctrl-v这里CommonInfo.cpp的来源.当然,它在编译期间存在,所以CommonInfo.cpp:

#include "CommonInfo.h"

CommonInfo::CommonInfo(const std::string& nx) : x(nx) {
}

std::string CommonInfo::getX() const {
    return x;
}
Run Code Online (Sandbox Code Playgroud)

一个Plugin.h头:

#include "CommonInfo.h"
extern "C" CommonInfo* getInfo();
Run Code Online (Sandbox Code Playgroud)

一个非常简单的Plugin.cpp:

#include <iostream>
#include "Plugin.h"
#include "CommonInfo.h"

using namespace std;

CommonInfo* getInfo() {
    return new CommonInfo("I'm a cat!");
}
Run Code Online (Sandbox Code Playgroud)

编译完成:

g++ -rdynamic -ldl -Werror CommonInfo.cpp loader.cpp -o loader
g++ -shared -fPIC -Werror Plugin.cpp -o Plugin.so
Run Code Online (Sandbox Code Playgroud)

运行:

./loader Plugin.so
Run Code Online (Sandbox Code Playgroud)

出现了错误:

./loader: symbol lookup error: ./Plugin.so: undefined symbol: _ZN10CommonInfoC1ERKSs
Run Code Online (Sandbox Code Playgroud)

实际上,在里面查看Plugin.so nm Plugin.so | grep -i CommonInfo会给出这个符号的"U"(未解决),这是完全可以的.另外,查看加载器的二进制文件,nm loader.so | grep -i CommonInfo我可以找到带有'T'的符号,这也没关系.问题是,dlfcn.h是否应该从主二进制文件中解析有问题的符号?没有这个功能,使用这些东西变得非常困难......我是否必须为CommonInfo编写一个类工厂函数,从插件加载dlfcn并调用它?

丹尼斯,先谢谢你

asv*_*kau 5

我没有密切关注你的代码,但我过去发现了当你没有链接可执行文件时,你在标题中描述的行为-E.(或者-Wl,-E在链接gcc时而不是ld.)

请注意,并非所有平台都允许共享库从调用二进制文件中获取符号.Linux和*BSD允许你.但是,如果您想要移植到Windows,那么您将无法使用此模式.我相信还有一些Unix类型的操作系统不会让你这样做.(已经有一段时间了,所以我不记得了......也许是Solaris?)