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

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

Automake

Copyright (c) Алексей Махоткин 2001
Впервые эта статья была напечатана в журнале "Программист", N09, 2001 год

Запрещается перепечатка без письменного разрешения автора.

GNU Autotools – инфраструктура для сборки программ: Automake

  From: Mark Mitchell <mark@codesourcery.com>
  Date: Fri, 11 May 2001 18:18:09 -0700

I used to think that automake wasn't flexible enough.  Now I think
that if you can't express your build system cleanly with automake,
your build system is too complex, and you need to think harder.

Обзор

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

Примерно десять лет назад Дэвид МакКензи начал работу над системой поддержки переносимости программ, над которыми работал в рамках проекта GNU. Со временем скрипты, которые он написал для этого, превратились в отдельный пакет Autoconf, которым пользуется практически каждая программа, написанная в рамках проекта GNU, и подавляющее большинство программ, написанных по технологии Open Source.

Autoconf позволяет относительно легко адаптировать программы для переноса на огромное количество почти всех известных вариантов системы UNIX, а также несколько систем, которые сложно назвать Unix’ом, включая и Win32 (имеется в виду система Cygwin).

Успех проекта Autoconf подвиг также на написание Automake – системы автоматического создания Makefile’ов для крупных проектов. Automake очень тесно работает совместно с Autoconf, позволяя с помощью буквально двух десятков строк создавать огромные Makefile’ы, которые обрабатывают огромное количество возможностей, по сборке и установке пакета, к которым привыкли все пользователи современных программ с открытыми исходниками.

Через какое-то время стало ясно, что проблема сборки разделяемых библиотек (а это действительно проблема – каждый вариант UNIX делает это немного по-своему) является идеальной задачей для еще одного пакета, и этот пакет называется Libtool. Libtool очень тесно работает совместно с Automake, и для включения сборки разделяемых библиотек достаточно лишь внести небольшие изменения в шаблон Makefile’а – огромную работу по выяснению всех деталей и тонкостей Libtool проделывает абсолютно прозрачно для разработчика.

Наконец, Ральф Энгельшал заметил, что почти все проекты, над которыми он работает, да и вообще практически все проекты, требуют одних и тех же вспомогательных скриптов (например, для создания каталога со всеми его родительскими каталогами, если они еще не существуют). Через небольшое время все эти разрозненные скрипты были объединены в пакет Shtool, который и замыкает цепочку продуктов Autotools.

Взаимодействие компонентов

Мы будем рассматривать ваш продукт с двух сторон: с вашей стороны – стороны разработчика, и со стороны пользователя. Заметьте, что “пользователь” в данном случае – это человек, который собирает и устанавливает программу на своей машине, чтобы его конечные пользователи могли использовать ее, не задумываясь о том, как именно она была установлена. Довольно часто в процессе разработки вы будете также еще и пользователем, неоднократно пересобирая ваш пакет и переустанавливая его в целях тестирования. Точка зрения конечного пользователя здесь не рассматривается.

Обратите внимание, кстати, что пользователю не требуется устанавливать у себя ни Autoconf, ни Automake, ни Libtool, ни Shtool. Все необходимые скрипты самодостаточны и поставляются в дистрибутиве.

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

    $ ./configure [флаги]

В качестве прототипов при этом используются файлы Makefile.in, которые по большей части похожи на файлы Makefile, но только в них встречаются различные переменные (типа путей инсталляции или флагов компиляции), значения которых подставляются в момент запуска configure.

Сам скрипт configure тоже генерируется из своего шаблона, который называется configure.in. Внутри configure.in находятся макросы, которые изучают систему, на которой происходит сборка пакета, а также выясняют, в какой именно конфигурации пользователь хочет собрать пакет (дополнительные библиотеки, флаги компиляции и т. п.)

Раньше, когда программа Automake еще не была написана, файлы Makefile.in писались вручную. Это довольно утомительно, и сейчас вместо них все чаще используются шаблоны, которые называются Makefile.am. Шаблоны превращаются в Makefile.in с помощью Automake. Шаблоны примерно на порядок меньше по размеру, чем результирующие файлы Makefile.in (обычно пара десятков строк шаблона разворачиваются в 700-800 строк). Внутри получившегося Makefile.in находится множество стандартных “целей”, обрабатывающих различные аспекты процедуры сборки и инсталляции пакета.

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

Используемые версии

Рекомендуется поставить самые свежие версии пакетов, которые только можно. Это значит, что Autoconf имеет номер версии 2.50 (в нем огромное количество изменений по отношению к предыдущей версии, 2.13. Для новых пакетов лучше начинать сразу с этой версии). Automake должен быть версии не ниже свежевыпущенной 1.4h (которая берется по ссылке непосредственно с основной страницы пакета). Libtool следует взять свежайший, потому что в основном изменения в нем сводятся к бесконечному добавлению поддержки все новых и новых вариантов Unix. Shtool – самый некритичный к версии пакет, к тому же он уже стабилизировался и новых версий не выходило довольно давно.

