序文
前回の記事では、フォントのパッケージ定義を通じて、パッケージ定義の流れを解説しました。この記事では一歩進んで、ビルドを伴うパッケージの定義を行っていきます。
実はGNU Guixはその思想上、この「ビルド」というプロセスをきちんと行うことを大切にしています。 前回の記事で、ハッシュ値を確認することで偽物を掴まされていないことを確認するプロセスがあることを説明したと思いますが、その一方で配信元がウイルスやマルウェアなどの悪意のあるコードを仕込んでいる場合は感知することはできません。これを防ぐための究極の方法は、ソースコードから直接ビルドすることです。公開されているソースコードからビルドすれば、ソースコードを確認することで悪意のあるコードが混入していないかを確認することができます。一方公開されているバイナリを直接インストールする方法の場合、悪意のあるコードが混入していることを確認する術はありません。元のソースコードが公開されていても、そのバイナリがそのソースコードからビルドされたことを確かめられないので無意味です。
このような理由で、GNU Guixはあらゆるパッケージを自分の手元でビルドすることを信条としています。もちろんサイズが大きいパッケージをたくさん使うような場合、全てビルドするのは大変な場合もあります。そのため、「このサーバーのビルドしたパッケージは信用できるので、ビルドする代わりにバイナリからインストールする」というのを実現する機能があります。この機能はSubstitutesと呼ばれています。デフォルトではGNUのサーバーだけが登録されています。詳しくは公式マニュアルをご覧ください。また、この機能はあくまでも「ビルド手順をパッケージ定義として示した上で、その手順と全く同一の手順を踏んでいるであろうバイナリを提供するサーバーを信用する」という機能であることに注意してください。ビルド手順の記述を省略するようなことはできません。そのへんに落ちているバイナリから直接インストールする機能は次回の記事で説明します。
前提
GNU Guix自体はインストールされていて、使えるようになっていることを前提とします。また、前回の記事の設定が残っていることが前提となっています。ただし、試すだけなら必ずしもGitレポジトリを使う必要はなく、 -L /path/to/channel
オプションを毎回使ってもよいです。大抵のサブコマンドには対応しています。
パッケージを定義する
今回は、agというバイナリのパッケージを作成していきます。 agは高速なgrepとして開発されたCLIツールで、パッケージはGNU Guixの公式チャンネルに含まれています。そこから引用されたコードはGPLv3 or laterによってライセンスされていることに留意してください。
前回はパッケージ定義の概要を説明するためにパッケージ定義を先に示しましたが、今回はパッケージを作るときの流れを実際に体験してもらうため、先に最終形を示すことはしません。
モジュール
まずは前回同様、モジュールを定義していきます。チャンネルの下の your-channel-name/packages/ag.scm
に以下を書きましょう。
(define-module (your-channel-name packages ag)
#:use-module (guix packages)
#:use-module ((guix licenses) #:prefix license:)
#:use-module (guix download))
この3つのモジュールはほぼ必ず #:use-module
することになるため、これを雛形としてもよいと思います。前回と異なるのは一行目の (your-channel-name packages ag)
のファイル名にあたる最後の ag
の部分くらいです。あと、今回はフォントではないので (gnu build-system font)
を #:use-module
しないようにしました。
パッケージ定義
次にパッケージ定義を書いていきます。今回は本家との名前の衝突を避けるために my-ag
という名前にしましょう。ビルドのしかたはagのREADMEに書いてあります。それによると、ここにあるtarballからビルドする場合は以下のようなコマンドでインストールできるらしいです。ソースコードは “https://geoff.greer.fm/ag/releases/the_silver_searcher-2,2,0.tar.gz” にあるようです(リンク先のリンクにあります)。
./configure
make
make install
このようなビルドの手順はLinuxにおいて非常によく使われる典型的なものです。まずはこの典型的なビルドをできるようになって欲しいため、このパッケージを題材にしました。
この情報を元に、パッケージ定義を書いてみます。
(define-public my-ag
(package
(name "my-ag")
(version "2.2.0")
(source (origin
(method url-fetch)
(uri (string-append
"https://geoff.greer.fm/ag/releases/the_silver_searcher-"
version ".tar.gz"))
(sha256
(base32
"0w1icjqd8hd45rn1y6nbfznk1a6ip54whwbfbhxp7ws2hn3ilqnr"))))
(build-system gnu-build-system)
(home-page "https://geoff.greer.fm/ag/")
(synopsis "Fast code searching tool")
(description
"The Silver Searcher (@command{ag}) is a tool for quickly searching large
numbers of files. It's intended primarily for source code repositories, and
respects files like @file{.gitignore} and @file{.hgignore}. It's also an order
of magnitude faster than its inspiration, @command{ack}, and less specialised
tools such as @command{grep}.")
(license license:asl2.0)))
上記のフィールドのほとんどは前回の記事と全く同様のため、詳細は省きますが、 my-ag
という名前のパッケージを定義しています。基本的に上記に示したフィールドは全て必須であるため、これをテンプレートとして穴埋めすることでパッケージを作るのが手っ取り早いです。
ビルドシステム
さて、今書いた中で最も大事なフィールドは (build-system gnu-build-system)
です。この変数の定義は (guix build-system gnu)
というモジュールにあるので、このモジュールを #:use-module
しておいてください。
(define-module (your-channel-name packages ag)
#:use-module (guix packages)
#:use-module ((guix licenses) #:prefix license:)
#:use-module (guix download)
#:use-module (guix build-system gnu))
先程のフィールドでは、 build-system
を gnu-build-system
と指定しています。この gnu-build-system
は、実は正に ./configure && make && make install
の典型的なビルド手順を表しています
(詳細な仕様が知りたい方は公式マニュアル(英語)を参照)。
ただし、 ./configure && make && make install
をそのまま走らせているわけではないということに注意してください。
GNU Guixはその特性上 /bin/
や /lib/
の代わりに /gnu/store/xxxxxxxxxxxxxxxxx-my-ag-2.2.0/bin/
や
/gnu/store/xxxxxxxxxxxxxxxxx-my-ag-2.2.0/lib/
に生成物をインストールする必要があります。そのため、 ./configure
にインストール先の接頭辞を指定する --prefix
を付ける、などを行っています。具体的な実装を見たい場合は、
GNU Guix公式レポジトリのguix/build/gnu-build-system.scmかguix/build-system/gnu.scmをご覧ください。
#:use-module
したのは前者ですが、ビルド手順自体は主に後者に実装されています。
ビルドは具体的にどのような手順で行われるのでしょうか。これも公式マニュアル(英語)に記載されています。
gnu-build-system
では以下のような手順で行われます。これらの各手順はフェイズ(phase)と呼ばれています。なお、他のビルドシステムも大抵は gnu-build-system
を継承して作られているため、似たような流れになります。また、ソースのダウンロード自体はビルドシステムが走るよりも前に行われており、ビルドシステムが走る環境は外のネットワークには一切繋がりません。これはソースのハッシュ値が等しいことと成果物が等しいことを等価にするのに必要です
(ネットワークに繋がってしまうと、ソースコードが同じでもネットワーク経由の入力によって成果物が変わり得る)。
set-paths
- ソースのダウンロードやビルドのための環境を用意するフェイズです。各種依存へパスを通したりします。
unpack
source
に指定したソースコードのtarballやzipを展開し、ビルド用の環境へとコピーします。patch-source-shebangs
- シェルスクリプトのshebangを変更します。
GNU GuixはFHSに従ったディレクトリ構造をしておらず、
bash
やsh
をも/gnu/store/
以下に閉じ込めているため、その位置をシェルスクリプトに伝えるべく#!/bin/sh
や#!/bin/bash
を#!/gnu/store/xxxxxxxxxxxxx-bash-0.0/bin/sh
や#!/gnu/store/xxxxxxxxxxxxx-bash-0.0/bin/bash
に置き換えます。 configure
./configure
を実行します。先程述べたように、--prefix
引数によってインストール先が変更されます。また、後述の#:confiugre-flags
引数によって追加のオプションを指定できます。build
make
を実行します。他のビルドシステムの場合でも、このフェイズで実際のビルドが走ることが多いです。なお、前述のとおり、ここではネットワークには一切繋がりません。そのため、外からダウンロードしてくる操作がビルドスクリプトに含まれていると失敗します。その場合、外からダウンロードしてくる操作自体をビルドスクリプトから取り除くか実行されないようにして、ダウンロードされてくる部分を別のパッケージとして定義し、それを依存としたパッケージを定義する必要があります。この作業はかなり大変です。後述の#:phases
引数を使ってこのフェイズ自体を一から書き直したり、substitute
マクロ(前述のバイナリ提供サーバーとしてのsubstituteとは無関係。#:phases
の詳細説明を参照) を使ってビルドスクリプトを修正するフェイズをビルド前に追加したりすることで対応することになります。ここはどうしてもアドホックになりがちなところです。check
make check
を実行します。後述の#:tests?
引数によって抑制できます。install
make install
を実行します。./configure
に渡された--prefix
オプションにより、/gnu/store/
直下にある専用のインストール先にインストールされます。patch-shebangs
patch-source-shebangs
とほとんど同じです。今回はソースコードではなくインストールされた実行ファイルに適用されます。strip
- 生成されたバイナリからデバッグ情報を取り除きます。なにをしているのかをあまり気にすることはないのですが、このフェイズでたまにコケるので、その場合は後述の
#:strip-binaries?
引数を#f
とするとよいです。 validate-runpath
- 生成されたバイナリの
RUNPATH
を確認し、依存するライブラリがきちんと存在するかどうかを検証します。このフェイズも引数を用いて飛ばすことは可能ですが、ここでコケるのはライブラリの依存が足りていない証拠なので、「足りない」と言われた依存を適宜追加してください。
依存の解決
さて、ビルドシステムの説明も終わったことなので、先程書いたパッケージを一旦ビルドしてみましょう。
guix build -L /path/to/your/channel my-ag
すると、たくさんのビルドログの下のほうに、エラーが出るはずです。実は、一番下を見てもあまり有用な情報は出てきません。なぜなら末尾のエラーはScheme及びGNU Guixがコケたことによるエラーだからです。少し上に、コケた根本の原因、すなわちどこかのフェイズで実行された実際のコマンドのエラーのログがあるはずです。今回は、以下のような configure
フェイズのエラーが出ているはずです。
configure: error: The pkg-config script could not be found or is too old. Make sure it
これが出るのは正常です。 ag
のビルドに必要な依存を一切入れていないからです。
agのREADMEのBuilding a Release tarballとBuilding masterを読むと、以下が必要そうだとわかります。
automake
pkg-config
PCRE
LZMA
このうち automake
は gnu-build-system
においては自動で利用可能になっているので、気にする必要はありません。とりあえず、 pkg-config
を依存として追加してみましょう。
依存は package
オブジェクトに inputs
フィールドや native-inputs
として渡します(それらの違いは後述)。渡す値は package
オブジェクトのリストになります。つまり、依存パッケージを格納している変数がどのモジュールで定義されているか知る必要があります。パッケージの検索には guix search
や guix package -A
を使います。
guix search
では説明文も含めて検索しますが、 guix package -A
の場合はパッケージ名だけが検索の対象になります。また、ブラウザではこちらで検索することも可能です。
guix search pkg-config
結構たくさん候補が出てくるのですが、一番上に pkg-config
というそのままのパッケージがあります。ある特定のパッケージの情報だけを見たい場合は、 guix show
を使います。
guix show pkg-config
すると以下のような表示が得られます。ブラウザの検索の場合はこちらをご覧ください。
name: pkg-config
version: 0.29.2
outputs:
+ out: everything
systems: x86_64-linux i686-linux
dependencies:
location: gnu/packages/pkg-config.scm:37:2
homepage: https://www.freedesktop.org/wiki/Software/pkg-config
license: GPL 2+
synopsis: Helper tool used when compiling applications and libraries
description: pkg-config is a helper tool used when compiling applications and libraries. It helps you insert the correct compiler options on the command
+ line so an application can use gcc -o test test.c `pkg-config --libs --cflags glib-2.0` for instance, rather than hard-coding values on where to find glib
+ (or other libraries). It is language-agnostic, so it can be used for defining the location of documentation tools, for instance.
location
が gnu/packages/pkg-config.scm
となっていることから、このパッケージは (gnu packages pkg-config)
モジュールに定義されていることがわかります。行数は現時点でのものなので今後変更されているかもしれません。念のため定義を見ておきましょう。locationはブラウザでもコマンドラインでもリンクになっています。公式レポジトリでいうとこちらになります。そこには以下のような定義が書いてあります。
;; This is the "primitive" pkg-config package. People should use `pkg-config'
;; (see below) rather than `%pkg-config', but we export `%pkg-config' so that
;; `fold-packages' finds it.
(define-public %pkg-config
(package
(name "pkg-config")
(version "0.29.2")
...))
どうやら変数自体は %pkg-config
だけど、普通に pkg-config
を使ってくれと書いてあります。今回の場合は該当しませんが、変数名とパッケージ名は異なる場合がたまにあるので、このように確認する作業が必要になります。
さて、どのモジュールのどの変数に pkg-config
のパッケージが保存されているかわかったので、それを依存に入れていきます。
(define-public my-ag
(package
(name "my-ag")
...
(native-inputs
(list pkg-config))
...))
native-inputs
は「ビルドを行うプラットフォームで必要なパッケージ」を指定します。実はGNU Guixは今いるプラットフォームとは別のプラットフォーム用のパッケージをビルドする機能があります。「ビルドには必要だけど実際使うときにはいらないパッケージ」と捉えていただいて構いません。一方 inputs
は実行時にも必要な依存を記述します。なお、 propagated-inputs
というものも存在します。
propagated-inputs
に指定された依存は親パッケージをインストールすると一緒にインストールされます。
さて、これで再びビルドしてみましょう。
guix build -L /path/to/your/channel my-ag
すると、以下のようなエラーが得られます。
ice-9/eval.scm:223:20: In procedure proc:
error: pkg-config: unbound variable
hint: Did you forget `(use-modules (gnu packages pkg-config))'?
そういえば、 pkg-config
が定義されているモジュール (gnu packages pkg-config)
を指定していませんでしたね。このようにモジュールを指定せずに変数を使ってしまっても、かなりの確率で教えてくれます。勘で依存パッケージの変数を書いてビルドして、ヒントでどこにあるか確認するという横着もできてしまいます(私もけっこうやる)。
(define-module (your-channel-name packages ag)
#:use-module (guix packages)
#:use-module ((guix licenses) #:prefix license:)
#:use-module (guix download)
#:use-module (guix build-system gnu)
#:use-module (gnu packages pkg-config))
これでもう一度ビルドしましょう。
guix build -L /path/to/your/channel my-ag
今度は最初とは別のエラーが configure
フェイズで出ています。
configure: error: Package requirements (libpcre) were not met:
No package 'libpcre' found
先程言ったように、 PCRE
が依存として必要でした。他にも LZMA
が必要とのことだったので、一気に解決を試みましょう。
先程と同様に guix search
やブラウザでの検索を行うと、 pcre
は (gnu packages pcre)
モジュールにある pcre
という変数に束縛されたパッケージにあるとわかります。ここでは詳細を省きます。 pkg-config
のときと全く同じなので、是非実際に試してみてください。
LZMA
についても同様に検索しますが、どうも lzma
という名前のパッケージはないようです。これでは埒があかないので、とりあえずビルドして ./configure
がどんなエラーを吐くか見てみましょう。
(gnu packages pcre)
モジュールを use-module
しつつ、以下のようにパッケージ定義を変更しましょう。
(define-public my-ag
(package
(name "my-ag")
...
(native-inputs
(list pkg-config))
(inputs
(list pcre))
...))
依存として inputs
に PCRE
を追加しました。ビルドしてみましょう。
guix build -L /path/to/your/channel my-ag
すると以下のようなエラーが build
フェイズで得られます。 configure
フェイズはどうやら正常に通ったようです。
src/zfile.c:63:9: error: unknown type name ‘z_stream’
63 | z_stream gz;
| ^~~~~~~~
(後略)
ここからはGNU Guixに限った話ではなく、ただただビルドを通るまで依存を追加していく作業になります。幸い z_stream
でググると zlib
の話が大量に出てくるので、 zlib
に定義されていることがすぐわかります。また、もう一度基本に戻って公式のビルド手順を見てみると、Fedoraにおける依存解決のしかたが書いてあります。
yum -y install pkgconfig automake gcc zlib-devel pcre-devel xz-devel
どうも、ここでも zlib
が必要なことがわかります。(もうひとつ xz
というのも入っていますが、とりあえず無視しておきます。)
GNU Guixでのビルド方法の情報は少ないため、このような他のディストロの情報を利用するのも大切です。
先程と同じように zlib
というパッケージを探し出していきます。ここも詳細は省きますが、 (gnu packages compression)
モジュールに zlib
が定義されています。
#:use-module
しつつまた依存を追加していきます。
(define-public my-ag
(package
(name "my-ag")
...
(native-inputs
(list pkg-config))
(inputs
(list pcre zlib))
...))
ここでビルドすると、 build
フェイズの最後に行うリンクでコケます。
CCLD ag
ld: src/log.o:/tmp/guix-build-my-ag-2.2.0.drv-0/the_silver_searcher-2.2.0/src/log.h:12: multiple definition of `print_mtx'; src/ignore.o:/tmp/guix-build-my-ag-2.2.0.drv-0/the_silver_searcher-2.2.0/src/log.h:12: first defined here
ld: src/log.o:/tmp/guix-build-my-ag-2.2.0.drv-0/the_silver_searcher-2.2.0/src/util.h:15: multiple definition of `out_fd'; src/ignore.o:/tmp/guix-build-my-ag-2.2.0.drv-0/the_silver_searcher-2.2.0/src/util.h:15: first defined here
(後略)
ag multiple definition of
で検索してみると、どうやら ag
自体のバグなようです。そこの説明文をみるに、
GCC-10(gnu-build-system
で利用されるデフォルトのGCCのバージョンは2022/12/7現在では10です)では
./configure
に CFLAG=-fcommon
を付けないと動かないとのこと。このような場合、どうすればよいでしょうか。
実は「ビルドシステム」というのは引数を取ることができます。引数は package
のフィールドとして直接与えます。つまり以下のように書きます。
(define-public example
(package
(name "example")
(version "0")
...
(arguments
'(#:tests? #f
#:configure-flags '("--some-option" "--other-option")))
(build-system gnu-build-system)
...))
使用するビルドシステムによって取れる引数は異なりますが、ほとんどのビルドシステムは gnu-build-system
を継承して作られているため、代表的なものは他のビルドシステムでも利用できます。折角なのでいくつか紹介しておきます。公式マニュアル(英語)で一覧を見ることができます。
#:configure-flags
./configure
に渡されるオプションを文字列のリストで渡します。典型的にはオプションの機能をオンにしたりオフにしたりするのに使います。#:make-flags
make
、make check
、make install
に渡されるオプションを文字列のリストで渡します。あまり利用頻度は多くないです。#:tests?
- テスト(
make check
)をするかどうか、すなわちcheck
フェイズを行うかどうか真偽値で渡します。デフォルトでは#t
(Schemeにおけるtrue)となっていて、ネットワークがないとテストが通らない場合やそもそもテストがない場合には#f
(Schemeにおけるfalse)を指定してテストをしないようにします。 #:strip-binaries?
- 生成されたバイナリからデバッグ情報を取り除くかどうか、すなわち
strip
フェイズを行うかどうかを真偽値で渡します。 #:phases
- この引数が最も柔軟にビルド内容を変更できます。具体的には、ビルドプロセスの1手順(phase)をまるっと別のものに入れ替えたり、ある手順の前や後ろに別の手順を追加したりできます。詳細の書き方を以下に置いておきますが、かなり難しい内容になっているため、一旦飛ばしても構いません。
#:phases
引数を利用するための詳細な説明
各フェイズ自体もSchemeで書かれているため、無名関数を与えるだけで新しいフェイズを与えることができます。この引数として与える式は、ほとんどが (modify-phases %standard-phases ...)
という形です。
%standard-phases
というのは build-system
を経由して与えられるフェイズ群で、これを修正した新しいフェイズ群を与えることでフェイズの変更を達成しています。
(modify-phases %standard-phases ...)
のうち ...
の部分には以下の4つをいくつでも書くことができます。
(delete 'phase-name)
phase-name
という名前のフェイズを削除します。(replace 'old-phase-name 無名関数)
old-phase-name
という名前のフェイズを新しいフェイズに置き換えます。(add-before 'base-phase-name 'new-phase-name 無名関数)
base-phase-name
という名前のフェイズの前にnew-phase-name
という名前の新しいフェイズを追加します。(add-after 'base-phase-name 'new-phase-name 無名関数)
base-phase-name
という名前のフェイズの後にnew-phase-name
という名前の新しいフェイズを追加します。
無名関数は新しいフェイズの定義になります。無名関数はキーワード引数を受け取ります。受け取れる引数は #:make-flags
などの各種引数と、 inputs
や outputs
といった連想リストです。
inputs
は、キーを依存の名前、値を依存として与えられたディレクトリ(読取専用)へのパスとした連想リストです。
outputs
は、キーを出力の名前(普通に定義したパッケージは"out"のみをキーとする)、値を出力先(インストール先)のディレクトリへのパスとした連想リストです。これらを用いることで、新しいフェイズから依存のディレクトリやインストール先のディレクトリを直接触ることができます。たとえばデフォルトの出力先である"out"に対応するディレクトリを取り出す場合は、 (assoc-ref outputs "out")
とします。
以下に例を示します。この例は公式マニュアル(英語)からの引用です。
(define-public example
(package
(name "example")
;; other fields omitted
(build-system gnu-build-system)
(arguments
'(#:phases (modify-phases %standard-phases
(delete 'configure)
(add-before 'build 'set-prefix-in-makefile
(lambda* (#:key outputs #:allow-other-keys)
;; Modify the makefile so that its
;; 'PREFIX' variable points to "out".
(let ((out (assoc-ref outputs "out")))
(substitute* "Makefile"
(("PREFIX =.*")
(string-append "PREFIX = "
out "\n")))))))))))
この例では2つのフェイズ修正を行っています。一つ目は (delete 'configure)
による configure
フェイズの削除です。二つ目は (add-before 'build 'set-prefix-in-makefile ...)
による新しいフェイズの追加です。
Schemeでキーワード引数を受け取る無名関数を作りたい場合、
(lambda* (#:key key1 key2 #:allow-other-keys) ...)
のように書きます。特に #:allow-other-keys
は必要のないキーワード引数を受け取ってもエラーにならないようにするもので、フェイズのようにどんな引数が渡されるかわからないような状況では便利です。
今回受け取って引数として束縛するキーワード引数は outputs
だけです。前述のようにここには連想リストが束縛されています。その後、 let
節を用いて (assoc-ref outputs "out")
すなわちインストール先のディレクトリへのパスを
out
一時変数に束縛しています。さらにその後 substitute*
マクロを使っています。このマクロは、第一引数に与えられたファイルにおいて、第二引数以降で指定された置換を実行します。第二引数以降は ((regexp...) body...)
の形を取っていて、 (regexp...)
には置換したい対象を表す正規表現のリストを、
body
は順次評価したときに最後の評価結果が置換後の文字列になるようなS式群を表しています。これにより Makefile
の中にある 「PREFIX=.*」にマッチする文字列すべてが、「PREFIX=パッケージにおけるインストール先のディレクトリの絶対パス」へと置き換わります。
arguments
として与えられたリストはクオートされていることに注意してください。すなわち、 今の無名関数を含めた arguments
下にあるS式は、現環境では評価されません。
これがなにを意味するかというと、現在のモジュールで #:use-module
宣言をいくらしたところで、さきほどの無名関数からそのモジュールの機能には一切アクセスできません。なぜなら各 arguments
が評価される環境は現在のモジュールを定義した環境ではなく、
guix
がパッケージをビルドしようとしたときの環境だからです。もしなんらかのモジュールを無名関数で利用したい場合、無名関数の中で use-modules
マクロを呼び出すことであらためてモジュールの使用を宣言してください。以下は (ice-9 match)
モジュールと (srfi srfi-26)
モジュールを無名関数の中で使う場合の例です。
(lambda* (#:key outputs #:allow-other-keys)
(use-modules (ice-9 match)
(srfi srfi-26))
...)
つまり、今回の場合は #:configure-flags
として CFLAG=-fcommon
が与えられればよいわけです。つまり以下のように書きます。
(define-public my-ag
(package
(name "my-ag")
...
(arguments
'(#:configure-flags (list "CFLAGS=-fcommon")))
...))
この状態で再びビルドしてみましょう。
すると、エラーが全く出ずに最後まで実行できました。ビルド成功です。しかしまだ喜んではいけません。それがインストールされた環境へ入って実行してみましょう。今回は --pure
でも --container
でも構いません。
guix shell --pure -L /path/to/your/channel my-ag
たとえば今作っていたチャンネルのディレクトリに入り、 ag home-page
と実行してみましょう。すると、我々が今作成したパッケージや、前回の記事で作ったフォントのパッケージの home-page
フィールドがきちんとみつけられました。きちんと動いています。
xz
について
先程見た公式のビルド手順には、Fedoraにおける依存解決のしかたが書いてありました。
yum -y install pkgconfig automake gcc zlib-devel pcre-devel xz-devel
ここには、 xz
というみたことのない依存を入れています。なくても動きますが、公式のチャンネルの定義では入れています。せっかくなので xz
を入れていきましょう。
まずは、 xz
を検索してみます。今度は guix package -A
を使ってみましょう。
guix pacakge xz
すると以下のようなリストが得られます。
java-xz 1.9 out gnu/packages/java-compression.scm:288:2
pixz 1.0.7 out gnu/packages/compression.scm:1059:2
rust-xz2 0.1.6 out gnu/packages/crates-io.scm:67762:2
xz 5.2.5 out,static gnu/packages/compression.scm:509:2
xzgv 0.9.2 out gnu/packages/image-viewers.scm:983:2
ずばり xz
という名前のパッケージがあるので、これを使うとよさそうです。
guix show xz
で詳細情報も確認しておくと確実です(LZMAに触れられています)。モジュールは zlib
と同様なので新しく use-module
する必要はなさそうです。変数名もそのまま xz
であることを確認し、依存として inputs
に xz
も追加します。
(define-public my-ag
(package
(name "my-ag")
...
(native-inputs
(list pkg-config))
(inputs
(list pcre zlib xz))
...))
これでも同様に動きますが、動作に必要あるかは不明です(もしかしたら xz
がないと特定の機能だけ動かない可能性もある)。
guix import
で手抜きできる場合がある
ビルドが必要なパッケージの定義を実際に行っていきました。それなりに大変だったと思います。使いたいパッケージの度にこれを行うのは億劫だという人もいると思います。実は、比較的簡単にパッケージを定義できる場合があります。それは、 guix import
が利用できる場合です。
guix imort
は、インポーターというものを使って自動でパッケージ定義を書く機能です。インポーターの一覧など、詳しくは公式マニュアル(英語)にありますが、例えば以下のようにしてパッケージを生成できます。
guix import go gopkg.in/yaml.v2 --recursive
go
というのがインポーターを表していて、https://proxy.golang.org/からメタデータを取得することでパッケージ定義を生成します。
--recursive
は依存を再帰的に辿ってパッケージ定義を生成するオプションで、付けないと依存が足りずにビルドがコケます。また、デフォルトでは標準出力に定義を吐くため、ファイルにでも流しこんでください。モジュール定義 や #:use-module
は行ってくれないので、自分で行ってください。
もちろん guix import
だけで全てのパッケージ定義を賄うことはできないですし、これを用いてもビルドが失敗することはあります。それでも、依存先のパッケージなども含めて一気に定義できるのは有用ですし、ビルドが失敗しても今回の記事のようにビルドを成功へ導いてあげればよいです。是非利用してみてください。
最後に
今回の記事では、ビルドの必要なパッケージ定義を扱いました。これをマスターすればあなたも guix
の玄人です。
前回とおなじ締めですが、もしなにか質問などあれば、コメントなりメールなりで受け付けます。また、Guixの日本語コミュニティであるGuix-jpもあります。そちらには私以上のエキスパートの人がいますので、是非そちらもご興味あれば覗いてみてください。
次回の記事はこちらになります。