Пример статической библиотеки
Теперь давайте создадим свою собственную библиотеку, располагающую двумя функциями:
h _ world () и g _ world (), которые выводят на экран "Hello World" и "Goodbye World" соответственно. Начнем со статической библиотеки.
Начнем с интерфейса. Создадим файл world . h:
/* world.h */
void h_world (void);
void g _ world ( void );
Здесь просто объявлены функции, которые будут использоваться.
Теперь надо реализовать серверы. Создадим файл h _ world . c:
/* h world. с */
#include <stdio.h>
#include "world.h"
void h_world (void)
{
printf ("Hello World\n");
}
Теперь создадим файл g_world.c, содержащий реализацию функции g_world():
/* g_world.c */
#include <stdio.h>
#include "world.h"
void g_world (void)
{
printf (" Goodbye World \ n ");
}
Можно было бы с таким же успехом уместить обе функции в одном файле (hello . c например), однако для наглядности мы разнесли код на два файла.
Теперь создадим файл main . c. Это клиент, который будет пользоваться услугами сервера:
/* main.c */
#include "world.h"
int main (void)
{
h_world ();
g _ world ();
}
Теперь напишем сценарий для make. Для этого создаем Makefile:
# Makefile for World project
binary: main.o libworld.a
gcc -o binary main.o -L. –I world
main.o: main.c
gcc -c main.c
libworld.a: h_world.o g_world.o
ar cr libworld.a h_world.o g_world.o
h_world.o: h_world.c
gcc -c h_world.c
g_world.o: g_world.c
gcc -c g_world.c
clean:
rm – f *. o *. a binary
He забывайте ставить табуляции перед каждым правилом в целевых связках.
Собираем программу:
$ make
gcc -с main . c
gcc - с h_world.c
gcc - с g_world.c
ar cr libworld.a h_world.o g_world.o
gcc - о binary main.o -L. –I world
Осталось только проверить, работает ли программа и разобраться, что же мы такое сделали:
|
|
$ ./binary Hello World
Goodbye World
$
Итак, в приведенном примере появились три новые вещи: опции - I и - L компилятора, а также команда а r. Начнем с последней. Как вы уже догадались, команда а r создает статическую библиотеку (архив). В нашем случае два объектных файла объединяются в один файл libworld . a. В Linux практически все библиотеки имеют префикс lib.
Как уже говорилось, компилятор gcc сам вызывает линковщик, когда это нужно. Опция - I, переданная компилятору, обрабатывается и посылается линковщику для того, чтобы тот подключил к бинарнику библиотеку. Как вы уже заметили, у имени библиотеки "обрублены" префикс и суффикс. Это делается для того, чтобы создать "видимое безразличие" между статическими и динамическими библиотеками. Но об этом речь пойдет в других главах книги. Сейчас важно знать лишь то, что и библиотека libfoo . so и библиотека libfoo . a подключаются к проекту опцией - lfoo. В нашем случае libworld . a "урезалось" до - world.
Опция -L указывает линковщику, где ему искать библиотеку. В случае, если библиотекa располагается в каталоге /lib или / usr / lib, то вопрос отпадает сам собой и опция -L не требуется. В нашем случае библиотека находится в репозитории (в текущем каталоге). По умолчанию линковщик не просматривает текущий каталог в поиске библиотеки, поэтому опция -L. (точка означает текущий каталог) необходима.
|
|
Пример совместно используемой библиотеки
Для того, чтобы создать и использовать динамическую (совместно используемую) библиотеку, достаточно переделать в нашем проекте Makefile.
# Makefile for World project
binary: main.o libworld.so
gcc -o binary main.o -L. –I world –Wl, -rpath,.
main.o: main.c
gcc -c main.c
libworld.so: h_world.o g_world.o
gcc -shared -o libworld.so h_world.o g_world.o
h_world.o: h_world.c
gcc -c -fPIC h_world.c
g_world.o: g_world.c
gcc -c -fPIC g_world.c
clean:
rm –f *.o *.so binary
Внешне ничего не изменилось: программа компилируется, запускается и выполняет те же самые действия, что и в предыдущем случае. Изменилась внутренняя суть, которая играет для программиста первоочередную роль. Рассмотрим все по порядку.
Правило для сборки binary теперь содержит пугающую опцию - Wl, - rpath. Ничего страшного тут нет. Как уже неоднократно говорилось, компилятор gcc сам вызывает линковщик ld, когда это надо и передает ему нужные параметры сборки, избавляя нас от ненужной платформенно-зависимой волокиты. Но иногда мы все-таки должны вмешаться в этот процесс и передать линковщику "свою" опцию. Для этого используется опция компилятора - Wl , option , optargs ,...
|
|
Расшифровываю: передать линковщику (- Wl) опцию option с аргументами optargs. В нашем случае мы передаем линковщику опцию -rpath с аргументом . (точка, текущий-каталог). Возникает вопрос: что означает опция -rpath? Как уже говорилось, линковщик ищет библиотеки в определенных местах; обычно это каталоги /lib и /usr/lib, иногда / usr / local / lib. Опция -rpath просто добавляет к этому списку еще один каталог. В нашем случае это текущий каталог. Без указания опции -rpath, линковщик "молча" соберет программу, но при запуске нас будет ждать сюрприз: программа не запустится из-за отсутствия библиотеки. Попробуйте убрать опцию - Wl , - rpath. из Makefile и пересоберите проект. При попытке запуска программа binary завершится с кодом возврата 127. То же самое произойдет, если вызвать программу из другого каталога. Верните обратно -Wl , - rpath ,., пересоберите проект, поднимитесь на уровень выше командой cd .. и попробуйте запустить бинарник командой world / binary. Ничего не получится, поскольку в новом текущем каталоге библиотеки нет.
Есть один способ не передавать линковщику дополнительных опций при помощи - Wl - это использование переменной окружения LD _ LIBRARY _ PATH.. Сейчас лишь скажу, что у каждого пользователя есть так называемое окружение (environment) представляющее собой набор пар ПЕРЕМЕННАЯ=ЗНАЧЕНИЕ, используемых программами. Чтобы посмотреть окружение, достаточно набрать команду env. Чтобы добавить в окружение переменную, достаточно набрать export ПЕРЕМЕННАЯ=ЗНАЧЕНИЕ, а чтобы удалить переменную из окружения, надо набрать export - n ПЕРЕМЕННАЯ. Будьте внимательны: export - это внутреннаяя команда оболочки BASH; в других оболочках (csh, ksh, ...) используются другие команды для работы с окружением. Переменная окружения LD _ LIBRARY _ PATH содержит список дополнительных "мест", разделенных двоеточиеями, где линковщих должен искать библиотеку.
|
|
Не смотря на наличие двух механизмов передачи информации о нестандартном расположении библиотек, лучше помещать библиотеки в конечных проектах в / lib и в / usr / lib. Допускается расположение библиотек в подкаталоги / usr / lib и в / usr / local / lib (с указанем - Wl, - rpath). Но заставлять конечного пользователя устанавливать LD _ LIBRARY _ PATH почти всегда является плохим стилем программирования.
Следующая немаловажная деталь - это процесс создания самой библиотеки. Статические библиотеки создаются при помощи архиватора а r, а совместно используемые - при помощи gcc с опцией - shared. В данном случае gcc опять же вызывает линковщик, но не для сборки бинарника, а для создания динамической библиотеки.
Последнее отличие - опции - fPIC (- fpic ) при компиляции h _ world . c и g _ world . c. Эта опция сообщает компилятору, что объектные файлы, полученные в результате компиляции должны содержать позиционно-независимый код (PIC - Position Independent Code), который используется в динамических библиотеках. В таком коде используются не фиксированные позиции (адреса), а плавающие, благодаря чему код из библиотеки имеет возможность подключаться к программе в момент запуска.
Дата добавления: 2019-03-09; просмотров: 384; Мы поможем в написании вашей работы! |
Мы поможем в написании ваших работ!