- •Методические указания для выполнения лабораторной работы № 4 по курсу «Операционные системы и системное программирование»
- •Цель работы
- •Краткие теоретические сведения Статические библиотеки.
- •Динамические библиотеки (shared).
- •Ход работы
- •Варинаты индивидуальных заданий
- •Содержание отчета
- •Используемые источники
Динамические библиотеки (shared).
Динамическая библиотека - библиотека, подключаемая к программе в момент выполнения. Это означает, что при создании библиотеки производится не только ее компиляция, но и линковка с другими, нужными ей, библиотеками (!).
Динамические библиотеки полезны в случаях, если:
- Важно не перекомпилировать всю программу, а только перекомпилировать ту часть, которая реализует определенные функции - тогда эти функции выносятся в динамическую библиотеку.
- Важно использовать в программах на C библиотеки, подготовленные на C++ и при этом избежать лишних трудностей с линковкой программы.
- Кроме того, динамические библиотеки позволяют экономить место на жестком диске и в оперативной памяти, если одна и таже библиотека используется несколькими программами.
В Linux, обычно, динамические библиотеки имеют расширение ".so".
Подготовим исходный код динамической библиотеки (пример на C++).
Исходный код динамической библиотеки по принципам создания ничем (!) не отличается от исходного кода статических библиотек.
Итак, исходный код библиотеки (C++):
#include <iostream>
using namespace std;
#include
extern "C" int hello()
{
cout<<"Hello world!n I'm function hello()"<<endl;
return 0;
}
Сохраните приведенный код в файле dynamic.cpp.
* Кстати, внутри динамической библиотеки вы можете описать следующие функции:
void _init() - будет вызвана при инициализации динамической библиотеки (загрузки ее в память);
void _fini() - будет вызвана при выгрузке из памяти динамической библиотеки.
Компиляция и линковка динамических библиотек.
Получим файл с объектным кодом:
g++ -fPIC -c dynamic.cpp -o dynamic.o
(используйте gcc для программ на С и Assembler'е)
Здесь:
-fPIC - использовать относительную адресацию в переходах подпрограмм - во избежание конфликтов при динамическом связывании.
А теперь из объектного файла получим библиотеку:
g++ -shared -olibdynamic.so dynamic.o
(используйте gcc для программ на С)
libdynamic.so - имя результирующей библиотеки;
-shared - предписывает создать динамическую (т.е. "разделяемую") библиотеку.
* Именуйте динамические библиотеки следующим способом: libNAME.so. Это традиция.
Итак, на выходе мы имеем libdynamic.so - нашу динамическую библиотеку.
Использование динамической библиотеки в программе на C/C++.
Связывание с библиотекой во время компиляции программы (C/C++):
Подготовим исходный код нашей программы:
int main()
{
int x = hello();
printf("Return code: %xn",x);
return 0;
}
Сохраните его в файле Dprogram1.c
ИЛИ
(С++)
#include
extern "C" int hello();
int main()
{
int x = hello();
printf("Return code: %xn",x);
return 0;
}
Сохраните его в файле Dprogram1.cpp
(единственное отличие, как вы можете заметить, в ключевом слове extern)
Теперь добьемся того, чтобы система смогла найти нашу библиотеку. Поместим libdynamic.so в один из каталогов:
из списка:
echo $LD_LIBRARY_PATH
/lib
/usr/lib
или из списка:
cat /etc/ld.so.conf
и затем выполните "ldconfig"
И, наконец, скомпилируем программу и слинкуем ее с библиотекой:
gcc ИСХОДНИК -lИМЯ_БИБЛИОТЕКИ -o РЕЗУЛЬТИРУЮЩИЙ_БИНАРИК
В нашем случае: gcc Dprogram1.c -L/home/amv/c/libs/ -ldynamic
(используйте g++ для программы на C++)
Запустим на исполнение полученный файл:
./a.out
В итоге должно получится:
Hello world!
I'm function hello()
Return code: 0
Связывание с библиотекой во время исполнения программы (C/C++):
Бывает необходимо подключать библиотеку во время выполнения программы. Для этого можно использовать функционал из заголовочного файла.
Исходный код примера (C):
#include <stdio.h>
#include < dlfcn.h >
int main()
{
void *handle = dlopen("libdynamic.so",RTLD_LAZY);
int(*fun)(void) = dlsym(handle,"hello");
int x = (*fun)();
dlclose(handle);
printf("Return code: %dn",x);
return 0;
};
Сохраните его в файле Dprogram2.c
В dlfcn.h определены следующие функции:
void* dlopen("PATH_AND_NAME",FLAG) - загружает в память динамическую библиотеку с полным именем PATH_AND_NAME и возвращает ее описатель (HANDLE) (NULL в случае неудачи). FLAG - флаги, описанные в "man dlopen";
void* dlsym(HANDLE,"NAME") - возвращает указатель на функцию/переменную, импортируемую из библиотеки;
int dlclose(HANDLE) - выгружает библиотеку из памяти;
const char *dlerror() - получить сообщение о последней возникшей ошибке (NULL - если ошибок не произошло с момента последнего вызова dlerror).
Выполняем:
gcc -ldl Dprogram2.c
(используйте g++ для программы на C++)
Запустим на исполнение полученный файл:
./a.out
В итоге должно получиться:
Hello world!
I'm function hello()
Return code: 0
* Важно! Нет необходимости помещать библиотеку в один из специальных каталогов, модифицировать переменные окружения и выполнять "ldconfig"