Наши партнеры








Книги по Linux (с отзывами читателей)

Библиотека сайта rus-linux.net

На главную -> MyLDP -> Тематический каталог -> Установка новых программных пакетов

Упаковка программ с помощью RPM, часть 3: Разрешение зависимостей между пакетами

Оригинал: "Packaging software with RPM, Part 3: Accommodating software dependencies"
Автор: Martin Streicher
Дата публикации: 12 January 2010
Перевод: Н.Ромоданов
Дата перевода: февраль 2010 г.

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

На заре компьютеризации, каждый фрагмент программного обеспечения был монолитен. Исключая ПЗУ, которое использовалось для загрузки машины, и самой операционной системы, к каждому приложению прилагались все библиотеки и код, необходимый для его работы. Такой подход был целесообразным главным образом из-за того, что те компьютеры не были многозадачными. Однако затем компьютеры совершенствовались не по дням, а по часам, и стали поддерживать как одновременную работу со многими пользователями (разделение по времени), так и одновременное исполнение нескольких приложений. Поскольку несколько пользователей запускали одно и то же приложение и совместно использовали такие системные ресурсы, как файловую систему и оперативную память, то с точки зрения оптимизации стало необходимым и разумным совместное использование одного и того же кода.

Сегодня почти в каждой операционной системе библиотеки отделены от приложений и они объединяются вместе только во время исполнения приложения. Но разделяемые библиотеки (shared library — библиотека, разделяемая между несколькими приложениями, т. е. ими одновременно совместно используемая — прим.пер.) имеют свои плюсы и минусы. К "плюсам" относится то, что каждое приложение становится меньше, поскольку оно не должно быть монолитным. Более того, если в совместно используемой библиотеке исправляется ошибка, либо повышается ее производительность, преимущество от этого получают все приложения. Однако разделение приложений и библиотек в чем-то напоминает оковы: разделяемые библиотеки должны быть доступны и совместимы, иначе приложение не сможет работать.

Связь между приложением и библиотекой - это один из видов зависимости. Если вы распространяете исходный код и требуете для компиляции кода наличия определенного набора заголовочных файлов, то это тоже зависимость. Для вашего кода также может потребоваться конкретный инструментарий для компиляции, такой как Bison или Yacc. Если вы распространяете ваше программное обеспечение в виде пакета RPM, то вы, прежде чем установите код, должны убедиться, что в целевой системе разрешаются все зависимости (в системе имеются все необходимые библиотеки и инструментальные средства — прим.пер.). В конце концов, если система не подходит, то нет особых причин устанавливать в ней приложение.

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

Определение зависимостей

Когда вы создаете пакет RPM, вы можете объявить следующие четыре вида зависимостей:

  • Если для вашего пакета что-то требуется, что должно быть представлено другими пакетами, то задается требование (requirement).
  • Если другие пакеты зависят или потенциально могут зависеть от того, что предоставляет ваше программное обеспечение, то задается предложение (provides).
  • Если ваша программа (или часть вашего программного обеспечения) не может сосуществовать одновременно с каким-либо другим пакетом, то зависимость является конфликтом (conflict).
  • Если ваш пакет заменяет действие другого пакета или более старой версией вашего собственного программного обеспечения, определяется то, что будет считаться устаревшим (obsolete, т. е. того, что будет заменено — прим. пер.).

Каждая зависимость указывается отдельно в файле спецификаций RPM. Синтаксис следующий Type: Capability, где Type является одним из четырех понятных по своему названию тегов (Requires, Provides, Conflicts или Obsoletes), а Capability является указанием на приложение (пакет), сопровождаемое необязательным номером версии. Если у вас есть несколько значений Capability, задаваемых списком, они перечисляются все на той же строке, разделенные пробелами или запятыми.

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

Requires: perl

Если для вашего приложения требуется Perl и MySQL, вы можете записать:

Requires: perl, mysql 

Часто приложение зависит от конкретной версии или конкретного основного релиза пакета. Например, если вы написали код на языке Ruby, который совместим с версией 1.9, вы зависите от этой версии интерпретатора. Для того, чтобы указать зависимость от версии, добавьте в Capability номер версии:

Requires: ruby >= 1.9

Вы можете указывать номера версии в любом из четырех видов зависимостей. Синтаксис идентичен. Например, если ваше приложению несовместимо с версией интерпретатора Bash более новой, чем версия 2.0, вы должны записать:

Conflicts: bash > 2.0

Есть шесть вариантов сравнения номера версий:

  • package < revision требует, чтобы указанный package имел номер версии, меньший чем revision.
  • package > revision указывает, что package был более новый, чем revision.
  • package >= revision требует от package чтобы его номер был больше или равен номеру revision.
  • package <= revision требует, чтобы номер package был меньше или равен номеру revision.
  • package = revision разрешает использовать только конкретный релиз revision.
  • package разрешает использовать любой релиз пакета package.

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

