Лекция: Пример статической библиотеки
Теперь давайте создадим свою собственную библиотеку, располагающую двумя функциями: h_world() и g_world(), которые выводят на экран «HelloWorld» и «GoodbyeWorld» соответственно. Начнем со статической библиотеки.
Начнем с интерфейса. Создадим файл world.h:
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/* world.h */
void h_world (void);
void g_world (void);
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Здесь просто объявлены функции, которые будут использоваться. Теперь надо реализовать серверы. Создадим файл h_world.c:
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
/* h_world.c */
#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. -lworld
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
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Не забывайте ставить табуляции перед каждым правилом в целевых связках. Собираем программу:
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
$ make
gcc -c main.c
gcc -c h_world.c
gcc -c g_world.c
ar cr libworld.a h_world.o g_world.o
gcc -o binary main.o -L. -lworld
$
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Осталось только проверить, работает ли программа и разобраться, что же мы такое сделали:
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
$ ./binary
HelloWorld
GoodbyeWorld
$
−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−
Итак, в приведенном примере появились три новые вещи: опции -l и -L компилятора, а также команда ar. Начнем с последней. Как вы уже догадались, команда ar создает статическую библиотеку (архив). В нашем случае два объектных файла объединяются в один файл libworld.a. В Linux практически все библиотеки имеют префикс lib.
Как уже говорилось, компилятор gcc сам вызывает линковщик, когда это нужно. Опция -l, переданная компилятору, обрабатывается и посылается линковщику для того, чтобы тот подключил к бинарнику библиотеку. Как вы уже заметили, у имени библиотеки «обрублены» префикс и суффикс. Это делается для того, чтобы создать «видимое безразличие» между статическими и динамическими библиотеками. Но об этом речь пойдет в других главах книги. Сейчас важно знать лишь то, что и библиотека libfoo.so и библиотека libfoo.a подключаются к проекту опцией -lfoo. В нашем случае libworld.a «урезалось» до -lworld.
Опция -L указывает линковщику, где ему искать библиотеку. В случае, если библиотека располагается в каталоге /lib или /usr/lib, то вопрос отпадает сам собой и опция -L не требуется. В нашем случае библиотека находится в репозитории (в текущем каталоге). По умолчанию линковщик не просматривает текущий каталог в поиске библиотеки, поэтому опция -L. (точка означает текущий каталог) необходима.