Отправляет email-рассылки с помощью сервиса Sendsay

Программирование и др.

  Все выпуски  

Программирование в Linux с нуля - Выпуск 6


Информационный Канал Subscribe.Ru

Рассылка проекта Lindevel.Ru

Программирование в Linux с нуля. Выпуск 6.

1. Предисловие

Здравствуйте, уважаемые подписчики. Этот выпуск являет собой введение в библиотеки Linux.

2. Программа

2.1. Описание

Для изучения библиотек воспользуемся простой до безобразия программой, в которой выводится два сообщения, но особым образом. Чтобы не тянуть за собой лишний груз, не будем создавать в репозитории каких-либо каталогов. Нас сейчас интересуют библиотеки, а не способы организации исходных текстов программы.

2.2. Файлы

main.c
#include "hello1.h"
#include "hello2.h"

int main (void)
{
        hello1 ();
        hello2 ();

        return 0;
}


hello1.h
void hello1 (void);


hello2.h
void hello2 (void);


hello1.c
#include "hello1.h"
#include <stdio.h>

void hello1 (void)
{
        printf ("message #1\n");
}


hello2.c
#include "hello2.h"
#include <stdio.h>

void hello2 (void)
{
        printf ("message #2\n");
}


Makefile
main: main.o hello
        gcc -o main main.o -L. -lhello -Wl,-rpath .

main.o: main.c
        gcc -c main.c

hello1.o: hello1.c
        gcc -c -fPIC hello1.c -o hello1.o

hello2.o: hello2.c
        gcc -c -fPIC hello2.c -o hello2.o

hello: hello1.o hello2.o
        gcc -shared -o libhello.so hello1.o hello2.o

clean:
        rm -f *.o libhello.so main


2.3. Компиляция и запуск

Здесь все тривиально: make и ./main. Наблюдательные заметят, что в репозитории появился еще один странный файл libhello.so. Попробуйте запустить его. Ошибка?! Так и должно быть: просто теперь вы знаете, что подобные файлы не могут самостоятельно выполняться, хотя gcc и присваивает им права на выполнение.

3. Теория

3.1. Несколько слов о библиотеках

Библиотеки нужны для того, чтобы не изобретать велосипедов. Часто один и тот же набор функций можно использовать в разных программах. Повторная реализация схожих механизмов отнимает кучу времени и увеличивает размер исходных файлов. Даже при написании операционных систем используют библиотечную концепцию. Этой библиотекой всех библиотек является BIOS, в которой содержатся базовые функции ввода-вывода, используемые в различных программах. Однако не все так гладко. У библиотек есть и свои недостатки, о которых будет сказано позже.

3.2. Статические и динамические библиотеки

Вообще говоря, библиотека - это набор объектных файлов, объединенных в один модуль. Библиотека подключается к программе в процессе линковки. В таком случае говорят, что "программа собирается с такой-то библиотекой" или "такая-то библиотека включается в программу".

Библиотеки делятся на две группы: статические (объектные архивы) и динамические (совместно используемые). В процессе статической компоновки, все содержимое библиотеки помещается в исполняемый модуль. Такая программа как правило имеет большой размер и тяжело модернизируется, однако за счет непосредственного включения библиотечных механизмов в исполняемый код, является самодостаточной, т. е. мало зависимой от конфигурации системы. При динамической компоновке в исполняемый модуль внедряется лишь ссылка на библиотеку. Чтобы такая программа могла выполняться, необходимо, чтобы динамическая библиотека присутствовала в системе. Программы, построенные на динамических библиотеках, имеют маленький размер и легко модернизируются, но у таких программ могут возникнуть проблемы с запуском.

Статические библиотеки будут рассмотрены в следующем выпуске рассылки. Наша сегодняшнаяя программа использует концепцию динамической линковки.

Прежде, чем приступить к рассмотрению приведенного выше наитупейшего (простите меня за это!) примера, рассмотрим один важный момент, относящийся к библиотекам: если библиотека отсутствует в стандартных каталогах (/usr/lib, /lib и т. д.), то при компоновке необходимо явно указывать местоположение этой библиотеки, даже если она находится в текущем каталоге. Кроме того, в этом случае местоположение библиотеки следует указывать не только линковщику, но и самому исполняемому модулю.

3.3. Разбор полетов

Приведенная программа является типичным примером использования трех объектных модулей (клиент + два сервера). Два серверных модуля (hello1.o и hello2.o) мы объединяем в одну динамическую библиотеку. Теперь, при желании, этой библиотекой могут пользоваться разные программы (поэтому их и назвают совместно используемыми (shared)). Исходные файлы не содержат ничего нового, поэтому рассмотрим только Makefile.

При компиляции файлов hello1.c и hello2.c бросается в глаза опция -fPIC. Эта опция заставляет компилятор генерировать т. н. позиционно-независимый (Position Independent) код. Как уже говорилось в первых выпусках рассылки, объектный код отличается от исполняемого наличием символических имен вместо адресов. Указание опции -fPIC добавляет к объектному коду еще и т. н. плавающие позиции, благодаря которым объектные файлы могут пристыковываться к программе даже в процессе ее выполнения. Это называется динамической загрузкой библиотеки, которая будет рассмотрена в последующих выпусках рассылки. Итак, объектные модули, из которых строится библиотека должны содержать позиционно-независимый код.

Для объединения объектных файлов в динамическую библиотеку используется опция -shared. Как правило имена совместно используемых библиотек начинаются с префикса lib и заканчиваются расширением .so. Это стандарт и его нужно придерживаться.

При компоновке (линковке) программы с динамической библиотекой используют опцию -l, после которой указывают имя библиотеки без префикса lib и суффикса .so. Если, например, нужно подключить библиотеку libqt.so, то пришут так: -lqt.

Опция -L указывает, где находится библиотека во время линковки, а опция линковщика '-rpath' (опция '-Wl,' в gcc обозначает, что следующие за ней оции будут переданы линковщику) включает в исполняемый модуль информацию о том, где будет находиться библиотека во время запуска программы. В нашем случае библиотека находится в текущем каталоге и никуда оттуда не переезжает, поэтому мы смело указываем '-L . -Wl,-rpath .'.

Теперь запустим программу командой './main'. Если все сделано правильно, то программа выведет следующее:

-----------------------------------------------------------+
$ ./main                                                   |
message #1                                                 |
message #2                                                 |
$                                                          |
-----------------------------------------------------------+

Однако, если переименовать или удалить файл libhello.so, то программа откажется запускаться:
-----------------------------------------------------------+
$ mv libhello.so hello.n                                   |
$ ./main                                                   |
 ./main: error while loading shared libraries:              |
libhello.so: cannot open shared object file:               |
No such file or directory                                  |
$                                                          |
-----------------------------------------------------------+

В следующем выпуске мы продолжим изучать библиотеки, а сейчас настоятельно рекомендую попрактиковаться и даже поэкспериментировать с рассмотренным примером.


Всегда ваш, Николай.
mailto: nnivanov@mail.ru
Рассылки Subscribe.Ru
*nix project - новости из мира unix-систем! (ежедневная)

http://subscribe.ru/
http://subscribe.ru/feedback/
Подписан адрес:
Код этой рассылки: comp.soft.prog.linuxp
Отписаться

В избранное