gpt4 book ai didi

c++ - Linux、Clang、Cmake、QtCreator : Using shared libraries

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:03:29 35 4
gpt4 key购买 nike

我正在学习 C++,我来自 Java,我想编写一些加载插件的程序。基本上我想做的是:

  • 运行程序
  • 加载共享库(插件)
  • 在主程序的列表中注册共享库中的一个函数
  • 在主程序中运行这些函数
  • 能够从库中使用主程序中编写的一些函数

正如我所说,我来自 Java,我要做的就是 import somestuff; 以便能够使用它。所以我试图为 C++ 解决这个问题。我读过 dlopen/dlsym 可以是一个解决方案,所以我阅读了那些手册页和一些示例,这就是我所做的:

主要.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

主要.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;
}

导出库

#ifndef LIB_H
#define LIB_H

class Lib
{
public:
Lib();
static void func(void);
static bool init(void);
};

#endif // LIB_H

导出库.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++ 的普遍缺乏知识,而且我很难理解 GDB 中围绕 dlsym() 东西发生了什么。因此,如果我理解正确(如果我错了请告诉我),我已将 dlinit 声明为函数指针,并且当我调用 dlsym 时,返回值得到在 dlinit 中,所以 dlinit 应该指向我在我的库中寻找的函数,我应该能够使用它。我希望 dlinit 的值是一个地址,但在 dlsym() 之后它的值仍然是 0。

我读了很多有趣的东西,比如this answer ,或关于导出符号的可见性属性的事情(here),但我找到了很多 gcc 的例子,但没有找到 clang 的等价物。最后,我读到了有关构建项目以实现奇迹的方式的内容 (there),但同样,我没能找到等效的 clang。

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

最佳答案

在调用它指向的函数之前,您应该检查 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,因为导出库没有名为 init 的符号,而是有一个损坏的 C++ 符号对于 bool::Lib::init(void)。如果你想用 dlsyn 获取符号,你应该为你的库提供一个 C 接口(interface)。即导出

extern "C" int init(void);

关于c++ - Linux、Clang、Cmake、QtCreator : Using shared libraries,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53294786/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com