Automake

Automake очень тесно работает совместно с Autoconf. Так как Autoconf является темой второй статьи, то на первых порах нам придется использовать минимальный configure.in, ограничившись минимальным объяснением его содержимого. На текущий момент вы можете консультироваться с документацией на Autoconf, если потребуется дополнять и исправлять configure.in.

Такая последовательность обсуждения вызвана тем, что если начать с Autoconf, то придется вручную писать очень скучные и длинные файлы Makefile.in, которые все равно придется выбросить сразу после того, как будет написан первый Makefile.am.

Исходные тексты программы

Итак, предположим, мы хотим написать обычную программу “Hello, world!”. Для увеличения сложности искусственно разделим её на два файла (один из которых позже будет оформлен в виде разделяемой библиотеки).

Все исходные тексты, использующиеся в этой статье, помещены на домашней странице автора, по адресу http://alexm.here.ru/autotools-ru/

Создадим основной каталог проекта, а в нем подкаталог src/. Создадим src/hello.c, содержащий коротенькую функцию print_hello():

=== src/hello.c ===
#include <stdio.h>

#include "hello.h"

void
print_hello(void) {
    printf("Hello, world!\n");
}
=== src/hello.c ===

Еще создадим файл src/main.c с функцией main(), которая использует функцию print_hello():

=== src/main.c ===
#include "hello.h"

int main(void) {
    print_hello();
    exit(0);
}
=== src/main.c ===

Еще создадим заголовочный файл src/hello.h, содержащий объявление функции print_hello():

=== src/hello.h ===
#ifndef HELLO_H
#define HELLO_H

void print_hello(void);

#endif
=== src/hello.h ===

Два файла hello.c и main.c будут компилироваться в объектные файлы hello.o и main.o, соответственно, которые будут слинкованы в исполняемый файл, который называется просто hello.

Файлы верхнего уровня

В корневом каталоге проекта мы создадим два файла: configure.in

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

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

а также коротенький, из одной строчки Makefile.am:

=== Makefile.am ===
SUBDIRS = src
=== Makefile.am

Содержимое Makefile.am означает, что вся реальная работа по сборке происходит в подкаталогах. Пока используется только один каталог, src/.

Automake при обработке своих шаблонов просматривает также файл configure.in. Первая строчка этого файла, AC_INIT, обязательна для всех файлов configure.in. В качестве параметра этого макроса задается имя какого-нибудь основного исходника пакета. Это имя используется, чтобы предотвратить нечаянный запуск скрипта configure из неправильного каталога.

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

Третья строчка, AC_PROG_CC, позволяет перед сборкой проверить, есть ли вообще в системе компилятор C, и работает ли он.

Наконец, в четвертой строчке, AC_OUTPUT, перечисляются названия файлов Makefile, которые будут созданы после выполнения пользователем скрипта configure.

Makefile.am в подкаталогах

Наконец, нужно еще создать небольшой файл Makefile.am, в подкаталоге src/. В этом файле описаны программы и библиотеки, которые будут собираться в текущем каталоге, а также исходники, которые будут использоваться при сборке:

=== src/Makefile.am ===
bin_PROGRAMS=hello
hello_SOURCES=main.c hello.c hello.h
=== src/Makefile.am ===

В этом файле описан (с помощью “базовой переменной” bin_PROGRAMS) один исполняемый файл, hello. Этот файл создается из исходников, перечисленных в базовой переменной hello_SOURCES.

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

Обработка

Теперь можно попробовать обработать файлы, которые мы только что создали, и получить в результате готовый продукт с кучей возможностей в плане сборочной инфраструктуры.

Для создания скрипта configure из configure.in выполните две команды (более полное их описание будет во второй статье. Если нужно, обратитесь к документации).

    $ aclocal
    $ autoconf

В корневом каталоге проекта появились два новых файла: aclocal.m4 и configure.

Запустим Automake:

    $ automake
    automake: configure.in: required file `./install-sh' not found
    automake: configure.in: required file `./mkinstalldirs' not found
    automake: Makefile.am: required file `./NEWS' not found
    automake: Makefile.am: required file `./README' not found

(несколько строчек было удалено). Часть упомянутых в этом списке файлов Automake может добавить, скопировав их из своей инсталлированной копии. Не пугайтесь, что в вашем проекте со временем окажутся слегка устаревшие версии вспомогательных скриптов: пользователь ничего не заметит, потому что главное в данном случае – что все эти скрипты, сгенерированные и скопированные, совместимы друг с другом. При желании можно будет перегенерировать их или скопировать заново при выходе новых версий пакетов из серии Autotools.

