Наверняка, все знают чем отличается динамические библиотеки от статических. Но всё же я повторю. Когда вы используете статические библиотеки, их код внедряется в программный код вашей программы на этапе компиляции. Когда же вы используете динамические библиотеки, то их загрузка происходит уже после запуска приложения.
Что нам даст такой подход? А то, что наша программа сможет быть динамически расширяемой. А это даёт неограниченные возможности в масштабировании приложения. К тому же, если приложение большое и тяжелое, это позволит разгрузить его. У модульного программирования много преимуществ, не буду про это писать, а расскажу о своём примере.
Итак, мы создадим 2 библиотеки:
- одна будет содержать обычную функцию, при вызове которой мы будем получать текст в stdoutput;
- другая будет содержать класс, который содержит функцию на подобие той, что описана Выше.
Далее, мы создадим программу, подгружающую эти библиотеки и вызывающую функции из них.
Для начала, создадим файл test.cpp с следующим содержанием:
#include <iostream> //Наша функция, которую мы будем запускать из нашего приложения. extern "C" void test() { std::cout << "This message from test.so function test" << std::endl; }Теперь скомпилируем это всё в библиотеку
g++ -shared -o test.so test.cppНа выходе получаем test.so Теперь проверим есть ли у нашей библиотеки доступные функции. Воспользуемся командой nm, которая не заменима при работе с библиотеками или объектниками, выполним:
nm test.soВывод будет следующего вида:
Большая буква "T" напротив имени функции test, означает что она объявлена в текстовой области. Это как раз то, что нужно нам.
Дальше начнём создавать наш класс TestClass
header:
#ifndef TEST_CLASS_HPP #define TEST_CLASS_HPP #include <iostream> class Test_Class{ public: Test_Class(){}; ~Test_Class(){}; virtual void test_func(); }; //Определяем тип класса typedef Test_Class* new_class_t(); typedef void delete_class_t(); #endifsource:
#include "test_class.h" void Test_Class::test_func() { std::cout << "This message from test.so class Test_Class function test" << std::endl; } //Внешняя функция создания класса extern "C" Test_Class* new_class() { return new Test_Class; } //Внешняя функция удаления класса extern "C" void delete_class(Test_Class* temp) { delete temp; }Скомпилируем:
g++ -shared -o test_class.so test_class.cpp
Так, вроде всё готово, осталось создать саму программу, которая будет всем этим пользоваться.
main.cpp:
#include <iostream> #include <dlfcn.h> #include "test_class.h" int open_function() { //Открываем динамическую библиотеку void* handle = dlopen("./test.so", RTLD_LAZY); //Проверяем на ошибки if (!handle) { std::cerr << dlerror() << std::endl;; return 1; } //Определяем тип typedef void (*test_t)(); //Загружаем нужную нам функцию. test_t test = (test_t) dlsym(handle, "test"); //Проверяем на ошибки if (dlerror()) { std::cerr << dlerror() << std::endl; dlclose(handle); return 1; } //Исполняем функцию из библиотеки test(); //Закрываем библиотеку dlclose(handle); return 0; } int open_class_function() { //Открываем динамическую библиотеку с классом void *handle_c = dlopen("./test_class.so", RTLD_LAZY); //Проверяем на ошибки if (!handle_c) { std::cerr << dlerror() << std::endl;; return 1; } //Загружаем фукнции по созданию класса. new_class_t* new_class = (new_class_t*) dlsym(handle_c, "new_class"); delete_class_t* delete_class = (delete_class_t*) dlsym(handle_c, "delete_class"); //Проверяем на ошибки if (!new_class || !delete_class) { std::cerr << dlerror() << std::endl; return 1; } //Создаём класс Test_Class* test_class = new_class(); //Исполняем функцию из класса test_class->test_func(); //Удаляем класс delete_class(); //Закрываем библиотеку dlclose(handle_c); //Выходим } int main() { if(open_function() == 1) std::cout << "open_function missed" << std::endl; if(open_class_function()==1) std::cout << "open_class_function missed" << std::endl; return 0; }Компилируем
g++ -o dlopen_example main.cpp -ldlВсё осталось только запустить и убедиться, что всё действительно работает!
Удачного Вам освоения dlopen!
sources
Комментариев нет:
Отправить комментарий