Шаг 9 - Инициализация динамических библиотек

До сих пор мы писали с Вами простые динамические библиотеки, поэтому у нас не болела голова об инициализации внутренних переменных. А представьте себе более сложную ситуацию, когда функции библиотеки для работы требуют правильно инициализированные переменные. Ну, например, для работы функции нужен буфер или массив.

Специально для таких случаев в библиотеках можно задавать инициализирующую и деинициализирующую функции:

Чтобы понять, что к чему, введем в нашей библиотеке 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 ничем не хуже...


Загрузить проект | Предыдущий Шаг | Следующий Шаг | Оглавление
Автор Кузин Андрей - 27.02.2002