Функции работы с динамическими библиотеками |
Функции работы с динамическими библиотеками Если Вы подумали, что фокусы с динамическими библиотеками кончились, то Вы очень сильно ошиблись. До того были цветочки, а ягодки будут сейчас :) Оказывается, что использовать динамические библиотеки можно не только в начале загрузки, но и в процессе самой работы программы. Программа сама может вызывать любые функции из библиотеки, когда ей захочется. Для этого всего-лишь надо использовать библиотеку dl, которая позволяет линковать библиотеки "на лету". Она управляет загрузкой динамических библиотек, вызовом функций из них и выгрузкой после конца работы. Для использования функций программной работы с динамическими библиотеками необходимо подключить заголовочный файл: #include <dlfcn.h> Чтобы вызывать какие-то функции из динамической библиотеки сначала надо открыть эту библиотеку (можно сказать "загрузить"). Открывается она функцией: void *dlopen (const char *filename, int flag); Параметр filename содержит путь до требуемой библиотеки, а параметр flag задает некоторые специфические флаги для работы. Функция возвращает указатель на загруженную библиотеку. В случае любой ошибки возвращается указатель NULL. В таком случае тест ошибки понятный человеку можно получить с помощью функции dlerror(). Пока мы не будем задумываться над этим, и я приведу стандартный код для открытия библиотеки: void *library_handler; //...... //загрузка библиотеки library_handler = dlopen("/path/to/the/library.so",RTLD_LAZY); if (!library_handler){ //если ошибка, то вывести ее на экран fprintf(stderr,"dlopen() error: %s\n", dlerror()); exit(1); // в случае ошибки можно, например, закончить работу программы }; После этого можно работать с библиотекой. А работа эта заключается в получении адреса требуемой функции из библиотеки. Получить адрес функции или переменной можно по ее имени с помощью функции: void *dlsym(void *handle, char *symbol); Для этой функции требуется адрес загруженной библиотеки handle, полученный при открытии функцией dlopen(). Требуемая функция или переменная задается своим именем в переменной symbol. Закрывается библиотека функцией: dlclose(void *handle); При закрытии библиотеки динамический линковщик проверяет счетчик количества открытий библиотеки, и если она была открыта несколькими программами одновременно, то она не выгружается до тех пор, пока все программы не закроют эту библиотеку. Для примера создадим программу, которая в качестве параметра получает название функции, которую она будет использовать в работе. Например, это будут математические функции возведения в степень. Создадим сначала динамическую библиотеку. Пишем ее код: double power2(double x){ return x*x; }; double power3(double x){ return x*x*x; }; double power4(double x){ return power2(x)*power2(x); }; //...... Сохраняем его в файл lib.c и создаем динамическую библиотеку libpowers.so следующими командами: dron:~# gcc -fPIC -c lib.c dron:~# gcc -shared lib.o -o libpowers.so Теперь создаем основную программу в файле main.c: #include <stdio.h> /* заголовочный файл для работы с динамическими библиотеками */ #include <dlfcn.h> int main(int argc, char* argv[]){ void *ext_library;// хандлер внешней библиотеки double value=0;// значение для теста double (*powerfunc)(double x);// переменная для хранения адреса функции //загрузка библиотеки ext_library = dlopen("/root/libpowers.so",RTLD_LAZY); if (!ext_library){ //если ошибка, то вывести ее на экран fprintf(stderr,"dlopen() error: %s\n", dlerror()); return 1; }; //загружаем из библиотеки требуемую процедуру powerfunc = dlsym(ext_library, argv[1]); value=3.0; //выводим результат работы процедуры printf("%s(%f) = %f\n",argv[1],value,(*powerfunc)(value)); //закрываем библиотеку dlclose(ext_library); }; Код главной программы готов. Требуется его откомпилировать с использованием библиотеки dl: dron:~# gcc main.c -o main -ldl Получим программный файл main, который можно тестировать. Наша программа должна возводить значение 3.0 в требуемую нами степень, которая задается названием функции. Давайте попробуем: dron:~# ./main power2 power2(3.000000) = 9.000000 dron:~# ./main power3 power3(3.000000) = 27.000000 dron:~# ./main power4 power4(3.000000) = 81.000000 dron:~# Ну, как ?! Круто !!! Мы используем какие-то функции, зная лишь их название. Представьте открывающиеся возможности для программ, на основе этого метода можно создавать плагины для программ, модернизировать какие-то части, добавлять новые возможности и многое другое. |