Debianパッケージ構築のメモ

Debianパッケージはぱっとみ概念とかがわかりにくいので、色々省きつつ大雑把にとりあえず作ったりする上で必要な情報を説明してみる試み。

簡単なdebはとりあえず作ったりできるようになってみて、個人的にはこういう情報がまとまってると楽だったなーということをメモっておく。

自分自身あまり構築したパッケージの運用が長くはないので、ひょっとしたらシステムの依存関係を壊したり、あるいは正しくはない部分もあったりするかと思いますが、そういった部分があれば指摘してもらえれば勉強になります。

debパッケージ

  • バイナリパッケージ (*.deb, *.udeb)
    • いわゆるdebパッケージ
  • ソースパッケージ(*.dscとアーカイブ)
    • バイナリパッケージを作れる状態にしたもの。

環境が変わったり、ソフトウェアバージョンを上げるときにソースパッケージがあった方が作り直しが楽なのでなるべくとっておきませう。

debianパッケージの構成

はじめに、

$ tar xvzf git-1.6.3.tar.gz
$ cd git-1.6.3
$ dh_make --cdbs -f ../git-1.6.3.tar.gz --email=walf443+nospam@gmail.com

するとこんな感じになる。

  • /
    • /debian/
        • ./rules: パッケージの構築手順を示したMakefile
        • ./control: パッケージのメタ情報
        • ./changelog: dchでいじる。
        • ./preisnt
        • ./postinst
        • ./prerm
        • ./postrm
        • ./init.d
        • ./$(package)-default
        • ./cron.d
        • ./compat: debhelperの互換性を保証する最低バージョン

パッケージの構築の仕方

パッケージ構築に必要なものは、devscripts、debhelperパケージを入れればだいたいは入るはず。

ソースパッケージから作る場合は次のようにする。

$ dpkg-source -x ruby-head_1.9.1-p129-1.dsc
$ cd ruby-head-1.9.1-p129
$ debuild -uc -us

上記のdh_makeしただけの状態から作るなら、debuild -uc -usだけでOK。

debuildの-uc -usは署名を飛ばすオプション。署名も含めて構築する場合、署名が失敗しただけで全部作りなおしになったりするので、つけた方がよい。署名自体はあとからでもやるコマンドがある。

debuildは、色々やってくれるので、構築を最小限にするのであれば、dpkg-buildpackage -rfakerootとかでもよい。

構築したパッケージの確認

debに入ってるファイル一覧を見る

$ dpkg --contents *.deb

debのメタ情報を確認する

$ dpkg --info *.deb

あとはインストールしてみたり削除してみたり動かしてみたり。

debian/control

Source: git
Section: unknown
Priority: extra
Maintainer: Yoshimi <walf443+nospam@gmail.com>
Build-Depends: cdbs, cdbs, debhelper (>= 5), autotools-dev
Standards-Version: 3.7.2

Package: git
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: <insert up to 60 chars description>
 <insert long description, indented with spaces>

Source, Packageは、パッケージ名なので、debianに既にあって別の名前にしておきたいときはいじっておく。

重要なのは、Build-Dependsで、なるべくここに構築に必要なパッケージ名を書くようにする。

DependsはCのパッケージの場合はたいてい共有ライブラリからうまく特定されて勝手に入るのであまりいじらなくてもよいこともある。

手元で作ってみたgitのパッケージの場合なら例えばこんな感じ。

Source: git-head
Section: unknown
Priority: extra
Maintainer: Keiji Yoshimi <walf443+nospam@gmail.com>
Build-Depends: cdbs, cdbs, debhelper (>= 5), autotools-dev, zlib1g-dev, libcurl3-openssl-dev, xmlto, libexpat1-dev, autoconf, libsvn-perl | libsvn-core-perl, libwww-perl
Standards-Version: 3.7.2

Package: git-head
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, libsvn-perl | libsvn-core-perl, libwww-perl
Description: git HEAD deb package. installed in /usr/local/. and include git-svn.

debian/rules

debhelper

一番標準的な書き方。Makefileの全部の手順を書く(基本的には自動生成)

全部1つのファイルに書いてあるので、Makefileを読むのか得意であれば少しいじるのは楽かも。

CDBSスタイル

ナウいスタイル。死語を使っているようにあまり新しくない。

余計なことを書いてないのでシンプルに書ける。

余程変なことをしない限りはすっきり書けるはず。

ターゲットは、:ではなく::で定義する。
同じフックポイントに複数回設定できる。

ルール

パッケージ構築のフックポイントを定義する。
基本的には、debhelperを使っておけばOK。

よく使いそうなフックポイント抜粋

  • clean::
  • configure/$(package)::
  • build/$(package)::
  • install/$(package)::
クラス

ルールで定義されたフックポイントを使ったデフォルトのアクションを定義する。

よく使いそうなクラス抜粋

  • makefile.mk: make && make installですむもの。
  • autotools.mk : ./configure && make && make installですむもの
  • perlmodule.mk: perl Makefile.PL && make && make installですむもの。
実例
rubyの場合

前提

  • gorubyも入れたい
  • ruby1.9とかとコンフリクトして嫌なことになりたくないので、/usr/local/以下に入れる
  • 最初からついている./configureはmake cleanで消えてしまうので毎回作りなおす。
  • O2でコンパイルするとparse.cが死ぬ程時間がかかるらしいため、O3でビルドする。
