序文

前回の記事では、フォントのパッケージ定義を通じて、パッケージ定義の流れを解説しました。この記事では一歩進んで、ビルドを伴うパッケージの定義を行っていきます。

実は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-systemgnu-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.scmguix/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に従ったディレクトリ構造をしておらず、 bashsh をも /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 tarballBuilding masterを読むと、以下が必要そうだとわかります。

  • automake
  • pkg-config
  • PCRE
  • LZMA

このうち automakegnu-build-system においては自動で利用可能になっているので、気にする必要はありません。とりあえず、 pkg-config を依存として追加してみましょう。

依存は package オブジェクトに inputs フィールドや native-inputs として渡します(それらの違いは後述)。渡す値は package オブジェクトのリストになります。つまり、依存パッケージを格納している変数がどのモジュールで定義されているか知る必要があります。パッケージの検索には guix searchguix 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.

locationgnu/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))
    ...))

依存として inputsPCRE を追加しました。ビルドしてみましょう。

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です)では ./configureCFLAG=-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
makemake checkmake 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 などの各種引数と、 inputsoutputs といった連想リストです。 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 であることを確認し、依存として inputsxz も追加します。

(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もあります。そちらには私以上のエキスパートの人がいますので、是非そちらもご興味あれば覗いてみてください。

次回の記事はこちらになります。