Dll libraries in linux

Блог радиста

Сегодня мы поговорим о библиотеках в Linux (подозреваю также, что многие описанные здесь вещи возможны и в других *nix-операционных системах, но это требует проверки 🙂 ).

1) Статические библиотеки (создание с помощью Assembler, C/C++; подключение и использование в программах на Assembler,C/C++);
2) Динамические библиотеки (создание с помощью Assembler, C/C++; подключение и использование в программах на C/C++l, Python).

1) Статическая библиотека — это такая библиотека, которая связывается (линкуется) с программой в момент компиляции оной. При этом объектный код библиотеки помещается в исполняемый файл программы. С этой точки зрения статическая библиотека похожа на исходный код программы, с которой она связывается, за исключением того, что библиотека компилируется «кем-то еще» и программист, использующий библиотеку, имеет дело исключительно только с результатом этой компиляции.

В Linux, как правило, файл-статическая_библиотека имеет расширение «.a»

2) Статические библиотеки на языке C.

Сохраните его в файле static.c

Ключевое слово extern необходимо для того, чтобы функция была видна в программе.

Теперь скомпилируем (! без линковки) библиотеку:

gcc -c static.c -o static.o
(на выходе имеем файл static.o, содержащий объектный код нашей библиотеки)

ar rc libMY_STATIC.a static.o

ar упаковывает несколько (! Это важно. Дело не ограничивается только одним объектным файлом) объектных файлов в одну статическую библиотеку. Статическая библиотека имеет расширение «.a», при этом ее название должно начинаться с «lib» (дань традиции).
Параметры ar:
r — предписывает заменять старые версии объектных файлов новыми — необходим для переупаковки библиотеки;
c — создать статическую библиотеку, если та еще не существует.

Проиндексируем функции внутри библиотеки для более быстрой линковки:

Итак, мы получили статическую библиотеку libMY_STATIC.a.

Теперь попытаемся использовать библиотеку в нашей программе:

Исходный текст программы (C):

Сохраните его в файле program1.c

Способы связывания библиотеки и программы:

— Скомпилируем и слинкуем (в том числе с нашей библиотекой) нашу программу:

gcc program1.c libMY_STATIC.a

(предполагается, что в качестве аргумента gcc будут переданы полные пути (!) к вашим библиотекам)

— Скомпилируйте с помощью команды:

gcc program1.c -L. -lMY_STATIC -o a1.out

