До сих пор мы писали с Вами простые динамические библиотеки, поэтому у нас не болела голова об инициализации внутренних переменных. А представьте себе более сложную ситуацию, когда функции библиотеки для работы требуют правильно инициализированные переменные. Ну, например, для работы функции нужен буфер или массив.
Специально для таких случаев в библиотеках можно задавать инициализирующую и деинициализирующую функции:
Чтобы понять, что к чему, введем в нашей библиотеке 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 ничем не хуже...