Подписываем пакет RPM

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

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

Сначала вы должны иметь пару ключей GPG: закрытый ключ и открытый ключ. Если они у вас отсутствуют, то их сгенерировать просто. Первым шагом является запуск пакета gpg-agent, который осуществляет управление ключами. В системах обычно для всех пользователей используется один и тот же пакет gpg-agent. Обратитесь к системному администратору, чтобы определить, требуется ли установка этого пакета. Если в системе этот пакет уже работает, спросите администратора, как к этому пакету подключиться.

$ gpg-agent --daemon --enable-ssh-support \
  --write-env-file "${HOME}/.gpg-agent-info"

Пакет gpg-agent создает в вашем домашнем директории файл .gpg-agent-info. В этом файле содержатся настройки среды вашей шелл-оболочки, которые нужны для запуска этого пакета. Загрузите информацию с помощью следующей команды (наберите в ответ на запрос всю команду, либо, для удобства добавьте ее в файл запуска вашей оболочки):

$ if [ -f "${HOME}/.gpg-agent-info" ]; then
  . "${HOME}/.gpg-agent-info"
  export GPG_AGENT_INFO
  export SSH_AUTH_SOCK
  export SSH_AGENT_PID
fi

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

$ GPG_TTY=$(tty)
$ export GPG_TTY

Теперь вы готовы сгенерировать ключ. Запустите команду gpg —gen-key и отвечайте на запросы. На листинге 1 показан пример сессии генерации ключа. Вводимые данные выделены жирным.

Листинг 1: Пример сессии генерации ключей

$ gpg --gen-key
gpg (GnuPG) 1.4.9; Copyright (C) 2008 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Please select what kind of key you want:
   (1) DSA and Elgamal (default)
   (2) DSA (sign only)
   (5) RSA (sign only)
Your selection? 1
DSA keypair will have 1024 bits.
ELG-E keys may be between 1024 and 4096 bits long.
What keysize do you want? (2048) 1024
Requested keysize is 1024 bits
Please specify how long the key should be valid.
         0 = key does not expire
      <n>  = key expires in n days
      <n>w = key expires in n weeks
      <n>m = key expires in n months
      <n>y = key expires in n years
Key is valid for? (0)  0
Key does not expire at all
Is this correct? (y/N) y

You need a user ID to identify your key; the software constructs the user ID
from the Real Name, Comment and Email Address in this form:
    "Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>"

Real name: Martin Streicher
Email address: martin.streicher@example.com
Comment: Example key for RPM
You selected this USER-ID:
    "Martin Streicher (Example key for RPM) <martin.streicher@example.com>"

Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
You need a Passphrase to protect your secret key.

Enter passphrase: ******
Retype passphrase: ******

We need to generate a lot of random bytes. It is a good idea to perform
some other action (type on the keyboard, move the mouse, utilize the
disks) during the prime generation; this gives the random number
generator a better chance to gain enough entropy.
+++++++++++++++++++.+++++.++++++++++++++++++++.+++++>.+++++.+++++..>+++++.+++++

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

После завершения генератор ключей создаст новый директорий с именем $HOME /.gnupg и заполнит его файлами, которые будут вашими закрытыми и открытыми ключами. Для того, чтобы посмотреть, какие у вас есть ключи, выполните команду gpg --list-key. Обратите внимание на uid: в нем содержится имя ключа, который вы должны использовать для подписи пакета RPM.

$ gpg --list-key
/home/strike/.gnupg/pubring.gpg
-------------------------------
pub   1024D/1811A3E4 2009-11-23
uid                  Martin Streicher (Example key for RPM) <martin.streicher@example.com>
sub   1024g/15BBCF06 2009-11-23 

Далее для продолжения требуется установить параметры подписи пакета RPM. Создайте или откройте файл $HOME/.rpmmacros, и добавьте в него следующие три строки:

%_signature gpg
%_gpg_path /home/strike/.gnupg
%_gpg_name Martin Streicher (Example key for RPM) <martin.streicher@example.com>

В строке %_signature выбирается тип подписи. Здесь установлено gpg. Значение %_gpg_name указывает идентификатор ключа, которым осуществляется подпись. В процессе генерации ключа в качестве имени ключа было выбрано Martin Streicher (Example key for RPM) <martin.streicher@example.com> (значение идентификатора пользователя [UID], указанное ранее), так что оно здесь повторяется. Наконец, %_gpg_path указывает путь к вашим ключам.