— путь к каталогу, содержащему наши библиотек (используйте «-L

— название нашей библиотеки (это важно — название (!), а не имя файла — собственно, если библиотека имеет своим именем «libBLABLABLA.a», то ее названием будет «BLABLABLA» — т.е. имя без приставки «lib» и расширения «.a») (для нескольких библиотек используйте «-l -l . «)

Запустите файл a1.out на выполнение и удостовертесь, что результаты те же, что и в предыдущем пункте.

— Видоизменим предыдущий способ — уберем аргументы «-L»:

В начале проверим значение переменной LD_LIBRARY_PATH и содержимое файла /etc/ld.so.conf:

echo $LD_LIBRARY_PATH ; cat /etc/ld.so.conf

На экране появился некоторый список каталогов — это те каталоги, в которых система ищет библиотеки при их линковке с программой (еще к таким каталогам относятся:
/lib
/usr/lib
. Поместите libMY_STATIC.a в один из этих каталогов:

Читайте также:  What is linux file type

(Я, к примеру, засуну нашу библиотеку в каталог /usr/lib):

su -c ‘cp libMY_STATIC.a /usr/lib’
(в Ubuntu — sudo cp libMY_STATIC.a /usr/lib )
ldconfig
(ldconfig обновляет кеш данных о библиотеках линковщика)

Теперь скомпилируем и запустим нашу программу:

gcc program1.c -lMY_STATIC -o a2.out
./a2.out

Бинго! Кстати, таким вот способом вы можете подключать к своей программе любые статические библиотеки из приведенных выше каталогов.

* Бывает полезно определить все прототипы функций библиотеки в некотором заголовочном файле, который будет потом включаться в вашу программу. Это не обязательно, но удобно.

3) Статические библиотеки на языке Assembler.

Представьте, что вам необходимо оптимизировать выполнение некоторых действий в вашей программе. Разумеется, вы может применить ключевое слово asm (если пишите программу на C/C++), но лучшим решением будет создание оптимизированной вами библиотеки на языке Assembler и подключение ее к вашей программе. Давайте попробуем:

*Кстати, углубляться в процесс компиляции библиотеки и ее линковки с вашей программой я не буду (!). Этот процесс идентичен полностью (!) тому же процессу для библиотек, написанных на языке C.

Итак, имеем вот такую программу:

Сохраните ее в файле program2.c

Скомпилируйте ее и запустите:

Я привел этот пример, чтобы показать действительно возможность оптимизации программы с помощью библиотеки на Assembler’е. Вы можете заметить, что вызов printf в main() не оптимален, т.к. printf, по крайней мере, один раз использует цикл while для поиска вхождений конструкций «%. » в строку. Это не оптимально, т.к. очевидно, что таковых символов у нас нет. Оптимизируем нашу программу с помощью библиотеки на Assebmler’е:

my_printf:
movl $4,%eax
xorl %ebx,%ebx
incl %ebx
movl $hw,%ecx
movl $hw_e,%edx
int $0x80
xorl %eax,%eax
ret

Сохраните исходный код библиотеки в файле static2.s

Это AT&T наречие Assembler’а.

.globl my_printf — «my_printf» описывается как глобальная (видимая в других объектных файлах) последовательность
my_printf: — начало описание функции my_printf
movl $4,%eax — поместим 4 в eax (4 — номер системного вызова write)
xorl %ebx,%ebx и incl %ebx — поместим в ebx единицу — номер STDOUT
movl $message,%ecx — в ecx запишем адрес начала сообщения
movl $message_l,%edx — в edx поместим адрес конца сообщения
int $0x80 — произведем системный вызов write
xorl %eax,%eax — в eax — код возврата (0)
ret — вернемся в вызывающую процедуру
.data — секция данных (разумеется, мы могли бы передавать выводимую строку как параметр, но тогда вычисление ее конца потребовало бы от нас дополнительных усилий, что, согласитесь, лениво 🙂 )

Теперь получим библиотеку:

gcc -c static2.s -o static2.o
ar rc static2.a static2.o
ranlib static2.a

На выходе имеем статическую библиотеку static2.a

Теперь напишем программу, использующую эту статическую библиотеку (язык C):

Читайте также:  Выбираем графическую оболочку linux

Сохраните текст программы в файле program3.c

Заметьте, я добавил прототип библиотечной функции для удобства.

Скомпилируем и слинкуем программу с библиотекой, после чего запустим программу на выполнение:

gcc program3.c static2.a
./a.out

* Принцип линкования статических библиотек с программами на Assembler’е аналогичен принципу для программ на C. Просто, когда будете использовать статические библиотеки в Assembler’е, помните о соглашениях C по передаче аргументов в функцию и возвращению результата.

4) Статические библиотеки на языке C++.

Принцип создания аналогичен статическим библиотекам на C, но перед каждой экспортируемой функцией не забывайте добавлять:

(экспортировать как функцию на C — т.е. без расширения имен).

* Кстати, используйте g++ вместо gcc, если захотите протестировать приведенные выше примеры.

Подключение к вашей программе аналогично подключению к программе, написанной на C, за исключением необходимости явно добавлять к тексту программы прототипы импортируемых функций в следующем виде:

Где PROTOTYPE — прототип импортируемой функции.

* При подключении статических библиотек на C++ к программе на C сопряжено с некоторыми трудностями — т.к. при компиляции и линковки программы необходимо будет также вручную подключить системные библиотеки для реализации функционала, предоставляемого библиотекой Standart C++ сверх того, что предоставляет библиотека Standart C.

Динамические библиотеки (shared).

1) Динамическая библиотека — библиотека, подключаемая к программе в момент выполнения. Это означает, что при создании библиотеки производится не только ее компиляция, но и линковка с другими, нужными ей, библиотеками (!).

