Пример статической библиотеки



 

Теперь давайте создадим свою собственную библиотеку, располагающую двумя функциями:

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; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!