До сих пор мы писали с Вами простые динамические библиотеки, поэтому у нас не болела голова об инициализации внутренних переменных. А представьте себе более сложную ситуацию, когда функции библиотеки для работы требуют правильно инициализированные переменные. Ну, например, для работы функции нужен буфер или массив.
Специально для таких случаев в библиотеках можно задавать инициализирующую и деинициализирующую функции:
Чтобы понять, что к чему, введем в нашей библиотеке lib.c переменную test и возвращающую ее функцию:
char *test; char *ret_test(){ return test; };
Пишем основную программу main.c. Она очень похожа на предыдущий наш проект, поэтому можете его модифицировать:
#include <stdio.h> #include <dlfcn.h> int main(){ void *ext_library; double value=0; char * (*ret_test)(); ext_library = dlopen("libtest.so",RTLD_LAZY); if (!ext_library){ fprintf(stderr,"dlopen() error: %s\n", dlerror()); return 1; }; ret_test = dlsym(ext_library,"ret_test"); printf("Return of ret_test: \"%s\" [%p]\n",(*ret_test)(),(*ret_test)()); dlclose(ext_library); return 0; };
После компиляции всего этого хозяйства мы получим результат:
dron:~# gcc -c lib.c -fPIC dron:~# gcc -shared lib.o -o libtest.so dron:~# gcc -o main main.c -ldl dron:~# ./main Return of ret_test: "(null)" [(nil)] dron:~#
Как видите переменная test оказалась равной NULL, а нам бы хотелось нечто другое. Ну, так давайте посмотрим как работают функции _init() и _fini(). Создадим вторую библиотеку lib1.c:
#include <stdlib.h> char *test; char *ret_test() { return test; }; void _init() { test = (char *)malloc(6); if (test != NULL){ *(test + 0) = 'd'; *(test + 1) = 'r'; *(test + 2) = 'o'; *(test + 3) = 'n'; *(test + 4) = '!'; *(test + 5) = 0; }; printf("_init() executed...\n"); }; void _fini() { if (test != NULL) free(test); printf("_fini() executed...\n"); };
Теперь пробуем компилировать:
dron:~# gcc -c lib1.c -fPIC dron:~# gcc -shared lib1.o -o libtest.so lib1.o: In function `_init': lib1.o(.text+0x24): multiple definition of `_init' /usr/lib/crti.o(.init+0x0): first defined here lib1.o: In function `_fini': lib1.o(.text+0xc0): multiple definition of `_fini' /usr/lib/crti.o(.fini+0x0): first defined here collect2: ld returned 1 exit status dron:~#
Опаньки... Облом. Что же это такое ?! Оказывается кто-то уже использовал эти функции до нас и программа не может слинковаться. После долгого копания в нескольких чужих исходниках я получил ответ на этот вопрос. Оказывается, чтобы избавиться от мешающей библиотеки надо использовать ключ компилятора -nostdlib. Попробуем:
dron:~# gcc -shared -nostdlib lib1.o -o libtest.so dron:~#
Смотрите-ка, все прекрасно скомилировалось. Теперь попробуем запустить main:
dron:~# ./main _init() executed... Return of ret_test: "dron!" [0x8049c20] _fini() executed... dron:~#
Ну как ? Помоему классно. Теперь можно спокойно создавать для работы библиотеки правильно инициализированные переменные. Однако классные эти штуки - динамические библиотеки ! А Вы что хотели ? Тот же Windows только на своих DLL и живет. А Linux ничем не хуже...