Динамические библиотеки полезны в случаях, если:
— Важно не перекомпилировать всю программу, а только перекомпилировать ту часть, которая реализует определенные функции — тогда эти функции выносятся в динамическую библиотеку;
— Важно использовать в программах на C библиотеки, подготовленные на C++ и при этом избежать лишних трудностей с линковкой программы;
— Кроме того, динамические библиотеки позволяют экономить место на жестком диске и в оперативной памяти, если одна и таже библиотека используется несколькими программами.

В Linux, обычно, динамические библиотеки имеют расширение «.so».

2) Подготовим исходный код динамической библиотеки (пример на C++).

Исходный код динамической библиотеки по принципам создания ничем (!) не отличается от исходного кода статических библиотек.

Здесь мы подготовим некоторый пример, который в дальнейшем будем использовать повсеместно во всей части 2.

Итак, исходный код библиотеки (C++):

Сохраните приведенный код в файле dynamic.cpp.

* Кстати, внутри динамической библиотеки вы можете описать следующие функции:
void _init() — будет вызвана при инициализации динамической библиотеки (загрузки ее в память);
void _fini() — будет вызвана при выгрузке из памяти динамической библиотеки.

3) Компиляция и линковка динамических библиотек.

Давайте получим динамическую библиотеку:

Получим файл с объектным кодом:

g++ -fPIC -c dynamic.cpp -o dynamic.o

(используйте gcc для программ на С и Assembler’е)

-fPIC — использовать относительную адресацию в переходах подпрограмм — во избежание конфликтов при динамическом связывании

Читайте также:  How to get path in linux

А теперь из объектного файла получим библиотеку:

g++ -shared -olibdynamic.so dynamic.o

(используйте gcc для программ на С и Assembler’е)

libdynamic.so — имя результирующей библиотеки;
-shared — предписывает создать динамическую (т.е. «разделяемую») библиотеку.

* Именуйте динамические библиотеки следующим способом:

Итак, на выходе мы имеем libdynamic.so — нашу динамическую библиотеку.

4) Использование динамической библиотеки в программе на C/C++.

— Связывание с библиотекой во время компиляции программы (C/C++):

—— Подготовим исходный код нашей программы:

Сохраните его в файле Dprogram1.c

Сохраните его в файле Dprogram1.cpp

(единственное отличие, как вы можете заметить, в ключевом слове extern — см. часть 1 пункт 4)

—— Теперь добьемся того, чтобы система смогла найти нашу библиотеку. Поместим libdynamic.so в один из каталогов:

cat /etc/ld.so.conf
и выполните потом » ldconfig «

—— И, наконец, скомпилируем программу и слинкуем ее с библиотекой:

gcc ИСХОДНИК -lИМЯ_БИБЛИОТЕКИ -o РЕЗУЛЬТИРУЮЩИЙ_БИНАРИК

В нашем случае: gcc Dprogram1.c -L/home/amv/c/libs/ -ldynamic

(используйте g++ для программы на C++)

Запустим на исполнение полученный файл:

— Связывание с библиотекой во время исполнения программы (C/C++):

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

int main()
void *handle = dlopen(«libdynamic.so»,RTLD_LAZY);
int(*fun)(void) = dlsym(handle,»hello»);
int x = (*fun)();
dlclose(handle);
printf(«Return code: %d\n»,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).

* Посмотрите на досуге вот этот перевод «man dlopen»: Привет, OpenNET

(используйте g++ для программы на C++)

Запустим на исполнение полученный файл:

* Важно! Нет необходимости помещать библиотеку в один из специальных каталогов, модифицировать переменные окружения и выполнять «ldconfig»

— Использование динамической библиотеки в программе на Python:

—— Поместим libdynamic.so в один из каталогов:

cat /etc/ld.so.conf
и выполните потом «ldconfig»

Исходный текст программы на python’е:

Модуль ctypes входит в стандартную поставку модулей python версии 2.5 и выше.

Фуф. Мы проделали довольно большую работу, но ведь это только верхушка айсберга.

P.S. Я намерено пропустил тему «Perl и динамические библиотеки» — сейчас мне просто лениво разбирать свои старые примеры. Могу только сказать, что за динамические библиотеки в Perl ведает модуль DynaLoader (и не только он), который является, по сути, оболочкой для dlfcn.h. Почитайте perldoc DynaLoader 😉

Источник

Оцените статью
Adblock
detector