Алексей Махоткин

домашняя страница

Libtool

Введение

В двух предыдущих статьях из цикла, посвященного GNU Autotools, мы обсуждали два “основных” пакета: Automake и Autoconf. В третьей, заключительной статье цикла, мы кратко обсудим оставшихся два пакета: Libtool и Shtool.

Libtool – разделяемые библиотеки

Необходимость появления пакета Libtool стала очевидной после того, как доказали свою жизнеспособность пакеты Autoconf и Automake. Разработчики проекта GNU постоянно вставали перед проблемой создания разделяемых библиотек (shared libraries) на различных платформах.

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

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

Предварительные комментарии

Для иллюстрации использования Libtool мы будем использовать первую версию нашей многострадальной программы Hello, world. Как вы помните, в первой статье мы заранее разбили эту программу на два файла, в одном из которых находится наша функция print_hello(). Нашей задачей будет превратить этот файл в полноценную разделяемую библиотеку libhello.

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

Вообще, Libtool создает так называемые Libtool-библиотеки – это целый набор файлов. Главный файл, содержащий описание библиотеки, имеет расширение .la. Объектные файлы, используемые при компиляции, а также результирующие статические и динамические библиотеки, помещаются в подкаталог .libs/. При установке Libtool автоматически обрабатывает эти файлы, помещая их в нужные каталоги.

Заметьте, что некоторые устаревшие операционные системы не поддерживают динамических библиотек — Libtool автоматически будет создавать при этом только статические библиотеки.

Простейшая Libtool-библиотека

Для того, чтобы добавить поддержку Libtool в вашем проекте, используется макрос AC_PROG_LIBTOOL в файле configure.in:

=== configure.in ===
AC_INIT([src/hello.c])
AM_INIT_AUTOMAKE([hello], [0.3])
AC_PROG_CC
AC_PROG_LIBTOOL

AM_CONFIG_HEADER(config.h)

AC_OUTPUT([Makefile src/Makefile])
=== configure.in ===

Этот макрос не входит в стандартную поставку Autoconf, поэтому его нужно добавить в пакет с помощью программы aclocal. Кроме того, для поддержки Libtool требуется еще несколько файлов, которые можно автоматически установить с помощью программы automake:

    $ aclocal
    $ autoconf
    $ automake -ac

В дистрибутив добавятся следующие файлы: config.guess, config.sub, ltmain.sh, ltconfig. В процессе работы скрипта configure будет создан файл libtool, который и будет обеспечивать всю поддержку сборки.

Для создания Libtool-библиотек используется основная переменная Automake _LTLIBRARIES. Для того, чтобы создать разделяемую библиотеку libhello, напишем в src/Makefile.am:

=== src/Makefile.am ===
lib_LTLIBRARIES = libhello.la

libhello_la_SOURCES = hello.c hello.h
=== src/Makefile.am ===

Эта запись означает, что будет создана Libtool-библиотека, которая называется libhello.la и компилируется из двух исходных файлов: hello.c и hello.h.

Выполним программы automake, autoconf, файлы шаблонов; затем выполним скрипт ./configure. Теперь попробуем собрать библиотеку (несколько строчек из выдачи программы make удалено для краткости):

    $ cd src/
    $ make libhello.la
        . . .
    gcc -DHAVE_CONFIG_H -I. -I. -I.. -g -O2 -c hello.c  -fPIC -DPIC -Wp,-MD,.deps/hello.TPlo -o .libs/hello.lo
        /bin/sh ../libtool --mode=link gcc  -g -O2   -o libhello.la -rpath /usr/local/lib  hello.lo
        gcc -shared  hello.lo  -lc  -Wl,-soname -Wl,libhello.so.0 -o .libs/libhello.so.0.0.0
        (cd .libs && rm -f libhello.so.0 && ln -s libhello.so.0.0.0 libhello.so.0)
        ar cru .libs/libhello.a  hello.o 
        ranlib .libs/libhello.a
        creating libhello.la