#!/usr/bin/make -f

include /usr/share/cdbs/1/rules/debhelper.mk
include /usr/share/cdbs/1/class/autotools.mk

build/ruby-head::
  $(MAKE) && $(MAKE) golf

# Add here any variable or target overrides you need.
DEB_AUTO_UPDATE_AUTOCONF = YES # autoconfで./configureを作り直す
DEB_CONFIGURE_SCRIPT_ENV = optflags="-O3 -pipe" # ./configureを実行する際の環境変数
DEB_CONFIGURE_USER_FLAGS = --prefix=/usr/local/ # ./configureに渡すオプション

どの環境変数を指定すれば、どのあたりに効いくかはinclude先のMakefileをがんばって解読するのがてっとり早いと思います。(慣れれば)

ファイルを入れるだけのdeb

イントラ内のaptの設定を共通にしておくとかいうケース

#!/usr/bin/make -f

include /usr/share/cdbs/1/rules/debhelper.mk
# include /usr/share/cdbs/1/class/makefile.mk

APT_CONF_DIR = $(CURDIR)/debian/my-apt-intra/etc/apt/sources.list.d/

install/mf-apt-intra::
  install -m 644 -d $(APT_CONF_DIR)
  install -m 644 $(CURDIR)/debian/my-apt-intra.conf $(APT_CONF_DIR)/my-apt-intra

# Add here any variable or target overrides you need.

preinst/postrmのフックで、/etc/apt/souces.listをこのパッケージが入っている間は別ファイルに退避させておく。(ほんとはdiversionという方法があるらしいんですがまだいまいちうまく理解できてない)

debian/preinst

#!/bin/sh
# preinst script for my-apt-intra
#
# see: dh_installdeb(1)

set -e

APT_CONF_DEFAULT=/etc/apt/sources.list

case "$1" in
    install|upgrade)
      if [ -e $APT_CONF_DEFAULT ]
      then
        mv $APT_CONF_DEFAULT $APT_CONF_DEFAULT.bak
      fi
    ;;

    abort-upgrade)
    ;;

    *)
        echo "preinst called with unknown argument \`$1'" >&2
        exit 1
    ;;
esac
# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.

#DEBHELPER#

exit 0

|sh|<

debian/postrm
>|sh|
#!/bin/sh
# postrm script for my-apt-intra
#
# see: dh_installdeb(1)

set -e

APT_CONF_DEFAULT=/etc/apt/sources.list

case "$1" in
    purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
      if [ -e $APT_CONF_DEFAULT.bak ]
      then
        mv $APT_CONF_DEFAULT.bak $APT_CONF_DEFAULT
      fi
    ;;

    *)
        echo "postrm called with unknown argument \`$1'" >&2
        exit 1
    ;;
esac

# dh_installdeb will replace this with shell code automatically
# generated by other debhelper scripts.

#DEBHELPER#

exit 0
動的にファイルを作る例

メンテナスクリプト万能説

case "$1" in
    install|upgrade)
      # 自身のIPを調べる。あまりよくなさそうな方法な気はする。
      IP=`cat /etc/network/interfaces | grep address | grep 192.168 | cut -d ' ' -f2`
      echo $IP

      mv /etc/default/snmpd  /etc/default/snmpd.default
      cat <<END_CONF > /etc/default/snmpd
# This file controls the activity of snmpd and snmptrapd

# MIB directories.  /usr/share/snmp/mibs is the default, but
# including it here avoids some strange problems.
export MIBDIRS=/usr/share/snmp/mibs

# snmpd control (yes means start daemon).
SNMPDRUN=yes

# snmpd options (use syslog, close stdin/out/err).
SNMPDOPTS='-Lsd -Lf /dev/null -u snmp -I -smux -p /var/run/snmpd.pid $IP'

# snmptrapd control (yes means start daemon).  As of net-snmp version
# 5.0, master agentx support must be enabled in snmpd before snmptrapd
# can be run.  See snmpd.conf(5) for how to do this.
TRAPDRUN=no

# snmptrapd options (use syslog).
TRAPDOPTS='-Lsd -p /var/run/snmptrapd.pid'
END_CONF

    ;;

    abort-upgrade)
    ;;

    *)
        echo "preinst called with unknown argument \`$1'" >&2
        exit 1
    ;;
esac

パッケージを作る上で注意すること

別名のパッケージで同じファイルパスにインストールするものを作らない

作る場合は仮想パッケージするなどの処置をしてないと簡単にパッケージの関係が壊れるので注意。

とりあえずは./conifureで--prefix=/usr/localしておけば十分なケースが多い気もしつつ、あまり良くないという噂も効くので、まだ様子見。

パッケージ名はOSのバージョンアップも考慮に入れる。

OSをバージョンアップしたときに、Debianが公式で提供するものがあればそちらを使うようにしたい場合は、なるべくdebの命名規則にあわせる。例えば、DBIx::Class -> libdbix-class-perl

逆に、常に独自パッケージを使うようにしておきたいものの場合は、my-みたいなプレフィックスをつけるようにする。(パスも公式と被らないように注意)

特に今debになってないものでも将来debに入ることがあるので、そのとき苦労しないような名前にしておくのがよさそう。(ex. tokyotyrant)

参考

CDBSについて見て回ったサイトの中では大雑把に理解するには一番役に立った