Ruby Packaging mini-HOWTO
Материал из ALT Linux Wiki
(Import from freesource.info) |
SirRaorn (обсуждение | вклад) (Import from freesource.info) |
||
Строка 1: | Строка 1: | ||
- | [[Category: | + | [[Category:Sisyphus]] |
- | {{MovedFromFreesourceInfo|AltLinux/ | + | {{MovedFromFreesourceInfo|AltLinux/Sisyphus/ruby}} |
- | == Ruby | + | == Ruby == |
- | + | Основные правила сборки приложений и модулей ruby изложены в [[Ruby|Ruby Packaging Policy]]. Цель же этого документа - об'яснить на простых примерах как следует поступать в различных ситуациях а также показать как можно собирать простые модули. | |
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
+ | Я не рассматриваю rubygems, так как эта система включает в себя свой пакетный менеджер, не совместимый с дистрибутивным. Про отношение Debian к rubygems можно прочитать [http://pkg-ruby-extras.alioth.debian.org/rubygems.html тут], рекомендации апстриму изложены [http://pkg-ruby-extras.alioth.debian.org/upstream-devs.html тут]. У нас ситуация в общем аналогичная. | ||
- | + | ''Тут пока находится поток сознания, который я буду приводить к нормальному виду.'' | |
__TOC__ | __TOC__ | ||
- | === | + | === Общие принципы сборки модулей === |
- | + | Есть два способа сборки модулей. При помощи rubygems (который мы не рассматриваем по ряду причин), и "нативная" сборка, с помещением файлов в специальные каталоги, которые находятся в <tt>$LOAD_PATH</tt>. | |
- | + | Сборка пакета включает в себя: | |
- | + | * компиляцию бинарных модулей (если они есть); | |
+ | * выполнение тестов (если они есть и их выполнение возможно в hasher); | ||
+ | * установку файлов в соответствующие каталоги; | ||
+ | * генерацию документации в формате ri (class reference); | ||
- | + | Модули устанавливаются в так называемый vendor dir. В ALT Linux это <tt>/usr/share/ruby/vendor_ruby/RUBY.VERSION</tt> и <tt>/usr/lib/ruby/RUBY.VERSION/ARCHITECTURE</tt>. Поскольку по умолчанию установка модулей идёт в site dir, при сборке пакета надо использовать модуль <tt>vendor_specific</tt>, вызывая интерпретатор ruby как <tt>ruby -rvendor_specific</tt>. Для этого есть макрос <tt>%ruby</tt>. | |
- | + | === Внутри тарбола === | |
- | + | Внутри тарбола с модулем (или программой) могут находиться следующие файлы и каталоги: | |
- | + | * '''bin/''' - скрипты, будут установлены в <tt>%_bindir</tt>; | |
+ | * '''ext/''' - компилируемые модули (при использовании <tt>setup.rb</tt>), будут установлены в <tt>%ruby_sitearchdir</tt>; | ||
+ | * '''lib/''' - pure-ruby модули, будут установлены в <tt>%ruby_sitelibdir</tt>; | ||
+ | * '''data/''' - произвольные данные(при использовании <tt>setup.rb</tt>), будут установлены в <tt>%_datadir/ИМЯМОДУЛЯ</tt>; | ||
+ | * '''test/''' - unit-тесты; | ||
- | + | Также как правило присутствует один или несколько "сценариев сборки", о них расскажу далее. | |
- | + | === Собираем модуль === | |
- | + | Существует несколько, различного уровня "стандартности", способов сборки модулей ruby. | |
- | + | ==== <tt>extconf.rb</tt> AKA MkMf ==== | |
- | + | Аналог configure, использует модуль <tt>mkmf</tt>, входящий в стандартную поставку ruby. Внутри скрипта проверяется наличие необходимых заголовочных файлов и библиотек, на выходе генерится Makefile, который обрабатывается стандартным make. Используется только в тех проектах, где есть бинарные модули. Если "рядом" с <tt>extconf.rb</tt> находится файл <tt>depend</tt>, его содержимое добавляется к <tt>Makefile</tt>. Исходные тексты и заголовочные файлы бинарного модуля как правило тоже лежат "рядом" с <tt>extconf.rb</tt>. | |
- | + | Типичные секции <tt>%build</tt> и <tt>%install</tt> выглядят следующим образом: | |
- | <pre> | + | <pre>%build |
+ | %ruby_configure <опции extconf.rb> | ||
+ | %make_build | ||
- | + | %install | |
- | + | %make_install DESTDIR=%buildroot install</pre> | |
- | + | ||
- | + | ==== <tt>setup.rb</tt> имени Minero Aoki ==== | |
- | + | ||
- | + | Скрипт сборки и установки общего назначения. Как правило используется для сборки и установки pure-ruby модулей. Имеет некоторое количество стандартных опций, может собирать бинарные модули, находящиеся в каталоге '''ext/''' (как правило там присутствует <tt>extconf.rb</tt>, см. выше). | |
- | + | ||
- | + | Типичные секции <tt>%build</tt> и <tt>%install</tt> выглядят следующим образом: | |
- | + | ||
- | + | <pre>%build | |
- | + | %ruby_config <опции setup.rb> | |
- | % | + | |
- | + | ||
- | % | + | |
- | + | ||
- | + | ||
- | % | + | |
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | / | + | |
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | '' | + | |
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | '' | + | |
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | + | ||
- | % | + | |
- | + | ||
- | % | + | |
- | + | ||
- | + | ||
- | %ruby_config | + | |
- | + | ||
- | + | ||
- | + | ||
- | + | ||
%ruby_build | %ruby_build | ||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
- | |||
+ | %install | ||
+ | %ruby_install</pre> | ||
+ | |||
+ | ==== <tt>install.rb</tt> ==== | ||
+ | |||
+ | Иногда это самописный скрипт, иногда встречается одна из первых версий <tt>setup.rb</tt>. Как правило используется только для установки pure-ruby модулей. Стандартных макросов для поддержки <tt>install.rb</tt> нет. | ||
+ | |||
+ | ==== <tt>Rakefile</tt> и остальные случаи ==== | ||
+ | |||
+ | Сценарий для <tt>rake</tt>. Обычно может иметь task'и <tt>build</tt> (если есть бинарные модули) и <tt>test</tt>, но последнее время не имеет task'а <tt>install</tt>. Зато использует <tt>rubygems</tt>. | ||
+ | |||
+ | Для вызова <tt>rake</tt> и <tt>rake install</tt> есть два стандартных макроса <tt>%rake</tt> и <tt>%rake_install</tt> соответственно. | ||
+ | |||
+ | Если task <tt>install</tt> не определён или вообще отсутствует установочный скрипт (в случае pure-ruby модуля), можно использовать <tt>setup.rb</tt> из пакета <tt>ruby-tool-setup</tt> примерно следующим образом: | ||
+ | |||
+ | <pre>%prep | ||
+ | %setup | ||
+ | %patch -p1 | ||
+ | cp %_datadir/ruby-setup/setup.rb .</pre> | ||
+ | |||
+ | Далее используются макросы <tt>%ruby_config</tt>, <tt>%ruby_build</tt> и <tt>%ruby_install</tt>. | ||
+ | |||
+ | === Пакуем документацию === | ||
+ | |||
+ | Документация в формате RI генерируется при помощи утилиты <tt>rdoc</tt>, находящейся в пакете <tt>ruby-tool-rdoc</tt>. Для этого существует стандартный макрос <tt>%rdoc</tt> предназначенный для использования в секции <tt>%install</tt> (обычно одной из последних строк). В качестве аргументов этого макроса перечисляются файлы и каталоги с исходниками и при необходимости другие опции утилиты <tt>rdoc</tt>. | ||
+ | |||
+ | Для pure-ruby модулей как правило используется конструкция: | ||
+ | |||
+ | <pre>%rdoc lib/</pre> | ||
+ | |||
+ | Если присутствуют бинарные модули: | ||
+ | |||
+ | <pre>%rdoc *.c lib/</pre> | ||
+ | |||
+ | Документацию желательно паковать в подпакет <tt>%name-doc</tt>. При этом паковать следует только документацию для основных классов модуля, описание расширений сторонних классов паковать не нужно. | ||
+ | |||
+ | === Складываем файлы в пакеты === | ||
+ | |||
+ | Pure-ruby модули помещаются в <tt>%ruby_sitelibdir</tt>, бинарные модули в <tt>%ruby_sitearchdir</tt>, документация в формате RI в <tt>%ruby_ri_sitedir</tt> (при этом файл <tt>%ruby_ri_sitedir/created.rid</tt> упаковывать не нужно). | ||
+ | |||
+ | === Добро пожаловать в реальный мир === | ||
+ | |||
+ | В теории всё выглядит красиво, однако на практике среднего размера модуль представляет собой "нечто", что может работать в любой помойке. Однако мы делаем не помойку, поэтому местечковые хаки нам не нужны. | ||
+ | |||
+ | ==== Не загрязняем <tt>$LOAD_PATH</tt> (<tt>$:</tt>) ==== | ||
- | + | Очень часто в коде можно увидеть конструкции вида: | |
- | + | <pre>$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')</pre> | |
- | + | Эта конструкция добавляет в <tt>$LOAD_PATH</tt> некоторый путь. Сделано это для того, чтобы модуль (или исполняемый скрипт) можно было использовать из любого места. Поскольку в нашем случае все файлы пакуются в стандартные места, подобные конструкции не нужны. В большинстве случаев такие конструкции можно безболезненно удалить. | |
- | + | ==== Используем существующие модули и размаскируем зависимости ==== | |
- | + | Поскольку наша помойка не является "любой", её ТТХ нам известны. Например, известно что это Linux, есть Iconv и так далее. Поэтому специфичный код, предназначенный для работы на других платформах в наших пакетах не нужен (а иногда бывает и вреден, поскольку даже "мёртвый" код может порождать зависимости, которые в некоторых случаях превращаются в unmet'ы). | |
- | + | Также мы можем превратить опциональную зависимость в явную. Пример: | |
- | + | <pre>begin | |
+ | require 'iconv' | ||
+ | rescue LoadError | ||
+ | module Iconv | ||
+ | # Далее следует некоторый код, который в результате предоставляет API | ||
+ | # похожий на API модуля iconv, возможно урезанный функционально. | ||
+ | end | ||
+ | end</pre> | ||
- | + | В данном случае '''всю''' эту сложную конструкцию можно заменить на одну строку <tt>require 'iconv'</tt>. Как бонус мы получаем зависимость на <tt>ruby(iconv)</tt> и полную функциональность данного модуля. | |
- | + | Реальные примеры можно посмотреть в пакете [http://git.altlinux.org/people/raorn/packages/?p=ruby-gettext.git ruby-gettext]. |
Версия 16:07, 28 июля 2008
Ruby
Основные правила сборки приложений и модулей ruby изложены в Ruby Packaging Policy. Цель же этого документа - об'яснить на простых примерах как следует поступать в различных ситуациях а также показать как можно собирать простые модули.
Я не рассматриваю rubygems, так как эта система включает в себя свой пакетный менеджер, не совместимый с дистрибутивным. Про отношение Debian к rubygems можно прочитать тут, рекомендации апстриму изложены тут. У нас ситуация в общем аналогичная.
Тут пока находится поток сознания, который я буду приводить к нормальному виду.
Содержание |
Общие принципы сборки модулей
Есть два способа сборки модулей. При помощи rubygems (который мы не рассматриваем по ряду причин), и "нативная" сборка, с помещением файлов в специальные каталоги, которые находятся в $LOAD_PATH.
Сборка пакета включает в себя:
- компиляцию бинарных модулей (если они есть);
- выполнение тестов (если они есть и их выполнение возможно в hasher);
- установку файлов в соответствующие каталоги;
- генерацию документации в формате ri (class reference);
Модули устанавливаются в так называемый vendor dir. В ALT Linux это /usr/share/ruby/vendor_ruby/RUBY.VERSION и /usr/lib/ruby/RUBY.VERSION/ARCHITECTURE. Поскольку по умолчанию установка модулей идёт в site dir, при сборке пакета надо использовать модуль vendor_specific, вызывая интерпретатор ruby как ruby -rvendor_specific. Для этого есть макрос %ruby.
Внутри тарбола
Внутри тарбола с модулем (или программой) могут находиться следующие файлы и каталоги:
- bin/ - скрипты, будут установлены в %_bindir;
- ext/ - компилируемые модули (при использовании setup.rb), будут установлены в %ruby_sitearchdir;
- lib/ - pure-ruby модули, будут установлены в %ruby_sitelibdir;
- data/ - произвольные данные(при использовании setup.rb), будут установлены в %_datadir/ИМЯМОДУЛЯ;
- test/ - unit-тесты;
Также как правило присутствует один или несколько "сценариев сборки", о них расскажу далее.
Собираем модуль
Существует несколько, различного уровня "стандартности", способов сборки модулей ruby.
extconf.rb AKA MkMf
Аналог configure, использует модуль mkmf, входящий в стандартную поставку ruby. Внутри скрипта проверяется наличие необходимых заголовочных файлов и библиотек, на выходе генерится Makefile, который обрабатывается стандартным make. Используется только в тех проектах, где есть бинарные модули. Если "рядом" с extconf.rb находится файл depend, его содержимое добавляется к Makefile. Исходные тексты и заголовочные файлы бинарного модуля как правило тоже лежат "рядом" с extconf.rb.
Типичные секции %build и %install выглядят следующим образом:
%build %ruby_configure <опции extconf.rb> %make_build %install %make_install DESTDIR=%buildroot install
setup.rb имени Minero Aoki
Скрипт сборки и установки общего назначения. Как правило используется для сборки и установки pure-ruby модулей. Имеет некоторое количество стандартных опций, может собирать бинарные модули, находящиеся в каталоге ext/ (как правило там присутствует extconf.rb, см. выше).
Типичные секции %build и %install выглядят следующим образом:
%build %ruby_config <опции setup.rb> %ruby_build %install %ruby_install
install.rb
Иногда это самописный скрипт, иногда встречается одна из первых версий setup.rb. Как правило используется только для установки pure-ruby модулей. Стандартных макросов для поддержки install.rb нет.
Rakefile и остальные случаи
Сценарий для rake. Обычно может иметь task'и build (если есть бинарные модули) и test, но последнее время не имеет task'а install. Зато использует rubygems.
Для вызова rake и rake install есть два стандартных макроса %rake и %rake_install соответственно.
Если task install не определён или вообще отсутствует установочный скрипт (в случае pure-ruby модуля), можно использовать setup.rb из пакета ruby-tool-setup примерно следующим образом:
%prep %setup %patch -p1 cp %_datadir/ruby-setup/setup.rb .
Далее используются макросы %ruby_config, %ruby_build и %ruby_install.
Пакуем документацию
Документация в формате RI генерируется при помощи утилиты rdoc, находящейся в пакете ruby-tool-rdoc. Для этого существует стандартный макрос %rdoc предназначенный для использования в секции %install (обычно одной из последних строк). В качестве аргументов этого макроса перечисляются файлы и каталоги с исходниками и при необходимости другие опции утилиты rdoc.
Для pure-ruby модулей как правило используется конструкция:
%rdoc lib/
Если присутствуют бинарные модули:
%rdoc *.c lib/
Документацию желательно паковать в подпакет %name-doc. При этом паковать следует только документацию для основных классов модуля, описание расширений сторонних классов паковать не нужно.
Складываем файлы в пакеты
Pure-ruby модули помещаются в %ruby_sitelibdir, бинарные модули в %ruby_sitearchdir, документация в формате RI в %ruby_ri_sitedir (при этом файл %ruby_ri_sitedir/created.rid упаковывать не нужно).
Добро пожаловать в реальный мир
В теории всё выглядит красиво, однако на практике среднего размера модуль представляет собой "нечто", что может работать в любой помойке. Однако мы делаем не помойку, поэтому местечковые хаки нам не нужны.
Не загрязняем $LOAD_PATH ($:)
Очень часто в коде можно увидеть конструкции вида:
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
Эта конструкция добавляет в $LOAD_PATH некоторый путь. Сделано это для того, чтобы модуль (или исполняемый скрипт) можно было использовать из любого места. Поскольку в нашем случае все файлы пакуются в стандартные места, подобные конструкции не нужны. В большинстве случаев такие конструкции можно безболезненно удалить.
Используем существующие модули и размаскируем зависимости
Поскольку наша помойка не является "любой", её ТТХ нам известны. Например, известно что это Linux, есть Iconv и так далее. Поэтому специфичный код, предназначенный для работы на других платформах в наших пакетах не нужен (а иногда бывает и вреден, поскольку даже "мёртвый" код может порождать зависимости, которые в некоторых случаях превращаются в unmet'ы).
Также мы можем превратить опциональную зависимость в явную. Пример:
begin require 'iconv' rescue LoadError module Iconv # Далее следует некоторый код, который в результате предоставляет API # похожий на API модуля iconv, возможно урезанный функционально. end end
В данном случае всю эту сложную конструкцию можно заменить на одну строку require 'iconv'. Как бонус мы получаем зависимость на ruby(iconv) и полную функциональность данного модуля.
Реальные примеры можно посмотреть в пакете ruby-gettext.