我正在学习C ++,我来自Java,我想写一些加载插件的程序。 基本上我想做的是:
正如我所说,我来自Java,而我要做的就是import somestuff;
以能够使用它。所以我试图为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
main.cpp
#include <dlfcn.h>
#include "main.h"
std::vector <std::function<void()>> Test::initFuncList;
bool Test::registerInitFunc(std::function<void()> Func)
{
initFuncList.push_back(Func);
return true;
}
int main()
{
static bool (*dlinit)(void);
printf("opening library.\n");
void* dlh = dlopen("./libtest.so", RTLD_NOW);
if (!dlh)
{
fprintf(stderr, "dlopen failed: %s\n", dlerror());
exit(EXIT_FAILURE);
}
printf("Library opened.\n Reading init function address.\n");
*(void **) (&dlinit) = dlsym(dlh, "init");
printf("Function address is %p.\n", dlinit);
if(!dlinit())
{
exit(EXIT_FAILURE);
}
printf("Library initialized, function registered.\n");
for(auto func : Test::initFuncList)
{
printf("Looping through registered functions.\n");
func();
}
return EXIT_SUCCESS;
}
exportlib.h
#ifndef LIB_H
#define LIB_H
class Lib
{
public:
Lib();
static void func(void);
static bool init(void);
};
#endif // LIB_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项目,并且正在使用CLang 7.0.0来构建它。该项目已构建,但是在我运行它时,它在dlinit()
调用中因段错误而崩溃。
在这里,我对自己普遍缺乏C / C ++的知识感到沮丧,并且我很难理解dlsym()
周围的GDB中会发生什么。因此,如果我正确理解了事情(如果我错了,请告诉我),我已经声明dlinit
作为函数指针,并且当我调用dlsym
时,返回值进入dlinit
因此dlinit
应该指向我正在库中寻找的函数,并且我应该能够使用它。我希望dlinit
的值是一个地址,但是在dlsym()
之后,它的值仍为0。
我已经阅读了很多有趣的内容,例如this answer或有关导出符号的可见性属性(here)的内容,但是我发现了很多gcc的示例,但未能找到等效的lang。最终,我了解了有关构建项目以使魔术发生的方式(there)的内容,但是再次,我找不到等效的clang。
那么我在这里想念的是什么?如果需要,我可以提供CMakeLists.txt文件。
答案 0 :(得分:2)
在调用其指向的函数之前,应检查dlinit
指针的值:
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");
返回null,因为export lib没有名为init
的符号,而是bool ::Lib::init(void)
的C ++符号有误。如果要使用dlsyn获取符号,则应为库提供一个C接口。那就是出口
extern "C" int init(void);