GroongaのDebianパッケージについてお勉強中の児玉です。
Groongaでは、Debian向けのパッケージを作成し、そのメンテナンスを行っています。 その中で、「GroongaのDebianパッケージはどのようにビルドされているのだろう?」と気になったので、少し深掘りしてみました。 今回は、Debianパッケージの全体的なビルドフローの詳細には触れず、GroongaのDebianパッケージをメンテナンスする過程で学んだこと、 そして理解しておくべき重要なポイントに絞って紹介します。
より詳しい情報を知りたい方は、Groongaのdebian/を眺めてみる会をぜひご覧ください。 Debian Developerである林さんが詳細に解説しており、非常に参考になります。 この記事内でも関連する動画へのリンクを随時ご紹介しますので併せてご活用ください。
全体のビルドフロー
Debianパッケージのビルドは、debuildコマンドが全部やってくれます。
debuildは、Debianパッケージ(.debバイナリパッケージ)をビルドするためのコマンドです。 このコマンド1つで、依存関係の確認、ビルドの実行、パッケージの生成からlintianによるパッケージのチェックまでやってくれます。 これにより、開発者は複数のコマンドを手作業で実行する必要がなく、簡単にパッケージをビルドできます。
それでは、debuildを利用したDebianパッケージのビルドフローを見ていきましょう。各ステップごとに紹介します。
- 依存関係の確認
- ビルドプロセスの実行
- パッケージ用のファイル選定
- パッケージの生成
- パッケージのチェック
依存関係の確認
ビルドの最初に行われるのが依存関係の確認です。debian/control
ファイルに記載されている依存パッケージがインストールされているかをチェックします。(Groongaではdebian/control.in
からdebian/control
を生成しています。)
実際に、Groongaのdebian/control
ファイルを見てみましょう。
Source: groonga
Section: database
Priority: optional
Maintainer: Groonga Project <packages@groonga.org>
Uploaders: HAYASHI Kentaro <hayashi@clear-code.com>
Build-Depends:
cmake,
debhelper (>= 12),
...
rapidjson-dev,
zlib1g-dev
Standards-Version: 3.9.8
Homepage: https://groonga.org/
...
ここで重要なのは、Build-Depends
になります。ここで定義された依存パッケージは、debuildを実行した際にチェックされます。
依存関係にあるパッケージがすべてインストールされているかを確認し、1つでも不足している場合はエラーとなります。
debian/control
に関して、メンテナンスを通じて学んだこと
学んだことは大きく2つあります。
1つ目は、新しいバージョンのDebianでパッケージをビルドする際には、debian/control
ファイルの依存パッケージを確認し、
必要なパッケージが揃っていることを確認する必要があるという点です。依存パッケージが不足していると、ビルド前の依存関係チェックで失敗し、エラーとなってしまいます。
2つ目は、新しいパッケージが必要になったり、依存ライブラリのバージョンが変更された場合には、必ずdebian/control
ファイルを更新する必要があるという点です。古い依存関係のままだと、正確に依存関係のチェックが行われず、ビルドステップでエラーが発生する可能性があります。
依存関係のチェックが問題なく完了した後は、パッケージのビルドステップに移ります。 実際にビルドプロセスがどのように実行されているのか見ていきましょう。
debian/control
ファイルについて、もっと知りたい方はこちらのGroongaのdebian/を眺めてみる会 (第2回)debian/control編を参照してください!
ビルドプロセスの実行
依存関係の確認が完了すると、ビルドが開始されます。ビルドプロセスは、debian/rules
ファイルで定義されています。
debian/rules
ファイルは、パッケージの「ビルドレシピ」として機能し、どのようなビルドツールを使って、どのオプションでビルドするかが記述されています。
Groongaのdebian/rules
ファイルを見てみましょう。
#!/usr/bin/make -f
# ...
%:
dh $@
override_dh_auto_configure:
if dpkg -l libarrow-dev > /dev/null 2>&1; then \
GRN_WITH_APACHE_ARROW=ON; \
else \
GRN_WITH_APACHE_ARROW=OFF; \
fi; \
if [ "$$(lsb_release -cs)" = "focal" ]; then \
GRN_WITH_SIMDJSON=no; \
else \
GRN_WITH_SIMDJSON=auto; \
fi; \
dh_auto_configure \
--buildsystem=cmake+ninja \
-- \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DFETCHCONTENT_FULLY_DISCONNECTED=OFF \
-DGRN_WITH_APACHE_ARROW=$${GRN_WITH_APACHE_ARROW} \
-DGRN_WITH_BLOSC=bundled \
-DGRN_WITH_DOC=ON \
-DGRN_WITH_EXAMPLES=ON \
-DGRN_WITH_MRUBY=ON \
-DGRN_WITH_MUNIN_PLUGINS=ON \
-DGRN_WITH_SIMDJSON=$${GRN_WITH_SIMDJSON}
# ...
ここで重要なのは、Debianのビルドヘルパー(debhelper)によって提供されるdh_auto_configure
と、ユーザーが定義するoverride_dh_auto_configure
になります。それぞれ紹介します。
debhelper とは?
debhelperは、Debianパッケージのビルド手順を自動化・簡略化するためのツール群です。主にdebian/rules
ファイル内で使用され、パッケージのビルドプロセスを効率的に管理します。debhelperを使用することで、複雑なビルド手順を簡潔に記述でき、メンテナンスが容易になります。
dh_
プレフィックスは、debhelperの略称であり、debhelperツールセットの一部であることを示しています。
たとえば、ここで利用しているdh_auto_configure
コマンドもプレフィックスからdebhelperによって提供されていることが分かります。
dh_auto_configure
とoverride_dh_auto_configure
とは?
dh_auto_configure
は、Debianのビルドヘルパー(debhelper)が提供する標準的なコマンドで、ソースコードをビルドする前の設定(コンフィグレーション)を行います。
Groongaでは、--buildsystem
オプションを使用することで、ビルド時にCMake
とNinja
を利用するように指定しています。さらに、いくつかビルドオプションも指定しています。
一方、override_dh_auto_configure
は、debhelperが提供するオーバーライド機能を利用したものになります。debhelper自体がoverride_dh_auto_configure
を提供しているわけではなく、ユーザーがoverride_dh_auto_configure
ターゲットを定義することで、デフォルトのdh_auto_configure
ステップを置き換えることができます。この仕組みにより、ユーザーは特定のビルドオプションや設定をカスタマイズすることが可能になります。
Groongaでは、override_dh_auto_configure
を利用して、環境ごとのビルドフラグを管理しています。
たとえば、Apache Arrowがインストールされている場合はGRN_WITH_APACHE_ARROW
がON
に設定され、ビルドオプションに反映されます。また、Ubuntu FocalではGRN_WITH_SIMDJSON
がno
に設定されるなど、ビルド環境によってフラグが自動的に調整される仕組みを定義しています。
debian/rules
に関して、メンテナンスを通じて学んだこと
学んだことは大きく2つあります。
1つ目は、パッケージのビルドに失敗した際、オプションが正しく渡されているかは、debian/rules
ファイルで確認できるという点です。
debian/rules
ファイルに記載されているoverride_dh_auto_configure
の設定を見れば、ビルドオプションの設定に問題がないか確認できます。
2つ目は、特定のDebianバージョンやライブラリバージョンに合わせてビルドオプションを変更する必要がある場合、override_dh_auto_configure
で柔軟に制御できるという点です。
たとえば、Ubuntu FocalではGRN_WITH_SIMDJSON
をno
に設定するなど、バージョンに応じたカスタマイズが可能です。
ビルドプロセスが問題なく完了したあとは、ビルドの成果物からどのファイルをパッケージングの対象にするかを選定します。 実際にどのようにファイルの選定が行われていくのか見ていきます。
パッケージ用のファイル選定
ビルド完了後、ビルドの成果物からどのパッケージにどのファイルを含めるのか選定する作業を行います。
debian/*.install
ファイルでは、どのファイルをどのパッケージに含めるかが定義されています。
ビルド完了後、ビルドの成果物からどのパッケージにどのファイルを含めるのか選定する作業を行います。
このプロセスは、パッケージの機能や役割に応じて適切なファイルを分類・配置するために不可欠です。
debian/*.install
ファイルでは、各パッケージに含めるべきファイルのパスを定義しています。
これにより、パッケージの内容が明確になり、メンテナンス性が向上します。
実際に、Groongaのdebian/libgroonga0.install
ファイルを見てみましょう!
$ cat packages/debian/libgroonga0.install
usr/lib/*/libgroonga*.so.*
usr/lib/*/groonga/plugins/functions/index_column.*
usr/lib/*/groonga/plugins/functions/math.*
usr/lib/*/groonga/plugins/functions/number.*
usr/lib/*/groonga/plugins/functions/string.*
usr/lib/*/groonga/plugins/functions/time.*
usr/lib/*/groonga/plugins/functions/vector.*
usr/lib/*/groonga/plugins/query_expanders/*
usr/lib/*/groonga/plugins/token_filters/stop_word*
usr/lib/*/groonga/plugins/ruby/*
usr/lib/*/groonga/plugins/sharding.rb
usr/lib/*/groonga/plugins/sharding/*
usr/lib/*/groonga/scripts/*
etc/groonga/synonyms.tsv
このファイルは、libgroonga0
パッケージに含まれるべきファイルを具体的に列挙しています。
たとえば、usr/lib/*/groonga/plugins/functions/math.*
という記述から、math.
で始まるプラグインファイルすべてを対象としているのが分かります。
*.install
ファイルに関して、メンテナンスを通じて学んだこと
メンテナンスを通じて学んだことは、パッケージング時に追加または削除するファイルがある場合、この定義ファイルを編集するだけで、ファイルの管理を柔軟に行えるという点です。
新しいプラグインやスクリプトを追加する場合は、該当する*.install
ファイルに追加すれば、次回のビルドでそのファイルが適切なパッケージに含まれます。
不要なファイルを除外する場合も同様に、*.install
ファイルから削除するだけで簡単に反映されます。
パッケージ用のファイル選定が完了したら、実際にDebianパッケージとしてパッケージングを行います。 実際にどのようにパッケージングしていくのか見ていきましょう。
debian/*.install
ファイルについて、もっと知りたい方はこちらのGroongaのdebian/を眺めてみる会 (第5回)を参照してください!
パッケージの生成
パッケージに含めるファイルの選定が完了した後は、実際にDebianパッケージを生成します。
このプロセスもdebian/rules
ファイル内のdh
コマンドを介して行われます。
Groongaのdebian/rules
ファイルを見ていきましょう。
# ...
%:
dh $@
# ...
ここで重要なのは、%
というターゲットと、それに続くdh $@
の定義です。
%
はMakefileにおける「ワイルドカードターゲット」であり、指定されたターゲットが他に定義されていない場合にこのルールが適用されます。
つまり、特定のターゲット(例: build, clean, installなど)が指定されなかった場合、%
ターゲットがデフォルトでマッチし、dh $@
が実行されます。
Groongaでは、dh_auto_configure
で明示的に指定されているコンフィグレーションステップ以外のビルド、インストール、パッケージ化などの一連の処理がdebhelperのdh
コマンドを通じて実行されます。そのため、パッケージの生成もdh
コマンドを介して実行します。
今回は、パッケージ化の流れに注力して見ていきます。次の流れでパッケージが生成されます。
- メタデータの収集
- ファイルのアーカイブ
- アーカイブをまとめる
メタデータの収集
debian/control
ファイルやその他のメタ情報を基に、パッケージに必要な情報を収集し、control.tar.gz
というアーカイブにまとめます。
このアーカイブにはパッケージ名やバージョン、依存関係などが含まれます。
ファイルのアーカイブ
debian/*.install
ファイルで選定されたファイルが、data.tar.gz
というアーカイブにまとめられます。
このアーカイブには実際にインストールされるバイナリやライブラリ、設定ファイルなどが含まれます。
アーカイブをまとめる
上の過程でアーカイブとして作成したcontrol.tar.*
とdata.tar.*
を含むすべてのファイルをDebianパッケージ(.deb形式)としてアーカイブします。
メンテナンスを通じて学んだこと
メンテナンスを通じて学んだことは、パッケージングが正常に完了したかどうかを確認するためには、Debianパッケージを展開することで確認できるという点です。
実際に展開してみることで、パッケージに含まれるファイルやメタ情報が正しく設定されているかを確認できます。
たとえば、control.tar.*
を展開すれば、依存関係やパッケージの設定が正しいか確認できます。
また、data.tar.*
を展開すれば、インストールされるファイルの一覧を確認できます。
パッケージの生成が完了したら、次は生成したパッケージがDebianのポリシーに則っているかをチェックします。 実際にどのようにチェックしているのか見ていきましょう。
パッケージのチェック
生成されたパッケージがDebianのポリシーに則っているかチェックするには、lintianというツールを使用します。 lintianは、パッケージがDebianの品質基準に沿っているかをチェックし、基準に沿っていない場合には警告やエラーを報告します。 パッケージ内のメタデータやファイル構成、ライセンス、依存関係の管理など、さまざまな項目がチェック対象となります。
メンテナンスを通じて学んだこと
パッケージメンテナンスの過程で気づいたのは、lintianのチェックは単なる形式的な確認ではなく、実際の問題を未然に防ぐための重要な手段であるという点です。 たとえば、パッケージ内に不要なファイルが含まれていたり、必要なファイルが含まれていなかったりする場合、lintianのチェックを通じてこうした問題を発見できます。
まとめ
今回の記事では、GroongaのDebianパッケージをメンテナンスする過程で学んだことを中心に、ビルドプロセスの流れやdebian/
ディレクトリ内の重要なファイルについて紹介しました。
これにより、Debianパッケージのメンテナンス作業において注目すべきポイントを押さえ、実際のメンテナンス作業に役立つ視点を提供できていたら幸いです。
もし、Debianパッケージの作成や運用でお困りの方がいらっしゃいましたら、 こちらのお問い合わせよりぜひご連絡ください。