В этой заметке я опишу пример добавления функционала в C++ приложение с помощью плагинов. Описана практическая часть реализации для Linux, с теорией можно будет ознакомиться по ссылкам в конце статьи.
Для начала напишем плагин – функцию которую будем вызывать:
#include "iostream" using namespace std; extern "C" void extensionEntryPoint() { cout << "Extension entry point called" << endl; };
Далее соберем плагин как динамическую библиотеку “extension.so”, которую и будем подключать в дальнейшем:
clang++ -shared -fPIC extension.cpp -o extension.so
Напишем основое приложение, которое будет загружать файл “extension.so”, искать там указатель на функцию “extensionEntryPoint”, и вызывать его, печатая ошибки при необходимости:
#include "iostream" #include "dlfcn.h" using namespace std; typedef void (*VoidFunctionPointer)(); int main (int argc, char *argv[]) { cout << "C++ Plugins Example" << endl; auto extensionHandle = dlopen("./extension.so", RTLD_LAZY); if (!extensionHandle) { string errorString = dlerror(); throw runtime_error(errorString); } auto functionPointer = VoidFunctionPointer(); functionPointer = (VoidFunctionPointer) dlsym(extensionHandle, "extensionEntryPoint"); auto dlsymError = dlerror(); if (dlsymError) { string errorString = dlerror(); throw runtime_error(errorString); } functionPointer(); exit(0); }
Функция dlopen возвращает хэндлер для работы с динамической библиотекой; функция dlsym возвращает указатель на необходимую функцию по строке; dlerror содержит указатель на строку с текстом ошибки, если таковая имеется.
Далее собираем основное приложение, копируем файл динамической библиотеки в папку с ним и запускаем. На выходе должен быть вывод “Extension entry point called”
К сложным моментам можно отнести отсутствие единого стандарта работы с динамическими библиотеками, из-за этого есть необходимость экспорта функции в относительно глобальную область видимости с extern C; разница в работе с разными операционными системами, связанные с этим тонкости работы; отсутствие C++ интерфейса для реализации ООП подхода к работе с динамическими библиотеками, однако существуют open-source врапперы, например m-renaud/libdlibxx
Исходный код примера
https://gitlab.com/demensdeum/cpppluginsexample
Источники
http://man7.org/linux/man-pages/man3/dlopen.3.htm
https://gist.github.com/tailriver/30bf0c943325330b7b6a
https://stackoverflow.com/questions/840501/how-do-function-pointers-in-c-work