Заглянув в каталог .libs/, можно увидеть там как статическую библиотеку c расширением .a, так и динамические библиотеки с расширением .so, со всеми необходимыми символьными ссылками.

Сборка программ с Libtool-библиотеками

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

Давайте сделаем так, чтобы программа hello использовала разделяемую библиотеку libhello:

=== src/Makefile.am ===
bin_PROGRAMS=hello

hello_SOURCES=main.c

hello_LIBADD = $(top_builddir)/src/libhello.la
=== src/Makefile.am ===

Переменная $(top_builddir) содержит каталог сборки верхнего уровня. Есть еще похожая переменная $(top_srcdir), содержащая верхний уровень каталога с исходными текстами. Если вам нужно обратиться к собираемому объекту, используйте первую из них; в противном случае, чтобы обратиться к объекту, существующему в дистрибутиве (например, файлу данных или каталогу с заголовочными файлами), используйте вторую переменную.

Итак, мы опять обновляем файлы Makefile.in и Makefile, собираем библиотеку libhello.la, затем собираем программу hello (несколько строк удалено для краткости):

    $ cd src/
    $ make libhello.la
    $ make hello
    gcc -DHAVE_CONFIG_H -I. -I. -I..     -g -O2 -c `test -f main.c || echo './'`main.c
        /bin/sh ../libtool --mode=link gcc  -g -O2   -o hello  main.o ../src/libhello.la 
        gcc -g -O2 -o .libs/hello main.o ../src/.libs/libhello.so -Wl,--rpath -Wl,/usr/local/lib
        creating hello

Если мы посмотрим на файл hello, то увидим, что он на самом деле представляет собой shell-скрипт. Настоящий исполняемый файл находится в подкаталоге .libs/. Он будет установлен как следует при выполнении make install.

Впрочем, этот скрипт можно запустить прямо из каталога сборки, как если бы это была обычная программа: $ ./hello Hello, world!

Дополнительные возможности

Если вы хотите отладить вашу программу, то не сможете сделать это простым наивным методом:
    $ gdb hello
    "/home/alexm/autotools-ru/hello/src/hello": not in executable format: File format not recognized
Libtool обеспечивает специальный режим для отладки:
    $ libtool gdb hello
    This GDB was configured as "i686-pc-linux-gnu"...
    (gdb) run 
    Starting program: /home/alexm/autotools-ru/hello/src/.libs/lt-hello 
    Hello, world!

    Program exited normally.

Shtool

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

Shtool является одним большим shell-скриптом, который умеет выполнять полтора десятка подкоманд разного назначения. Основная причина использования этого скрипта – невероятная переносимость. Shell-код, который используется внутри этих скриптов, работает на огромном количестве командных интерпретаторов различных операционных систем, каждая из которых, как всегда, имеет свои, скажем так, особенности.

Вообще, в системах сборки пакетов, использующих Automake и Autoconf, почти нет места, где можно было бы использовать Shtool: разве что можно использовать подкоманды mkdir и install. Зачем бы это было нужно? – спросите вы, ведь команды mkdir и install есть на всякой системе? Нет. Например, команда mkdir имеет флаг -p только в GNU-версии и еще в некоторых. Ощутимое количество коммерческих операционных систем не умеют создавать каталоги, только если все его родительские каталоги уже существуют. Некоторые программы install также не поддерживают ряда полезных ключей.

Скрипты shtool проявляют себя в полной мере, когда их используют для различных дополнительных, нестандартных целей. В этой статье мы лишь кратко опишем подкоманды, которые обеспечивает Shtool, чтобы вы представляли себе, что можно не реализовывать снова и снова, а взять уже готовое. Подробности, как обычно, можно найти на великолепной странице руководства к Shtool.

Вывод на экран:

- echo: выдает на экран строку, в которой можно использовать служебные конструкции; поддерживает ключ -n, который умеет не всякая программа echo;

- mdate: печатает в указанном формате время последней модификации файла или каталога;

- table: печатает список значений в виде таблицы;

- prop: рисует красивый “пропеллер” во время выполнения длинной операции;

Работа с файлами:

- move: позволяет переименовывать файлы с поддержкой маски: например, shtool move -e %.txt %.asc переименует все файлы с расширением .txt в .asc; такой возможности обычно не хватает многим, привыкшим к досовской команде rename;

- install: устанавливает программу, скрипт или обычный файл; обеспечивает все флаги BSD-версии программы install, даже если системная программа install их не поддерживает или вообще не существует;

- mkdir: создает каталог; позволяет также создать все необходимые родительские каталоги – эта возможность часто отсутствует в системных программах mkdir;

- mkln: создает ссылку (жесткую или символьную) на файл; при создании символьной ссылки старается, чтобы ссылка была относительной;

- mkshadow: создает копию дерева исходных текстов с помощью символьных ссылок; полезно, если хочется внести несколько исправлений в существующее дерево, чтобы потом создать diff-файл;

- fixperm: “исправляет” права доступа к файлам перед созданием дистрибутива; обычно при этом устанавливаются недостающие права доступа и выполнения для “группы” и для “всех остальных”;

- tarball: создает правильный tar-файл с дистрибутивом. Этот tar-файл будет распаковываться в отдельный подкаталог; список файлов в этом tar-файле будет отсортирован, чтобы можно было пользоваться командой tar tvf;

Системные возможности:

- guessos: определяет операционную систему и архитектуру; обычно лучше использовать стандартный GNU-скрипт config.guess;

- arx: расширенный вариант команды ar;

- slo: специальная обертка к системному компоновщику, позволяющая удобно работать со специальными динамическими библиотеками;

- scpp: специальная обертка к препроцессору языка C, облегчающая написание библиотек на ANSI C;

- version: обеспечивает создание файлов описания версии пакета для нескольких различных языков программирования;

- path: утилита для работы с переменной окружения $PATH.

С помощью программы shtoolize можно создать скрипт shtool, содержащий необходимое подмножество подкоманд.

Дополнительные вопросы

Сборка вне дерева исходников

Autoconf и Automake обеспечивают чрезвычайно полезную возможность: сборка вне дерева исходников. Предположим, что исходники пакета hello распакованы в каталоге /usr/local/src, а вы хотите собрать пакет в каталоге /var/tmp/hello-build. Вот последовательность шагов:

    $ mkdir /var/tmp/hello-build
    $ cd /var/tmp/hello-build
    $ /usr/local/src/hello-1.3/configure
    $ make

Этот способ сборки особенно полезен, когда вашему пользователю нужно собирать пакет одновременно для множества различных архитектур: тогда он может иметь каталоги hello-build-linux, hello-build-solaris, hello-build-hpux. Если размер дерева исходников довольно велик, то экономия налицо.

Обязательно перед выпуском новой версии проверяйте, что пакет собирается вне дерева исходников.

Заключение

Итак, мы закончили краткий обзор пакетов из серии GNU Autotools. Надеемся, что мы помогли сориентироваться в обсуждаемой области, и вы станете использовать Autoconf, Automake и Libtool в своих программах, сэкономив время, и предоставив пользователю удобную и привычную поддержку сборки. Учтите, лицензия на все эти пакеты _позволяет_ использовать их даже в коммерческих программных продуктах.

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

Ссылки

Основная страница проекта Libtool: http://www.gnu.org/software/libtool/libtool.html

Основная страница проекта Shtool: http://www.gnu.org/software/shtool/shtool.html

Русская страница по Autotools: http://squadette.ru/autotools-ru/

Книга “GNU Autoconf, Automake, and Libtool”: http://sourceware.org/autobook/

Comments