20 авг. 2008 г.

Создаём пакет для Ubuntu. Часть 5a. Пример из helloworld.

Как вы, возможно, видели, некоторых каталогов, описанных в предыдущем разделе у вас в Ubuntu не существует. Это связано с тем, что структура файловой системы различается от дистрибутива к дистрибутиву, сохраняя, конечно, определённую концепцию описанную в Filesystem Hierarchy Standard.

На сайте FTP консорциума GNU лежит программа Hello world основное назначение её в том, чтобы просто посмотреть продукт полностью удовлетворяющий GNU стандарту. Но мы его попробуем использовать для того, чтобы просто узнать значения некоторых переменных.

Скачайте и распакуйте эту программу куда-нибудь в /tmp. Для того, чтобы нам не жалко было её стереть. Зайдите туда из-под консоли и выполните команду:

$ ./configure
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
...
configure: creating ./config.status
config.status: creating Makefile -- вот это нам понадобится
...

Eсли у вас возникнет ошибка, что не возможно создать "executable file", поставьте из репозитария пакет build-essential.

Итак, вы возможно обратили внимание на то, что вместо отсутствующего Makefile скрипт configure создал нам новый. Если вы его просмотрите то увидите следующее (нам отсюда нужна только верхняя часть:

$ cat Makefile
... (тут лежат комментарии)
SHELL = /bin/bash

srcdir = .
top_srcdir = .

prefix = /usr/local
exec_prefix = ${prefix}
... (а здесь остальной автоматически сгенерированный код)

Как вы видите префикс равен 'prefix = /usr/local'. В документе Filesystem Hierarchy Standard об этом сказано, что (4.8.2.1): "Иерархия /usr/local используется системным администратором при локальной установки программного обеспечения. Она не должна перезаписываться при обновлении системного программного обеспечения. Она может быть использована для программ и данных, которые совместно используются среди групп хостов, но которые не найдены в /usr. Локально установленное ПО должно быть помещено, предпочтительнее, в /usr/local, чем в /usr, если конечно оно не было установлено для замены или обновления ПО в /usr."

Так как я на своей памяти не встречал пакеты, которые записывались бы в /usr/local (тем более мы с вами будем делать наш собственный пакет, который в дальнейшем будет обновляться). Для этого выполним конфигурационный скрипт следующим образом, и просмотрим наш Makefile:

$ ./configure --prefix=/usr
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
...
$ cat Makefile
... (тут лежат комментарии)
SHELL = /bin/bash

srcdir = .
top_srcdir = .

prefix = /usr
exec_prefix = ${prefix}

bindir = ${exec_prefix}/bin
sbindir = ${exec_prefix}/sbin
libexecdir = ${exec_prefix}/libexec
datadir = ${prefix}/share
sysconfdir = ${prefix}/etc
sharedstatedir = ${prefix}/com
localstatedir = ${prefix}/var
libdir = ${exec_prefix}/lib
infodir = ${prefix}/info
mandir = ${prefix}/man
includedir = ${prefix}/include
oldincludedir = /usr/include
pkgdatadir = $(datadir)/hello
pkglibdir = $(libdir)/hello
pkgincludedir = $(includedir)/hello
top_builddir = .
... (а здесь остальной автоматически сгенерированный код)

Теперь уже всё можно свести в таблицу, чтобы было проще воспринять:


ПеременнаяПутьОписание
srcdir.Исходные коды
top_srcdir.Родительский каталог с исходными кодами (во вложенных директориях его значение равно '..'
prefix/usrКаталог, содержащий данные, совместно используемые несколькими машинами. Любая информация, меняющаяся со временем должна располагаться в другом каталоге
bindir/usr/binПервичная директория для исполняемых файлов
sbindir/usr/sbinДиректория содержащая незначительные файлы, обычно используемые системным администратором: восстановление системы, монтирование /usr раздела и т.д.
libexecdir/usr/libexecДиректория для установки исполняемых программ, которые чаще запускаются другими программами, чем пользователями
datadir/usr/shareИерархия для всех архитектурно-независимых данных, используемых совместно различными хостами
sysconfdir/usr/etcКаталог с файлами для конфигурирования хоста. Предпочтительно использование /etc
sharedstatedir/usr/comДиректория для установки файлов с архитектурно независимыми данными, которые могут быть изменены программой
localstatedir/usr/varДиректория для установки файлов с данными, которые могут быть изменены программами в процессе работы, и которые принадлежат одной конкретной машине
libdir/usr/libСодержит объектные файлы, библиотеки, внутренние бинарные файлы. Подразумевается, что они не используются напрямую пользователем или скриптами шелл
infodir/usr/infoДиректория для установки Info-файлов для этого пакета
mandir/usr/manКаталог верхнего уровня для установки страниц man для текущего пакета
includedir
oldincludedir
/usr/includeСюда помещаются все заголовочные файлы языка C
pkgdatadir/usr/share/helloЗдесь хранятся данные приложения hello. Например, Glade формы
pkglibdir/usr/lib/helloЗдесь хранятся данные библиотеки hello. Например, вспомогательные библиотеки
pkgincludedir/usr/include/helloЗдесь хранятся заголовочные файлы библиотеки hello

Здесь ещё можно добавить следующее, в каталоге /usr/include/pixmaps лежат различные картинки, используемые программой в процессе её жизнедеятельности. Про другие каталоги, такие как /usr/include/doc я ничего верно сказать не могу, так как не видел обобщённой информации по этому поводу. Скорее всего структура файловой системы основана на FHS, а потом идёт собственно набивка различными пакетами.

6 авг. 2008 г.

Создаём пакет для Ubuntu. Часть 5. Переменные директорий для установки

Директории для установки должны всегда именоваться с помощью переменных, для того чтобы облегчить установку программы в нестандартное место. Стандартные имена этих переменных описаны ниже. Они основаны на стандартном расположении файловой системы; эти варианты используются в SVR4, 4.4BSD, Linux, Ultrix v4 и других современных операционных системах.

Эти две переменные устанавливаются суперпользователем для установки. Все другие инсталляционные директории должны быть подкаталогами одного из этих двух и ничего не должно устанавливаться напрямую в эти два каталога.

'prefix'
Префикс используется в построении значений переменных указаных ниже по умолчанию. По умолчанию, 'prefix' должен быть равен '/usr/local'. Когда происходит сборка полной GNU системы, префикс должен быть пустым и '/usr' должна быть символической ссылкой в '/'. (Если вы используете Autoconf, записывайте его как '@prefix@'.)
'exec_prefix'
Префикс также используется в построении значений переменных указанных ниже по умолчанию. По умолчанию, 'exec_prefix' должен быть равен $(prefix). (Если вы используете Autoconf, записывайте его как '@exec_prefix@'.) Как правило, $(exec_prefix) используется для каталогов, которые содержат машинно-специфичные файлы (такие как исполняемые или библиотеки подпрограмм), в то время как $(prefix) напрямую используется для других директорий.

Исполняемые программы устанавливаются в одну из следующих директорий (обратите внимание, это важно для решения нашей с вами задачи):

'bindir'
Директория для установки исполняемых программ, которые пользователь может запускать. Обычно это '/usr/local/bin', но записывается как '$(exec_prefix)/bin'.
(Если вы используете Autoconf, записывайте его как '@bindir@'.)
'sbindir'
Директория для установки исполняемых программ, которые пользователь может запускать из шелла, они обычно полезны системным администраторам. Обычно это '/usr/local/sbin', но записывается как '$(exec_prefix)/sbin'.
(Если вы используете Autoconf, записывайте его как '@sbindir@'.)
'libexecdir'
Директория для установки исполняемых программ, которые чаще запускаются другими программами, чем пользователями. Обычно это '/usr/local/libexec', но записывается как '$(exec_prefix)/libexec'.
(Если вы используете Autoconf, записывайте его как '@libexecdir@'.)

Файлы с данными, используемые программами на протяжении своей работы подразделяются на категории по двум направлениям:

  • Файлы, которые обычно изменяются программами; другие никогда обычно не изменяются (хотя пользователи могут редактировать некоторые из них).
  • Архитектурно-независимые файлы и могут использоваться всеми машинами участка; некоторые архитектурно-зависимые и могут использоваться только машинами с таким же типом операционной системы; другие которые никогда не могут быть "расшарены" между двумя машинами.

Всё это создаёт 6 различных возможностей. Однако, мы хотим предостеречь вас от использования архитектурно-зависимых файлов, в отношении от объектных файлов и библиотек. Будет гораздо чище делать другие файлы с данными архитектурно-независимыми, и это, в общем, не так сложно.

Вот почему, здесь предлагаются переменные, которые должны использовать мейкфайлы для указания каталогов:

'datadir'
Директория для установки файлов с архитектурно независимыми данными, доступными только для чтения. Обычно это '/usr/local/share', но записывается как '$(prefix)/share'.В качестве особого исключения смотрите ниже'$(infodir)' и '$(includedir)'.
(Если вы используете Autoconf, записывайте его как '@datadir@'.)
'sysconfdir'
Директория для установки файлов с данными, имеющими отношение к одной машине, доступными только для чтения. В общем это файлы для конфигурирования хоста. Файлы конфигурации почтовой программы и сети, '/etc/passwd' и всё подобное этому. Все файлы в этой директории должны быть обычными текстовыми файлами с кодировкой ASCII. Обычно это '/usr/local/etc', но записывается как '$(prefix)/etc'.
(Если вы используете Autoconf, записывайте его как '@sysconfdir@'.)

Не устанавливайте исполняемые файлы в этот каталог (они возможно принадлежат '$(libexecdir)' или '$(sbindir)'). Также не устанавливайте файлы, которые могут изменяться в процессе работы (здесь исключаются программы предназначенные для изменения конфигурации системы). Они возможно пренадлежат '$(localstatedir)'.
'sharedstatedir'
Директория для установки файлов с архитектурно независимыми данными, которые могут быть изменены программой. Обычно это '/usr/local/com', но записывается как '$(prefix)/com'.
(Если вы используете Autoconf, записывайте его как '@sharedstatedir@'.)
'localstatedir'
Директория для установки файлов с данными, которые могут быть изменены программами в процессе работы, и которые принадлежат одной конкретной машине. Пользователи не должны никогда их изменять в этом каталоге, чтобы конфигурировать действия пакета; помещайте такую настраиваемую информацию в отдельные файлы, в '$(datadir)' или '$(sysconfdir)'. Обычно '$(localstatedir)' это '$(/usr/local/var)', но записывается как '$(prefix)/var'.
(Если вы используете Autoconf, записывайте его как '@localstatedir@'.)
'libdir'
Директория для объектных файлов и библиотек. Не устанавливайте исполняемые файлы сюда, они возможно должны лежать в '$(libexecdir)'. Обычно это '/usr/local/lib', но записывается как '$(exec_prefix)/lib'.
(Если вы используете Autoconf, записывайте его как '@libdir@'.)
'infodir'
Директория для установки Info-файлов для этого пакета. Обычно это '/usr/local/info', но записывается как '$(prefix)/info'.
(Если вы используете Autoconf, записывайте его как '@infodir@'.)
'lispdir'
Директория для установки любых Emacs Lisp-файлов для этого пакета. Обычно это '/usr/local/share/emacs/site-lisp', но записывается как '$(prefix)/share/emacs/site-lisp'.
(Если вы используете Autoconf, записывайте его как '@lispdir@'.) В добавок, чтобы '@lispdir@' работало, вам нужно добавить следующие файлы в ваш 'configure.in' файл:
lispdir='${datadir}/emacs/site-lisp'
AC_SUBST(lispdir)
'includedir'
Директория для установки заголовочных файлов, которые включаются в пользовательские программы с помощью директивы препроцессора C '#include'. Обычно это '/usr/local/include', но записывается как '$(prefix)/include'.
(Если вы используете Autoconf, записывайте его как '@includedir@'.)
Большинство компиляторов, отличных от GCC не просматирвают заголовочные файлы в '/usr/local/include'. Поэтому установка заголовочных файлов этим путём полезна только для GCC. Иногда, это не является проблемой, потому что некоторые библиотеки действительно предназначены работать с GCC, но некоторые могут работать с другими компиляторами. Они должны устанавилвать свои заголовочные файлы в два места: includedir и oldincludedir.
'oldincludedir'
Директория для установки заголовочных файлов, которые включаются в пользовательские программы с помощью директивы препроцессора C '#include'. Обычно это '/usr/include'.
(Если вы используете Autoconf, записывайте его как '@oldincludedir@'.)
Команды Makefile должны проверять пустое ли значение '@oldincludedir@'. Если да, то они не должны использовать его и прервать вторичную установку заголовочных файлов.
Пакет не должен заменять существующие заголовочные файлы в этой директории, если он не из этого пакета (установленного ранее). Таким образом, если ваш пакет (например, Foo) предоставляет файл 'foo.h', то он должен устанавливать заголовочный файл в каталог oldincludedir, если, первое, здесь нет 'foo.h' файла, или, второе, существующий файл принадлежит пакету Foo.
Для определения того, что файл 'foo.h' "пришёл" из пакета Foo, поместите "магическую строку" (просто, некоторую уникальную) в файл, как часть комментария, и выполните для неё grep.

man-страницы в стиле Unix устанавливаются в следующие каталоги:

'mandir'
Каталог верхнего уровня для установки страниц man (если имеется) для текущего пакета. Обычно это '/usr/local/man', но записывается как '$(prefix)/man'.
(Если вы используете Autoconf, записывайте его как '@mandir@'.)
'man1dir'
Каталог верхнего уровня для установки страниц man секции 1. Записывайте как '$(mandir)/man1'.
'man2dir'
Каталог верхнего уровня для установки страниц man секции 2. Записывайте как '$(mandir)/man2'.
'...'
Не делайте первичную документацию любого GNU программного обеспечения в качестве man страницы. Вместо этого, записывайте руководство (мануал) в Texinfo. Страницы man предназначены для людей, запускающих ПО под Unix.
'manext'
Расширение файла для установленной страницы man. Оно должно содержать точку и следующую за ней соответствующую цифру: '.1'.
'man1ext'
Расширение файла для установленных страниц man секции 1.
'man2ext'
Расширение файла для установленных страниц man секции 2.
'...'
Используйте эти имена вместо 'manext', если пакету требуется установить страницы man в более, чем одной секции мануала.

И, в конце, вы должны установить следующую переменную:

'srcdir'
Каталог исходных файлов, которые следует компилировать. Значение этой переменно обычно вставляется скриптом configure.
(Если вы используете Autoconf, используйте 'srcdir = @srcdir@'.)

Например:

# Общий префикс для директорий пути установки.
# NOTE: Эта директория должна существовать к моменту начала установки.
prefix = /usr/local
exec_prefix = $(prefix)
# Куда помещать исполняемые файлы для команды 'gcc'.
bindir = $(exec_prefix)/bin
# Куда помещать директории используемые компилятором.
libexecdir = $(exec_prefix)/libexec
# Куда помещать Info-файлы.
infodir = $(prefix)/info

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

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

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

Создаём пакет для Ubuntu. Часть 4. Переменные для указанных команд

Мейкфайлы должны предоставлять переменные для переопределения определённых команд, опций и так далее. В частности, вы должны запускать большинство утилит через переменные. Так, например, если вы используете Bison, имеете переменную BISON, чьё значение по умолчанию устанавливается в 'BISON = bison', и вы должны ссылаться на неё с помощью $(BISON), когда используете.

Утилиты для управления файлами, такие как ln, rm, mv и так далее не нуждаются в ссылке через переменные, так как пользователи обычно не заменяют их другими программами.

Каждая переменная с именем программы должна сопровождаться переменной с опциями, которые используются с ней. Добавьте в конце 'FLAGS' к имени переменной, например, BISONFLAGS. Исключением является CFLAGS (из-за стандарта). Используйте CPPFLAGS в любой другой команде компиляции, использующей препроцессор, равно как LDFLAGS, которая используется в компоновщике (linker), например ld.

Если есть какие-нибудь опции, особенные для того или иного файла, не используйте их в CFLAGS, так как пользователи могут подумать, что её можно свободно менять. Старайтесь записывать эти опции непосредственно в само правило:

CFLAGS = -g
ALL_CFLAGS = -I. $(CFLAGS)
.c.o:
        $(CC) -c $(CPPFLAGS) $(ALL_CFLAGS) $<

Не включайте опцию '-g' в CFLAGS, потому что она не является необходимой для правильной компиляции (это ведь опция о включении отладочной информации). Если пакет настроен для сборки GCC по умолчанию, то вы можете включить опцию '-O' CFLAGS по умолчанию (правильно, почему бы не поставлять пакет готовым к оптимизации).

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

Каждый Makefile должен определять переменную INSTALL, являющуюся базовой командой для установки файла в систему. Также каждый Makefile должен определять переменную INSTALL_PROGRAM и INSTALL_DATA (значение по умолчанию у них должно быть равно $(INSTALL)). Затем, он должен использовать эти переменные в качестве команд установки исполняемых и не исполняемых файлов отдельно. Используйте их следующим образом:

$(INSTALL_PROGRAM) foo $(bindir)/foo
$(INSTALL_DATA) libfoo.a $(libdir)/libfoo.a

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

5 авг. 2008 г.

Создаём пакет для Ubuntu. Часть 3. Утилиты в Makefile'ах

В своих мейкфайлах вы можете использовать всевозможные команды для выполнения тех или иных задач. Ниже приводится информация о том, какие именно утилиты и когда вам рекомендуется их использовать.

Записывайте комманды Makefile (и любые шелл скрипты, такие как configure), чтобы они работали в sh шелле, а не csh. Не используйте любые специальные возможности ksh или bash.

Скрипт configure, правила от мейкфайла, и команды установки не должны использовать утилиты за исключением следующих:

cat cmp cp diff echo egrep expr false grep install-info ln ls mkdir mv pwd rm rmdir sed sleep sort tar test touch true

Архиватор gzip может использоваться в правиле dist.

Привыкайте к использованию общих опций у этих программ. Например, не используйте 'mkdir -p', даже если это удобно, так как большинство систем этого не поддерживают. Также избегайте создания символических ссылок, по понятным причинам.

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

ar bison cc flex install ld ldconfig lex make makeinfo ranlib texi2dvi yacc

Используйте следующие переменные make для запуска этих программ:

$(AR) $(BISON) $(CC) $(FLEX) $(INSTALL) $(LD) $(LDCONFIG) $(LEX) $(MAKE) $(MAKEINFO) $(RANLIB) $(TEXI2DVI) $(YACC)

При использовании ranlib или ldconfig, убедитесь, что ничего плохого не случится если система не имеет программу, о которой идёт речь. Игнорируйте ошибку от этой комманды и выводите сообщение перед вызовом комманды, чтобы сообщить пользователю, что ошибка этой комманды не считается проблемной. (Макрос Autoconf'а 'AC_PROG_RANLIB' может помочь с этим.)

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

Дополнительные утилиты, которые могут быть использованы через переменные Make следующие:

chgrp chmod chown mknod

Это нормально использовать другие утилиты в частях мейкфайла (или скриптах) предназначенных только для конкретных систем, где заведомо известно о существовании этих утилит

Создаём пакет для Ubuntu. Часть 2. Общие соглашения о Makefile'ах

Вы, я думаю, поняли основную идею configure файла. Здесь я постараюсь раскрыть структуру Makefile, воспользовавшись тем же документом что и раньше, GNU Coding Standards.

Вы, если увлекаетесь программированием, или компилируя чужие исходные коды, в процессе своей компьютерной жизнедеятельности должны были столкнуться с "мейкфайлами" (Makefile). В чем заключается их смысл? Их назначение состоит в том, чтобы автоматизировать процесс сборки вашего проекта. Как вы знаете простая программа может быть скомпилирована с помощью одной лишь строчки gcc main.cpp. На выходе вы получите файл a.out который потом можете запустить или переименовать.

А что делать, если ваш проект содержит несколько исходных файлов, и вы хотите имя отличное от стандартного? Можно конечно написать некий скрипт, который будет за вас вызывать, копировать и устанавливать ваши файлы. Вот таким стандартизованным методом и является Makefile, обычно располагающийся в корне вашего проекта.

Каждый Makefile должен содержать эту строку:

SHELL = /bin/sh

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

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

.SUFFIXES:
.SUFFIXES: .c .o

Первая линия очищает существующий список суффиксов, вторая показывает все суффиксы, которые могут являться предметом для неявных правил (я счтиаю, что здесь разговор идёт в первую очередь о том, что множество промежуточных объектов, файлов и прочего оканчиваются по-разному: *.c, *.cpp, *.cc, *.o, *.obj Поэтому чтобы компилятор не путался мы ограничиваем этот список)

Не делайте предположения о том, что '.' является путём для вызова команды. Когда вам требуется запустить программы, являющиеся частью вашего пакета в процессе работы make, убедитесь, что она использует путь './' (если программа собирается как часть make), или '$(srcdir)/' (если файл - не изменяющаяся часть исходного кода). Без этих префиксов используется текущий путь поиска (ну то, есть по всем /usr/bin и прочим пробежится, а не там где надо).

Различие между './' (директория, где собирается программа) и '$(srcdir)/' (директория с иходными файлами) важно, так как пользователи могут собирать программу в отдельный каталог, используя '--srcdir' опцию configure скрипта. Следующее правило:

foo.1 : foo.man sedscript
        sed -e sedscript foo.man > foo.1

будет ошибочным если директория сборки будет отличаться от директории с исходными файлами, так как 'foo.man' и 'sedscript' располагаются в каталоге с исходниками (то есть видите что перед ними нет никаких приставок с абсолютными значениями пути?).

При использовании GNU make, полагаясь на то, что 'VPATH' укажет на исходный файл и компиляция будет работать, только в случае единичного файла. Для этого существует автоматическая переменная '$<', представляющая сам исходный файл (что-то вроде псевдонима). Много версий make устанавливают '$<' только в неявных правилах. Цель Makefile вида

foo.o : bar.c
        $(CC) -I. -I$(srcdir) $(CFLAGS) -c bar.c -o foo.o

должна быть переписана как

foo.o : bar.c
        $(CC) -I. -I$(srcdir) $(CFLAGS) -c $< -o $@

чтобы позволить переменной 'VPATH' корректно работать. Когда цель имеет несколько зависимостей, используйте явное '$(srcdir)/' в качестве легчайшего пути, чтобы ваше правило работало. Например, для цели выше 'foo.1' напишите следующее:

foo.1 : foo.man sedscript
        sed -e $(srcdir)/sedscript $(srcdir)/foo.man > $@

Дистрибутивы GNU обычно содержат некоторые файлы, которые не являются исходными файлами: info файлы, вывод из Autoconf, Automake, Bision или Flex. Эти файлы обычно появляются в директории с исходными файлами, и потому они должны всегда появляться там, а не в каталоге сборки. Поэтому правила Makfile обновляющие их должны класть их в исходный каталог.

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

Постарайтесь сделать цели сборки и установки, по меньшей мере (и все их подцели) так, чтобы они работали с параллельным make (скорее всего разговор идёт о том, чтобы ваши файлы не конфликтовали в случае параллельной компиляции и сборки).

3 авг. 2008 г.

Создаём пакет для Ubuntu. Часть 1. Что такое конфигурирование

Введение

Столкнувшись с темой программирования под ОС Linux, передо мной возник вопрос о публикации исходных файлов таким образом, чтобы из них можно было скомпилировать и создать пакет, в частности deb пакет для операционной системы Ubuntu.

Программирования под ОС Windows, мне как-то не приходилось сталкиваться с программами типа make, а потому знания в области создания Makefile'ов у меня пока ещё нет. На руках имеется всего лишь набор исходных файлов моего небольшого проекта Gnome Quod.

Поискав в интернете некоторую информацию об этом процессе, я наткнулся на статью GNU Coding Standards. Возможно вы подумаете: "Вот! Ещё один перевод". Хорошо, пусть так и будет, но это лучше чем ничего, тем более, я не собираюсь переводить всю статью, так как она очень большая, и не всё мне оттуда пригодится для решения поставленной задачи. Здесь я постараюсь по пунктам перевести и описать всё, что следует делать, чтобы ваши программы смогли в конце-концов быть "инсталлируемыми".

Процесс создания релиза

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

Как должно работать конфигурирование

Каждый дистрибутив GNU должен снабжаться скриптом configure. Этому скрипту предоставляются аргументы, каждый из которых описывает ту или иную машину, для которой вы хотите скомпилировать программу (вы наверное часто встречали файлы ./configure.sh, так вот разговор идёт о них).

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

Один путь сделать это - это создать ссылку от стандартного имени, такого как config.h к нужному конфигурационному файлу, для выбранной системы. Если вы используете эту технику, то дистрибутив не должен содержать файла названного 'config.h'. Это сделано для того, чтобы не смогли создать программу без предварительного её конфигурирования.

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

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

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

Скрипт configure должен записывать файл с названием 'config.status', который описывает какие опции конфигурирования были указаны с последнего запуска скрипта. Этот файл должен быть скриптом shell, при запуске которого воссоздастся такая же конфигурация.

Скрипт configure должен принимать опцию вида '--srcdir=dirname' чтобы указать каталог, где находятся исходные файлы (если это не текущая директория). Это делает возможным сборку программы в отдельный каталог, поэтому текущая директория с исходными файлами не изменяется.

Если пользователь не указывает '--srcdir', то configure должен просмотреть оба каталога '.' и '..' в поисках исходных файлов. Если он находит исходники в одном из этих мест, то он должен использовать их отсюда, иначе - сообщить, что не может найти исходные файлы, и выйти с ненулевым статусом.

Обычно, легчайший путь для предоставления '--srcdir' - это редактировать директиву VPATH в Makefile. Некоторые правила могут нуждаться в явном указании исходной директории. Чтобы сделать это возможным, configure может добавить переменную с именем srcdir в Makefile, чьё значение точно указывает директорию.

Скрипт configure должен также принимать аргумент, указывающий тип ОС для которой собирается программа. Этот аргумент выглядет как cpu-company-system. Например, для Sun 3 - это 'm68k-sun-sunos4.1'

Когда я выполнил конфигурирование любого готового пакета, то на моей Ubuntu-машине я увидел следующие строки:

$ ./configure.sh
...
checking build system type... i686-pc-linux
checking host system type... i686-pc-linux
...

Покопавшись в файле config.sub можно найти большой перечень систем и процессоров.

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

'--enable-feature[=parameter]'
Конфигурирует пакет для сборки и установки пользовательской возможности, называемой функцией (feature). Это позволяет пользователям выбрать какие функции следует включать. Передавая необязательный параметр 'no', должно отключать возможность, если она встроена по-умолчанию. Опция '--enable' не должна быть причиной замены одной возможности на другую. Также опция '--enable' даже не должна заменять одно полезное поведение на другое. Единственное корректное использование для '--enable' это опрос того, какая часть программы должна включаться, а какая исключаться.
'--with-package'
Пакет package будет установлен, поэтому сконфигурируйте вашу сборку для работы с package. Возможные значения 'x', 'x-toolkit', 'gnu-as' (или 'gas'), 'gnu-ld', 'gnu-libc' и 'gdb'. Не используйте опцию '--with', чтобы указывать имя файла для использования некоторых файлов, так как это выходит за пределы области видимости.
'--nfp'
Машина назначения не имеет процессора для вычислений с плавующей точкой.
'--gas'
Ассемблер машины назначения - GAS (GNU assembler). Эта опция устарела, пользователи вместо неё должны использовать '--with-gnu-as'
'--x'
На машине назначение имеется установленная система X Window. Эта опция устарела, пользователи вместо неё должны использовать '--with-x'.

Все скрипты configure должны принимать опции "детально", так или иначе они осуществляют любое различие пакета. В частности, они должны принимать любую опцию начинающуюся с '--with-' или '--enable-'. Это позволит пользователям конфигурировать всё дерево исходников GNU одним набором опций.

Вы заметите, что категории '--with-' или '--enable-' узки: они не предоставляют места для любого другого вида опций, о которых вы можете подумать. Это неслучайно. Мы (я о группе GNU) хотим ограничить возможное число опций конфигурирования в программном обеспечении GNU. Мы не хотим, чтобы GNU программы имели уникальные конфигурационные опции.

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

Способ для сборки кросс-компилятора, кросс-ассемблера или того, что есть у вас, это указать опцию '--host=hosttype' при запуске configure. Это указывает исходную систему, без изменеия системы назначения. Синтаксис для hosttype такой же как было описано выше.

Улучшение кросс-компилятора требует компилирование его на машине отличной от той, на которой он будет работать. Пакеты компиляции принимают опцию '--host=hosttype' для назначения конфигурации, что вы будете собирать их на машине, отличной от хоста (другими словами, как я понимаю, если вы будете использовать компилятор на Sun машине, а на руках у вас другая *nix машина, то вам нужно собрать компилятор для Sun сперва, а потом его уже использовать там.)

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

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