Linux、Clang、Cmake、QtCreator:使用共享库 我学习C++,我来自java,我想编写一些加载插件的程序。 基本上我想做的是: 运行程序 加载共享库(插件) 在主程序的列表中从共享库注册一个函数 在主程序中运行这些函数 能够使用libs主程序中编写的一些函数

Linux、Clang、Cmake、QtCreator:使用共享库 我学习C++,我来自java,我想编写一些加载插件的程序。 基本上我想做的是: 运行程序 加载共享库(插件) 在主程序的列表中从共享库注册一个函数 在主程序中运行这些函数 能够使用libs主程序中编写的一些函数,c++,linux,shared-libraries,C++,Linux,Shared Libraries,正如我所说,我来自Java,我所要做的就是导入一些东西以便能够使用它。所以我试着去理解C++。我已经读到dlopen/dlsym可以是一个解决方案,所以我阅读了这些手册页面和一些示例,下面是我所做的: main.h #ifndef MAIN_H #define MAIN_H #include <functional> #include <vector> class Test{ public : static std::vector <std::fu

正如我所说,我来自Java,我所要做的就是
导入一些东西以便能够使用它。所以我试着去理解C++。我已经读到dlopen/dlsym可以是一个解决方案,所以我阅读了这些手册页面和一些示例,下面是我所做的:

main.h

#ifndef MAIN_H
#define MAIN_H
#include <functional>
#include <vector>

class Test{
    public :
    static std::vector <std::function<void()>> initFuncList;
    static bool registerInitFunc(std::function<void()> Func);
};

#endif // MAIN_H
exportlib.cpp

#include "exportlib.h"
#include "main.h"

Lib::Lib(){}

bool Lib::init()
{
    printf("Initializing library.\n");
    return (Test::registerInitFunc(func));
}

void Lib::func()
{
    printf("This is the library function called after initialization.\n");
}
我使用QtCreator作为IDE,解析CMake项目,并使用clang7.0.0构建它。该项目会生成,但当我运行它时,它会在调用
dlinit()
时与segfault一起崩溃

我在这里遇到了一个绊脚石,就是我对C/C++的知识普遍缺乏,我很难理解GDB中关于
dlsym()
的东西发生了什么。因此,如果我理解正确(如果我错了,请告诉我),我将
dlinit
声明为函数指针,当我调用
dlsym
时,返回值将进入
dlinit
,因此
dlinit
应该指向我在库中查找的函数,我应该能够使用它。我希望
dlinit
的值是一个地址,但在
dlsym()
之后,它的值仍然是0

我读了很多有趣的东西,比如,或者关于导出符号()的可见性属性的东西,但是我找到了很多gcc的例子,但是没有找到与clang等效的例子。最后,我读了一些关于我应该如何构建我的项目来实现这个神奇的事情(),但我还是没有找到与之相当的叮当声


那么我在这里错过了什么?如果需要,我可以提供CMakeLists.txt文件。

在调用指针指向的函数之前,您应该检查指针的值:

if(not dlinit)
{
    auto const psz_error{::dlerror()};
    fprintf(stderr, "dlsym failed to fetch init: %s\n", (psz_error ? psz_error : "unknown"));
    exit(EXIT_FAILURE);
}
现在最有可能的是
dlsym(dlh,“init”)返回空,因为导出LIB没有一个名为“代码> init 的符号,相反,它有一个被损坏的C++符号,用于<代码>布尔:::LI::init(空)< /C>。如果您想使用dlsyn获取符号,您应该为您的库提供一个C接口。那就是出口

extern "C" int init(void);

谢谢你的回答。我可能遗漏了什么。如果我声明一个
extern“C”intinit(void)函数,我不能(我想)同时将其声明为静态。我必须在main.cpp中包含exportlib.h,对吗?我该怎么做呢?因为我不想每次新插件出现时都构建我的应用程序,或者更现实一些,我不想让我的用户构建我的应用程序,他们只需要编写插件,用我的头构建插件,然后用插件使用应用程序。也许我应该在我的问题中添加这一点?@aTom C接口意味着所有导出的函数都是全局命名空间中的自由函数
exportlib.h
实际上是应用程序声明插件接口的一部分,所以当应用程序更改其接口时,它应该更改。
if(not dlinit)
{
    auto const psz_error{::dlerror()};
    fprintf(stderr, "dlsym failed to fetch init: %s\n", (psz_error ? psz_error : "unknown"));
    exit(EXIT_FAILURE);
}
extern "C" int init(void);