Я изучаю 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 для его сборки. Проект компилируется, но когда я его запускаю, он завершается с segfault при вызове dlinit()
.
Я натыкаюсь на мое общее отсутствие знаний о C / C ++ здесь, и мне трудно понять, что происходит в GDB вокруг вещей dlsym()
. Так что, если я правильно понимаю вещи (скажите мне, если я ошибаюсь), я объявил dlinit
как указатель функции, и когда я вызываю dlsym
, возвращаемое значение попадает в dlinit
, поэтому dlinit
должно указывать к функции, которую я ищу внутри своей библиотеки, и я должен быть в состоянии использовать ее. Я ожидал бы, что значение dlinit
будет адресом, но после dlsym()
его значение по-прежнему равно 0.
Я прочитал много интересных вещей, таких как этот ответ или что-то об атрибуте видимости для символов экспорта ( здесь ), но я нашел много примеров для gcc, и не смог найти эквивалент для clang. Наконец я прочитал о том, как я должен построить свой проект, чтобы волшебство произошло ( там ), но, опять же, мне не удалось найти эквивалент кланга.
Так чего мне здесь не хватает? При необходимости я могу предоставить файл CMakeLists.txt.