Если есть ключи и правильно настроена конфигурация, то для подписывания пакета RPM потребуется только один дополнительный параметр --sign.

$ rpmbuild -v --sign -bb --clean SPECS/wget.spec
Enter pass phrase: 
Pass phrase is good.
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.46786
+ umask 022
...

Здесь изображена та же самая команда rpmbuild как и та, что была использована в первой части нашей серии, но только с одним добавлением: --sign. Когда вы получите запрос на ввод пароля, введите ту же самую фразу, которую вы использовали во время генерации ключей. Сборка пакета RPM продолжится и результирующий пакет будет подписан.

Вы можете проверить вашу подпись, чтобы убедиться, что ваш пакет никто не изменил. Чтобы проверить подпись пакета RPM, выполните команду rpm -K над файлом самого пакета:

$ rpm -K wget-1.12-1.i386.rpm
wget-1.12-1.i386.rpm: (SHA1) DSA sha1 md5 (GPG) OK

Если команда выдаст сообщение ОК, файл правильный. Если вы скачали пакет RPM другого разработчика, то перед установкой сначала проверьте пакет.

Дополнительный инструментарий для разработки RPM

Если для создания пакетов вы часто пользуетесь технологией RPM, то вы привыкли работать с файлами спецификаций. Тем не менее, есть очень много инструментальных средств, которые помогают создавать файлы спецификаций. Вот несколько примеров:

  • Пакет rpmlint осуществляет проверку файлов RPM. Этот инструмент позволяет отловить большое количество ошибок. Установка бинарных файлов в директорий /etc и конфигурационных файлов в директорий /usr являются типичными ошибками, обнаруживаемые rpmlint, но вы можете расширить его возможности с помощью настраиваемых модулей. Пакет rpmlint написан на языке Python и для того, чтобы он выполнял свои функции, требуется некоторые библиотеки.
  • Easy RPM Builder - это инструментальное средство, базирующееся на K Desktop Environment (KDE) и предназначенное для сборки пакетов. В нем есть несколько шаблонов, которые помогут начать вам разработку ваших пакетов RPM, и есть графический интерфейс, помогающий работе с файлами спецификаций. В этом инструментальном средстве есть несколько шаблонов, которые помогут вам правильно начать разработку RPM; а для части файла спецификаций предоставлен графический интерфейс. Easy RPM Builder не заменит rpmbuild - требуется некоторое знание RPM для того, чтобы эффективно использовать этот инструмент.
  • Если вы не используете KDE или предпочитаете работать с файлами спецификаций напрямую, вы можете расширить редакторы Vim и Emacs, добавив в них специальные модули, которые будут подсвечивать синтаксис файла спецификаций и помогут при его создании и модификации.
  • Хотя это и не является инструментом как таковым, в руководстве по RPM в проекте Fedora перечислены лучшие примеры практического использования RPM. Если вы собираетесь распространять программное обеспечение на Fedora, то обязательно обратите особое внимание на требования, касающиеся новых пакетов. Кроме того, в руководстве описывается как создавать пакеты приложений с использованием таких популярных платформ, как Eclipse, Perl и Ruby. Особое внимание уделяется созданию пакетов программ для конкретных интерпретаторов, поскольку в состав таких пакетов могут входить скрипты, бинарные модули и исходный код, которые во время установки должны быть пересобраны непосредственно под целевую машину. Например, модуль на Perl может быть частично написан на Perl и частично на С. На сайте Fedora можно также найти официальное руководство по использованию RPM.

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

Заключение

Технология RPM активно поддерживается. Вы можете отслеживать текущее состояние проекта RPM на его новой домашней странице. Средства работы с RPM существуют в большинстве дистрибутивов Linux, в том числе и в Debian. Последней версией RPM является 5.2.0, которая была выпущена в июле 2009 года. Цели проекта RPM остаются прежними: "Упрощаем добавление пакетов в систему и удаление их из системы, упрощаем проверку правильности установки пакетов в системе, упрощаем сборку пакетов, упрощаем сборку пакетов из исходного кода и запускаем пакеты на компьютерах с различной архитектурой".

Разработка пакета RPM может быть сложной, поскольку столь же сложна установка программ. В этой серии статей затронуты лишь некоторые темы. В интернете можно найти много информации об RPM. Есть учебники, форумы и даже IRC канал посвященные этой теме (посетите # rpm.org на Freenode). Кроме того, в сети можно найти сотни, если не тысяч других примеров RPM. Если вы встретитесь с особенно запутанной проблемой, поищите еще один пакет RPM и, проанализировав его файл спецификаций, попытайтесь по аналогии найти решение.

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


Другие статьи об управлении программным обеспечением в Linux в нашей Библиотеке.