2008-08-15
В прошлой главе мы научились устанавливать пакеты самыми различными способами и из различных источников. И убедились, что процедура эта совсем не трудная. При одном необходимом и достаточном условии: наличии в этих самых источниках, официальных или не совсем, нужного пакета.
Но что делать, если его нет ни в официальных репозиториях дистрибутива Zenwalk, ни в ZUR, ни даже в родственных репозиториях, которые в своё время выручили нас с загрузчиком GRUB? Остаётся вспомнить великую истину, высказанную некогда Ильфом и Петровым, которую один из героев Бориса Акунина счёл достойной помещения в Конституцию Государства Российского:
ДЕЛО ПОМОЩИ УТОПАЮЩИМ - ДЕЛО РУК САМИХ УТОПАЮЩИХ
(цитирую по Библиотеке Мошкова).
Что применительно к нашим условиям означает — взять и собрать недостающий, но позарез нужный пакет собственноручно. В большинстве случаев это тоже не Бог весть какое сложное занятие, и оно отнюдь не требует каких-то сверхъестественных навыков в программировании. В чем читатель, надеюсь, убедится из этой главы.
Впрочем, и при собственноручной сборке перед пользователем, как всегда бывает в мире Linux и Open Source, отрываются два пути. Первый — сборка пакетов «в лоб», второй — использование штатных средств построения пакетов дистрибутива Zenwalk. Поскольку понять второй путь, не пройдя по первому, невозможно, то с первого и начнём.
Ручная сборка пакетов из исходников — самый универсальный метод установки любого программного обеспечения. Собственно, в мире Open Source он единственно универсален — все прочие способы привязаны к тому или иному дистрибутиву или определенной системе управления пакетов или их построения.
В силу своей универсальности методы ручной сборки описывались бессчетное число раз. В частности, весьма подробно они освещены на страницах книги про POSIX'ивизм. Что избавляет меня от необходимости вдаваться в детали — остановлюсь только на ключевых моментах, необходимых для понимания специфики системы построения пакетов дистрибутива Zenwalk.
Процедура сборки пакета из исходных текстов в общем случае сводится к выполнению следующих действий:
Исходные тексты почти всех программ в мире Open Source распространяются в виде архивов, собранных утилитой tar и компрессированных посредством программ сжатия gzip или bzip2, то есть архивные файлы имеют примерно такой вид:
pkg_name-version-release.tar.gz
или
pkg_name-version-release.tar.bz2
соответственно. Иногда можно встретить архивные файлы в форме *.tgz или *.tbz — это те же самые «загзипленные» или «забзипленные» tar-архивы, переименованные для видимости в операционных системах, признающих имена файлов только по формуле 8.3 или не воспринимающих в именах множественных точек.
Получаются такие архивы, как правило, с авторских сайтов разработчиков (т.н. мастер-сайтов) или с серверов типа Sourceforge и им подобных, которые, при знании имени пакета, легко находятся с помощью Google. На худой конец, адреса мастер-сайтов всегда можно подсмотреть в портах FreeBSD, портежах Gentoo или пакетах Debian — этими системами окучен практически весь мир свободных исходников.
Распаковка архива осуществляется обычным образом:
$ tar xzfv path2/pkg_name-version-release.tar.gz
или
$ tar xjfv path2/pkg_name-version-release.tar.bz2
в зависимости от применявшейся утилиты компрессии. В большинстве случаев авторы пакетов предусматривают распаковку их архивов в собственный подкаталог типа ./pkg_name или ./pkg_name-version-release. Если в этом нет уверенности, во избежание захламления текущего каталога это лучше проверить:
$ tar tzfv path2/pkg_name-version-release.tar.gz
или
$ tar tjfv path2/pkg_name-version-release.tar.bz2
В графической среде (типа умолчальной для Zenwalk'а Xfce) для просмотра содержимого архивов и их распаковки можно воспользоваться программой Xarchiver — она же вызывается при щелчке мышью на файлах вида *.tat.gz или *.tar.bz2 в файловом менеджере Thunar.
После распаковки архива пакет остаётся только собрать. Для чего переходим в каталог, образовавшийся после распаковки архива и для начала внимательно читаем (почти наверняка) имеющиеся там файлы типа README и (или) INSTALL. Что позволяет удостовериться в том, что нам предстоит последовательно выполнить три магических действия — команды
$ ./configure $ make $ make install
Первая команда — это сценарий конфигурирования, находящийся в текущем каталоге пакета (почему и запускается с явным на то указанием — ./configure). В его задачу входит проверка установленных в системе компонентов, необходимых для сборки и функционирования собираемого пакета — пресловутых зависимостей. Если таковые оказываются на месте, можно приступать к следующей фазе процесса.
В противном случае последует более или менее внятное сообщение об ошибке, внимательное чтение которого обычно позволяет установить её причину; как правило, это отсутствие каких-либо библиотек, позарез необходимых нашему пакету (то есть нарушение «жестких» зависимостей).
Некоторые сценарии конфигурирования отслеживают также «мягкие» зависимости и любезно сообщают, какой функциональности собираемого пакета мы лишимся, если их не удовлетворим (например, поддержки мыши в консольных приложениях при отсутствии службы gpm, возможности печати или сканирования при отсутствии систем cups и sane соответственно).
Сценарий конфигурирования обычно предусматривает возможность указания необязательных опций. Наиболее часто используются флаги оптимизации для компилятора gcc, такие как CFLAGS И CXXFLAGS, опция prefix, переопределяющая корневой каталог для установки компонентов пакета (по умолчанию в этом качестве почти всегда выступает /usr/local), а также подключение или отключение дополнительных функций посредством опций with/without и enable/disable. Однако это тема совершенно особого разговора, которому здесь не место; заинтересованных отсылаю к главе 14 всё того же Введения в POSIX'изм.
Однако предположим, что зависимости мы или удовлетворили, или, если говорить о «мягких» зависимостях, проигнорировали. Теперь наступает время команды make, которая выполняет компиляцию бинарных файлов из исходных текстов и, в необходимых случаях, связывание их с функциями соответствующих библиотек (так называемую линковку, linking). Результатом будет появление в текущем каталоге или его подкаталогах исполняемого бинарника пакета и всех сопутствующих файлов типа man-страниц и прочей документации, примеров конфигурационных файлов и так далее.
На стадии сборки также возможны ошибки, обычно связанные с несоответствием версий библиотек и (или) компилятора (например, несоответствующим определением функций). Однако они решаются, скорее всего, только вмешательством в исходники, что мы здесь обсуждать не будем. А оптимистично предположим, что сборка завершилась благополучно и дадим команду
$ make install
В отличие от предыдущих команд, которые могут быть выполнены обычным пользователем, эта требует полномочий администратора. Ибо она выполняет очень простую, но важную функцию: видоизменяет файловую иерархию за пределами домашнего каталога, копируя собранные компоненты пакета в надлежащие места — по умолчанию, как уже говорилось, это почти всегда подкаталоги внутри /usr/local, такие как /usr/local/bin/, /usr/local/man, /usr/local/share и так далее. На этом сборку пакета можно считать законченной и приступать к его использованию.
По описанной схеме собирается, наверное, 99% всех пакетов, распространяемых в исходниках. Исключения редки. Например, пакет может быть настолько прост, что не требует предварительного конфигурирования. Или же в нем не предусмотрена автоматическая инсталляция — пользователю предоставляется право самому поместить исполняемые бинарники сотоварищи в те каталоги, которые он полагает для них подходящими. Все такие случаи, как правило, документированы в файлах README и INSTALL, почему и рекомендуется начинать сборку с их чтения.
Ручная сборка пакетов хороша своей универсальностью и гибкостью: в какой бы POSIX-системе мы ни находились, и какой бы пакет, для таковых предназначенный, нам не требовалось бы собрать, почти всегда мы можем сделать это посредством трех приведенных выше магических заклинаний. Причём можем сделать это, применив только нужные нам опции и задействовав необходимые функции (что далеко не всегда совпадает с умолчаниями разработчика).
Недостатки ручной сборки тоже известны наперечёт: в первую очередь это отсутствие учёта и контроля зависимостей пакетов, из чего вытекает сложность их удаления и обновления.
И тут впору вспомнить, что мы работаем не в абстрактной POSIX-совместимой системе, а в некоей вполне конкретной — в данном случае в роли её выступает Zenwalk Linux. И обратиться к её штатным средствам построения пакетов. Что позволяет, пожертвовав толикой универсальности, сохранить всю гибкость ручной сборки, приобретя к тому же ту самую систему учёта и контроля, простую и эффективную, за которую так горячо и тщетно ратовал Ульянов-Ленин.
Кроме того, построение пакета штатными средствами позволяет выполнить и Божью заповедь, велевшую, как известно, делиться. Сделав собранный пакет достоянием народа, мы добьёмся поставленной Господом цели легче, чем братва первой половины 90-х — с помощью утюгов и паяльников.
Каковы же они, эти штатные средства дистрибутива Zenwalk?
Собственно, такое дистрибутив-специфичное средство в нашем распоряжении одно — пакет buildpkg, но его вполне достаточно для решения всех поставленных перед нами задач: гибкости сборки, учёта, контроля и делёжки.
Правда, для начала сам пакет buildpkg следует установить — на инсталляционном диске Zenwalk'а его нет, и команда
$ netpkg list | grep buildpkg
даёт следующий результат:
[N][extra/d] Found buildpkg-1.6.0-noarch-54.1.tgz on the repository : not installed
из которого, впрочем, следует, что им богато в репозиториях. Так что действуем по описанному в прошлой главе рецепту:
$ netpkg buildpkg
разумеется, от имени суперпользователя. После чего можно заняться изучением возможностей установленного пакета.
Пакет buildpkg состоит из одноименного bash-сценария в /usr/bin, документации, в том числе man-страниц — buildpkg.8 и ZENBUILD.5 (что это такое, мы скоро узнаем), двух примеров конфигов, среди которых самый для нас важный — /etc/buildpkg/ZENBUILD, и нескольких служебных файлов.
Исполняемый файл пакета, как я уже говорил, представляет собой обычный сценарий оболочки, конкретно — /bin/bash, в чём легко убедиться, просмотрев его первую строку:
$ head -n 1 /usr/bin/buildpkg #!/bin/bash
В его задачи входит:
Не очень понятно? Согласен. Надеюсь, что вскоре всё прояснится. А пока скажу так: связка из buildpkg, build-pkg_name.sh и installpkg делает примерно то же самое, что и любая система построения пакетов и любая система управления ими. То есть:
А поскольку все звенья этой цепочки, несмотря на кажущуюся длину и сложность, суть простые bash- или sh-скрипты, то интегрально она оказывается весьма простой, пожалуй что проще портов FreeBSD и, уж конечно, проще портежей Gentoo.
Правда, как отметили авторы Buildpkg How-to, всё это
...не подменяет знания того, как надо компилировать. Вы только не обязаны знать детали сборки пакетов, поскольку об этом заботятся инструментальные средства.
И всё же успех сборки целиком и полностью зависит от корректного заполнения файла ZENBUILD, но ведь и во всех остальных системах построения пакетов дело обстоит точно так же. Поэтому самое время посмотреть, что такое
и с чем его едят.
Что такое ZENBUILD, вкратце уже говорилось: это файл, содержащий формализованное описание действий, которые необходимы для сборки пакета, предназначенного для установки в дистрибутиве Zenwalk. А едят его с текстовым редактором, ибо он представляет собой простой текстовый файл, в котором нужно просто заполнить строки, соответствующие реалиям собираемого пакета.
Для облегчения жизни сборщика при установке пакета buildpkg, как уже говорилось, устанавливается и прототип этого файла — /etc//buildpkg/ZENBUILD, специально предназначенный для всех издевательств, которые составят предмет настоящего раздела. Описание этих издевательств будет дано на примере сборки реального пакета — flwm версии 1.02; мысль собрать его появилась у меня после прочтения статьи о легких оконных менеджерах, в которой места для него почему-то не нашлось, как не обнаружился этот легчайший из лёгких менеджеров окон и в официальных репозиториях Zenwalk и его пользовательском репозитории.
Сборку пакета мы начинаем с того, что создаём каталог, где будут происходить все дальнейшие события:
$ mkdir ~/path2/flwm
И первым событием будет помещение в него прототипа файла ZENBUILD. Это можно сделать простым копированием
$ cp /etc//buildpkg/ZENBUILD ~/path2/flwm/
Но если последовательно следовать пути Дзэн, то лучше это сделать так:
$ buildpkg -g
Теперь извлекаем из закромов Родины любимый текстовый редактор. Если такового пока не имеется, рискну предложить на эту роль Geany — кстати, это один из способов убедиться в его несравненных достоинствах для достижения поставленной цели.
Первозданный ZENBUILD выглядит следующим образом:
#Maintainer: Name <email@address.com> #Former Maintainer(s): Name <email@address.com> #Anything commented out is optional and can be deleted.pkgname= pkgver= pkgrel= zenver= arch=i486 source=() #sourcetemplate=http://users.zenwalk.org/user-accounts/pnboy/$pkgname/$pkgver/ #docs=("readme" "install" "copying" "changelog" "authors" "news" "todo") #url= #extradepends=() #lessdepends=() #dotnew=() #CFLAGS= #CXXFLAGS= #options=('noextract')
#doinst() { # #}
slackdesc=\ ( #|-----handy-ruler------------------------------------------------------| "" )
build() { cd $startdir/src/$pkgname-$pkgver ./configure --prefix=/usr --localstatedir=/var --sysconfdir=/etc make || return 1 make install DESTDIR=$startdir/pkg }
Для удобства мы расчленим его на несколько секций, которые и рассмотрим последовательно.
Смысл первой секции --
#Maintainer: Name <email@address.com> #Former Maintainer(s): Name <email@address.com> #Anything commented out is optional and can be deleted.
ясен. Это имя, под которым выступает нынешний сборщик пакета, и его адрес, аналогичные данные для сборщика прежнего, если таковой имелся, а также некий комментарий, буде таковой требуется по смыслу. Все три строки первой секции закрыты символами комментария и должны оставаться таковыми и впредь.
Вторая секция — от строки pkgname до source включительно — включает переменные, значения которым должны быть определены столь же непременно (Mandatory), сколь обязательным было исполнение мандатов Великого Ленина. Этими значениями будут:
В результате заполнения всех обязательных полей эта секция для нашего примера (пакета flwm-1.02), Mandatory-секция приобретёт следующий вид:
pkgname=flwm
pkgver=1.02
pkgrel=1
zenver=1
arch=i486
source=("http://flwm.sourceforge.net/$pkgname-$pkgver.tgz")
Обращаем внимание, что в прототипе ZENBUILD ни одна строка не закомментирована — и все они должны остаться таковыми в итоговом файле.
Следующая секция — опциональная (Optional) или, скорее, дополнительная. Здесь, напротив, ремарками закрыты все строки. Однако, как станет ясно из дальнейшего изложения, это не значит, что все они не обязательны. Те, которым необходимо или желательно придать значения, должны быть раскомментированы.
Смысл ополнительных переменных следующий:
В нашем примере с пакетом flwm вся опциональная секция свелась к четырём строкам:
docs=("readme")
url="http://flwm.sourceforge.net/"
extradepends=('fltk' 'xcb')
options=('requiredbuilderflatdeps')
Отступление. В свете того, что говорилось на протяжении этой и ряда предшествующих глав, может возникнуть резонный вопрос: а откуда же берутся сведения о необходимых зависимостях? Ведь ранее неоднократно подчеркивалось, что отслеживание их — одна из самых сложных задач, которые призваны решать системы построения пакетов и управления ими.
Ответ, как всегда, двоякий. Во-первых, для простых пакетов типа нашего flwm их можно просто знать — в этом часто помогут разработчики, приводящие сведения о зависимостях своих пакетов на сайтах проекта. Так, автор оконного менеджера flwm, Bill Spitzak (транскрибировать его фамилию не берусь), на своем сайте указывает, что для сборки этого пакета необходима библиотека fltk (разработанная им же).
Однако в отношении сложных пакетов со множеством зависимостей этот подход может не дать результата. И тогда на помощь прходит ещё один, специальный, скрипт — requiredbuilder. Если выполнить его с указанием текущего каталога в качестве аргумента, то последует серия запросов такого типа (на примере flwm):
$ requiredbuilder . Do you want to add these dependencies to the slack-required? Reply yes or no:Ответы будут отражены в файле ./install/slack-required, откуда их легко будет извлечь для использования в построении ZENBUILD.cxxlibs | gcc-g++ Do you want to add this dependency? [yes] y fltk Do you want to add this dependency? [yes] y gcc Do you want to add this dependency? [yes] y xcb Do you want to add this dependency? [yes] y xorg-libs Do you want to add this dependency? [yes] y
Вернёмся, однако, к заполнению ZENBUILD. Следующая секция — slackdesc — представляет собой описание пакета, выполненное по правилам, которые приняты в Slackware. Согласно этим правилам, первая строка должна содержать имя пакета (определяемое через значение переменной pkgname) и его (очень) краткое описание, примерно такое:
"$pkgname - fast light window manager"
Далее идёт описание более подробное. Оно также должно быть разбито на строки, каждая из которых заключается в кавычки и должна содержать не более 70 символов. Всех же строк в slackdesc должно быть не более 10, причём — по-английски, почему я и воздержусь от приведения примера.
И, наконец, последняя секция — функция build(), которая собственно и описывает процесс сборки пакета. В прототипе файла ZENBUILD она выглядит так:
build() {
cd $startdir/src/$pkgname-$pkgver
./configure --prefix=/usr --localstatedir=/var --sysconfdir=/etc
make || return 1
make install DESTDIR=$startdir/pkg
}
Можно видеть, что содержимое функции build() — те самые три магических заклинания, о которых шла речь в первом разделе этой главы. Опции конфигурирования определяют корневые каталоги для установки собранных компонентов (--prefix=/usr), модифицируемых файлов (--localstatedir=/var) и общесистемных каталогов. В ряде случаев в этой функции ничего менять не надо — именно так обстоит дело с нашим примером, пакетом flwm. Однако если сборщик пакета полагает необходимым включить какие-либо дополнительные функции или, напротив, отключить те из них, которые включены по умолчанию, то задать соответствующие опции конфигурирования следует именно здесь в виде:
./configure --prefix=/usr --localstatedir=/var --sysconfdir=/etc \ --with-PACKAGE --without-PACKAGE \ --enable-FEATURE --disable-FEATURE
Подробности по использованию опций with/without и enable/disable с конкретными примерами можно найти в главе 14 книги Введение в POSIX'ивизм.
По завершении заполнения ZENBUILD можно заняться и собственно сборкой пакета, для чего вспоминаем о сценарии buildpkg, которому принадлежит главная роль в этом процессе. Если не спешить и действовать последовательно, то начать следует с запуска этого скрипта без опций и аргументов. Результатом будет создание скрипта build-$pkgname.sh, каковой можно просмотреть на предмет общего образования.
Дальнейшие действия потребут, во-первых, использования опций сценария buildpkg, во-вторых, прав суперпользователя. Получив оные посредством su, запускаем команду
$ buildpkg -x
которая пересоздаст файл build-$pkgname.sh и запустит его на исполнение. Результатом чего будет:
ZENBUILD build-flwm.sh http://flwm.sourceforge.net/flwm-1.02.tgzсодержание которых вполне прозрачно.
Подкаталоги ./pkg и ./src нужны нам только для изучения и проверки правильности выполненных действий в случае получения ошибок, так что теперь их вполне можно удалить. Делается это командой
$ buildpkg -c
после которой в каталоге — «сборочном цехе» остаются компоненты, нужные в дальнейшей жизни:
$ ls -1 . ZENBUILD build-flwm-1.02-i486-1.1.log build-flwm.sh flwm-1.02-i486-1.1.dep flwm-1.02-i486-1.1.md5 flwm-1.02-i486-1.1.src flwm-1.02-i486-1.1.tgz
и изначальный архив исходников — flwm-1.02.tgz.
При уверенности в правильности сборки её можно совместить с избавлением от отходов жизнедеятельности, что достигается командой
$ buildpkg -X
После этого остаётся лишь завершающий штрих — собственно установка пакета, выполняемая традиционным образом:
$ installpkg flwm-1.02-i486-1.1.tgz
Результатом чего будет не только установка пакета, но и фиксация его в базе данных — в виде файла в соответствующем каталоге:
/var/log/packages/flwm-1.02-i486-1.1
и в виде подкаталога в /usr/src:
/usr/src/flwm-1.02/
содержащего файлы ZENBUILD и build-flwm.sh.
Следствием чего будет лёгкость удаления пакета при необходимости. В отличие от пакета, собранного «в лоб», для удаления которого потребовалось бы сохранение каталога с деревом исходников и команда типа
make deinstall
(да и то, только если цель deinstall предусмотрена разработчиком), наш пакет может быть удалён штатными средствами — командой
/sbin/removepkg flwm
А файл /usr/src/flwm-1.02/ZENBUILD позволит отследить его зависимости и, если с ними не связано никаких более пакетов (а с библиотекой fltk в нашей системе не связано ничего, кроме flwm), избавиться также и от них.
Несмотря на все проделанные действия, наш «самопальный» пакет не стал ещё полноценным zen-пакетом, пригодным к тому, чтобы с ним работала система netpkg. И дело не в отсутствии служебных файлов типа pkgname.meta, о которых шла речь в предыдущей главе: вся необходимая для их генерации метаинформация у нас имеется, а сам процесс генерации — дело техники.
Однако для того, чтобы netpkg получил доступ к нашему пакету, тот должен быть включён в какой-либо репозиторий, а адрес последнего прописан в файле /etc/netpkg.conf.
Можно, конечно, организовать для этого собственный репозиторий — только из лично собранных пакетов. Вот только стоит ли овчинка выделки? Ведь это означает не только создание и поддержку репозитория для нескольких пакетов. Каждый из этих пакетов также нуждается в поддержке, то есть пересборке по выходе новой версии. И всё это — для себя, любимого. Да и вспомним, что в качестве одной из целей сборки пакетов нами была поставлена «делёжка» — обеспечение доступа широких народных масс к результатам нашей «собирательной» деятельности.
Так что лучше поместить свой пакет в общедоступные репозитории проекта Zenwalk. Разумеется, наивно было бы ожидать, что команда разработчиков дистрибутива спит и во сне видит, как бы сподобиться такого счастья и поместить наш пакет в официальный репозиторий, не дожидаясь, пока кулер процессора остынет после компиляции этого пакета. Однако не следует забывать о ZUR — пользовательском репозитории дистрибутива Zenwalk, специально предназначенном для помещения результатов народного творчества.
Что нужно для приобщения к ZUR? Для начала, конечно, следует убедиться, что собранного пакета нет ни в официальном, ни в пользовательском репозитории. Впрочем, истинный линуксоид не станет делать работу, если она уже кем-то сделана, так что, думаю, поиск пакета в репозиториях был первым этапом его сборки.
Далее, конечно, следует собрать пакет и проверить его работоспособность на собственной машине (а при возможности — и на машине ближнего своего). После этого остаётся только зарегистрировать на ZUR свой аккаунт, пройти проверку его валидности, зайти под своим логином и со своим паролем и закачать на сервер те самые файлы, которые сохранились в «сборочном» каталоге после процедуры buildpkg -X:
ZENBUILD build-flwm-1.02-i486-1.1.log build-flwm.sh flwm-1.02-i486-1.1.dep flwm-1.02-i486-1.1.md5 flwm-1.02-i486-1.1.src flwm-1.02-i486-1.1.tgz
Очевидно, что архив исходников на сервер помещать не нужно — ведь в нашем build-скрипте предусмотрено автоматическое его получение из Сети.
И еще хорошо бы не забыть придать своему пакету статус Testing — дабы его возможные пользователи знали, с чем имеют дело.
После этого своим пакетом можно любоваться на первой странице ZUR. Впрочем, счастье это будет недолгим — новые или обновлённые пакеты в пользовательский репозиторий добавляются весьма активно.
Теперь, вероятно, можно расчитывать, что, если ваш пакет будет востребован широкими кругами пользователей и пройдёт некую апробацию, то со временем он окажется и в официальном репозитории. Впрочем, я такого счастья не сподобился (и вряд ли сподоблюсь), так что как это происходит — сказать не могу.