Попросим Automake добавить все скрипты, которые ему требуются:

    $ automake -a -c
    automake: configure.in: installing `./install-sh'
    automake: configure.in: installing `./mkinstalldirs'
    automake: Makefile.am: installing `./COPYING'
    automake: Makefile.am: required file `./NEWS' not found
    automake: Makefile.am: required file `./README' not found
    automake: Makefile.am: required file `./AUTHORS' not found
    automake: Makefile.am: required file `./ChangeLog' not found

(несколько строчек было удалено). Как видите, часть отсутствующих скриптов Automake сам создать не может. Действительно, откуда ему знать, что должно быть написано в README, файле описания пакета? По стандарту (GNU Coding Standards) в файле NEWS должны быть кратко описаны изменения от версии к версии. Файл ChangeLog, обычно генерируется автоматически, например, скриптом cvs2cl, (см. список ссылок). В файле AUTHORS должны быть перечислены лица, участвовавшие в написании проекта.

Automake удовлетворится, если вы создадите хотя бы пустые файлы с такими именами (но обязательно обновляйте их от версии к версии!)

Заметьте, что Automake без предупреждения создает файл COPYING, в котором приведен текст Универсальной Общественной Лицензии GNU (GPL). Если ваш пакет распространяется под какой-либо другой лицензией, не забудьте заменить содержимое этого файла во избежание недоразумений!

Вот, в корневом каталоге вашего проекта появился целый ряд новых файлов. В каталоге src/ должен был появиться файл Makefile.in.

Если вы пользуетесь системой контроля версий, например, CVS, то нужно зарегистрировать там все эти файлы, включая автосгенерированные. Ни в коем случае не помещайте под контроль версий готовые файлы Makefile, и другие файлы, возникшие в результате работы скрипта configure.

Сборка программы

Теперь можно попробовать собрать нашу программу. Это делается совершенно обычным, привычным образом:

    $ ./configure
    creating cache ./config.cache
    [ . . . ]
    creating ./config.status
    creating Makefile
    creating src/Makefile
    $ make
    Making all in src
    make[1]: Entering directory `/home/alexm/autotools-ru/hello/src'
    [ . . . ]

    gcc  -g -O2   -o hello  main.o hello.o  
    make[1]: Leaving directory `/home/alexm/autotools-ru/hello/src'
    make[1]: Entering directory `/home/alexm/autotools-ru/hello'
    make[1]: Nothing to be done for `all-am'.
    make[1]: Leaving directory `/home/alexm/autotools-ru/hello'

Точно так же сработает и make install, установив вашу программу hello в место, указанное пользователем с помощью ключа --prefix программы configure (по умолчанию – /usr/local).

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

Работа Automake с библиотеками будет описана в третьей статье серии.

Если в вашем пакете есть программы, написанные на скриптовых языках (то есть, они не требуют компиляции), то их можно указать так:

    bin_SCRIPTS = foo.sh

Документация

Automake обрабатывает документацию в формате Texinfo и в стандартном для UNIX формате страниц руководства. Создайте для документации отдельный каталог, например, doc/. Поместите туда небольшой Makefile.am, в котором перечислите:

=== doc/Makefile.am ===
info_TEXINFOS = hello.texi
man1_MANS = hello.1
=== doc/Makefile.am ===

Не забудьте поправить configure.in и Makefile.am верхнего уровня проекта, добавив в них упоминания о каталогах с документацией. Перегенерите все файлы с помощью команд autoconf и automake.

Цели в файлах Makefile

Automake автоматически предоставляет множество различных служебных целей. Например, make install установит все программы, библиотеки, файлы данных и документацию, которые описаны в файлах Makefile.am.

Для того, чтобы после инсталляции очистить каталог с исходными текстами от объектных файлов, скомпилированных программ, и т. п., можно использовать цели make clean и make distclean (и еще несколько, см. документацию). Первая цель предназначена для пользователя. Вторая цель удаляет абсолютно все файлы, созданные после распаковки архива с исходниками, даже файлы Makefile (чтобы пересоздать их, запустите скрипт configure еще раз).

Разработчику будет полезна стандартная цель make dist, которая создает дистрибутивный файл со всеми необходимыми исходными текстами пакета. Заметьте, что в архив попадут только те файлы, которые явно так или иначе упомянуты в одном из файлов Makefile.am, а также стандартные файлы, про которые Automake знает и сам (их список выдается в краткой справке, которую можно получить с помощью automake --help). Для того, чтобы добавить в архив любой файл (например, вспомогательный текстовый документ, создайте в Makefile.am строчку

    EXTRA_DIST = foo.txt

Вообще, файл Makefile.am, помимо базовых переменных, может содержать обычные make-правила, которые будут без изменений помещены в Makefile.in.

Заключение

Практика показывает, что уже минимальное применение Automake позволяет безболезненно и эффективно преобразовать старую систему сборки проекта “вручную” (с трудоемким прописыванием каждой зависимости), в автоматическую систему, имеющую больше возможностей и более легкую для изменения.

В комплекте программы Automake есть великолепная исчерпывающая документация, которая полностью покрывает все вопросы, не затронутые в этой короткой статье. Эта документация (а также документация на Autoconf) была переведена на русский язык Алексом Оттом, и свободно доступна в Интернете по адресу http://alexm.here.ru/autotools-ru/

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

Ссылки

Comments