LoginSignup
12
6

More than 3 years have passed since last update.

GNU GuixでQuicklispから卒業したい

Last updated at Posted at 2020-02-14

GNU GuixでQuicklispから卒業したい

処理系固有のツールを避けたい&Guixインストールからの続きです。

これまでのあらすじ

先日GNU Guixと言うNix派生の次世代パッケージ管理システム(と言ってもNixはそれなりに古いですが)を導入しました。GNU Guileのコードでパッケージの定義を行うのでNixと比較し個人的にはわかりやすい感じがします。ということでQuicklispが担う役割をプライベートチャネルを作って、自分が使うパッケージのみをひとまず管理する感じで代替しつつ、ECL処理系を複数バージョン同時に導入し、切り替えも簡単にできるように、突き進んでみます。

Guixの特徴を簡単にまとめてみます。

  • 個別のユーザー単位で導入パッケージの管理ができる
  • パッケージ操作の履歴が保持され、ロールバックが可能
  • 同一パッケージの別バージョンを両方入れておくことができる。LibraryAバージョン1とLibraryAバージョン1.1を別名で管理するのではなく、どちらもLibraryAという名前で同時に存在する
  • パッケージ定義ファイルが書きやすい(少なくともDebパッケージより簡単だと思う)
  • GNU/Linux、GNU/Hurdで動作する
  • OSに付随するパッケージ管理システムで導入したパッケージとは競合しない

このツールの有用性は、ディストリビューションに依存しない、言語処理系に依存しないパッケージ管理ツールであり、それら全てのツールを代替できる可能性がある点だと思っています。

他の言語処理系であっても、DockerとGuixがあれば中間に存在するOSや言語処理系に依存するパッケージ管理ツールは不要になるのでは?不要にしたい!という願いを実現するべく、使いものになるのかちょっとずつ試していきます。

環境

  • Debian GNU/Linux 10.2
  • Guix 1.0.1

Guixのコマンドについて

以下のように、--helpでコマンドの説明を確認できます。guix package --helpとすると、package操作の詳細なヘルプを確認できます。

$ guix --help
$ guix package --help

パッケージ操作

$ guix package -I # インストール済みパッケージリスト
$ guix package -r package-name # パッケージ削除
$ guix package -i package-name # パッケージインストール
$ guix package -s package-name # パッケージ検索

インストールや削除は1回の操作で1つのトランザクションになり、次にように複数のパッケージのインストールと削除を1回の操作で実行できます。

$ guix package -r pn1 pn2 -i pn3 pn4 pn5

世代操作

一般的なパッケージ管理システムにない世代操作について。世代一覧は、-lオプションを与えることで確認できます。

$ guix package -l
Generation 25    2月 14 2020 12:53:36
 + cl-alexandria    1.0.0-1.3b849bc out /gnu/store/f85dbyyhfyanqly48nrmsvs048qy7hxa-cl-alexandria-1.0.0-1.3b849bc

Generation 26    2月 14 2020 13:26:05
 + cl-sdl2  1.0.0-1.1588954 out /gnu/store/r4pb0zby2aq2fn043byykvn559bbdvb5-cl-sdl2-1.0.0-1.1588954

Generation 27    2月 14 2020 14:06:30
 - cl-sdl2  1.0.0-1.1588954 out /gnu/store/r4pb0zby2aq2fn043byykvn559bbdvb5-cl-sdl2-1.0.0-1.1588954

Generation 28    2月 15 2020 03:16:23  (current)
 + cl-sdl2  1.0.0-1.1588954 out /gnu/store/r4pb0zby2aq2fn043byykvn559bbdvb5-cl-sdl2-1.0.0-1.1588954

+は導入、-は削除を意味します。実験のためにcl-sdl2を導入したり削除したりしてたんですが、その世代の履歴が上の内容から確認できます。

nanoを入れて、もう一度-lを付けて実行します。Generation 29が作られ、(current)という指定が付与される状態になります。

$ guix package -i nano
$ guix package -l
Generation 28    2月 15 2020 03:16:23
 + cl-sdl2  1.0.0-1.1588954 out /gnu/store/r4pb0zby2aq2fn043byykvn559bbdvb5-cl-sdl2-1.0.0-1.1588954

Generation 29    2月 15 2020 04:08:01  (current)
 + nano 4.8 out /gnu/store/l5ds0mx103lrir23l302ax148wy2pd7q-nano-4.8

世代をひとつ前に戻します。-Sオプションに-1を指定します。すると、以下のように(current)Generation 28に付与された状態になります。

$ guix package -S -1
switched from generation 29 to 28
$ guix package -l
Generation 28    2月 15 2020 03:16:23  (current)
 + cl-sdl2  1.0.0-1.1588954 out /gnu/store/r4pb0zby2aq2fn043byykvn559bbdvb5-cl-sdl2-1.0.0-1.1588954

Generation 29    2月 15 2020 04:08:01
 + nano 4.8 out /gnu/store/l5ds0mx103lrir23l302ax148wy2pd7q-nano-4.8

これにより、インストール前の状態に戻すことができます。

プライベートチャネルを作る

初期状態で、Guixにはguixという名前のデフォルトチャネルが存在します。このチャネルにあるパッケージは、https://guix.gnu.org/packages/で確認することができ、現在は1万以上のパッケージが登録されています。

このようなパッケージのチャネルは自分で作成することができます。cl-sdl2はGNUのパッケージチャネルに存在しないため、次のようなディレクトリ構造で、cl-sdl2を配信するチャネルを作成します。

チャネルのディレクトリ・ファイル

$ tree 
.
└── cl-guix
    └── packages
        └── cl-package.scm

cl-package.scmの中身は以下のような形になります。

cl-package.scm
(define-module (cl-guix packages cl-package)
  #:use-module (guix packages)
  #:use-module (guix utils)
  #:use-module (guix download)
  #:use-module (guix git-download)
  #:use-module (guix build-system gnu)
  #:use-module (guix build-system asdf)
  #:use-module ((guix licenses) #:prefix license:)
  #:use-module (ice-9 match))

(define-public cl-sdl2
  (let ((revision "1")
        (commit "1588954ee4abc37b01a7e2e17a76e84fd4da8c77"))
    (package
     (name "cl-sdl2")
     (version (git-version "1.0.0" revision commit))
     (source
      (origin
       (method git-fetch)
       (uri (git-reference
             (url "https://github.com/lispgames/cl-sdl2.git")
             (commit commit)))
       (file-name (git-file-name name version))
       (sha256
        (base32 "15x5d139qj3zba2qx3r43s1sh2bqgm4zcwd07kx2l23q2j89v509"))))
     (build-system asdf-build-system/source)
     (synopsis "Common Lisp SDL2 Package")
     (description "")
     (home-page "https://github.com/lispgames/cl-sdl2")
     (license license:expat))))

define-moduleに渡している(cl-guix packages cl-package)は、このscmファイルのあるディレクトリまでの構造を記述します。cl-guix以下のpackages以下のcl-package.scmファイルのため、このように記述しています。

#:use-moduleは、このパッケージ内で使用するモジュールの指定を行います。

define-publicで、公開するパッケージの定義を開始します。実際のパッケージ定義は、packageから始まる箇所です。

Gitリポジトリからファイルを取得するための記述

今回、cl-sdl2はhttps://github.com/lispgames/cl-sdl2の最新のコミットを取得する形にしています。以下の部分がGitリポジトリからファイルを取得するための記述になります。

(origin
 (method git-fetch)
  (uri (git-reference
        (url "https://github.com/lispgames/cl-sdl2.git")
        (commit commit)))
  (file-name (git-file-name name version))
  (sha256
   (base32 "15x5d139qj3zba2qx3r43s1sh2bqgm4zcwd07kx2l23q2j89v509"))))

commitという変数には、GitのコミットIDを入れておき、どのコミットを取得するのかを指定します。sha256base32の値は、以下のコマンドで確認できるため、それをそのまま記述しておきます。

$ git clone https://github.com/lispgames/cl-sdl2.git
$ guix hash -rx ./cl-sdl2
15x5d139qj3zba2qx3r43s1sh2bqgm4zcwd07kx2l23q2j89v509

ASDFシステムのためのビルドシステム

Guixには様々な環境に向けたビルドシステムが用意されており、ここでは、ASDFシステム用のビルドシステムを用います。

(build-system asdf-build-system/source)

は、特別なことをせずASDFのシステム定義をソースのままインストールする形になります。asdf-build-system/eclasdf-build-system/sbclと言ったオプションもあるのですが、実行時にコンパイルすれば良い感じがするのでsourceを選択しています。

チャネルの公開

作成したディレクトリとファイルをGitバージョン管理下に置き、そのまま公開します。今回は、https://gitlab.com/hu.moonstone/cl-guix.gitにpushしました。

チャネルの登録

手元のGuixで、新しく公開したチャネルを登録する必要があります。$HOME/.config/guix/channels.scmというファイルを新しく作成し、次の内容を記述します。

channels.scm
(cons (channel
       (name 'cl-guix)
       (url "https://gitlab.com/hu.moonstone/cl-guix.git")
       (branch "master"))
      %default-channels)

その後、以下のコマンドを実行します。

$ guix pull

登録に問題がなければ、guix pull -lによって以下のような形でcl-guixが新しく登録されていることを確認できます。

Generation 2     2月 15 2020 03:14:44  (current)
  cl-guix 83c669a
    repository URL: https://gitlab.com/hu.moonstone/cl-guix.git
    branch: master
    commit: 83c669af1bba037ea09ad6886eb540f3cb10e9bf
  guix 64fc4f3
    repository URL: https://git.savannah.gnu.org/git/guix.git
    branch: master
    commit: 64fc4f3705423c83c680a95d8dea81a39fce9a70

あとは、通常通りの操作でcl-guixに登録されているcl-sdl2パッケージを導入することができます。

$ guix package -i cl-sdl2

インストールされたファイルの場所

$HOME/.guix-profile以下に展開されます。asdf-build-system/sourceの場合、.guix-profile/share/common-lisp/source以下にファイルが設置されるので、次のようにしてASDFにパスを教えると読み込みにいきます。以下の設定ファイルはECLのもので、Guixインストール時に設定したGUIX_PROFILE環境変数の値を使ってASDFのsource-registry-parameterの設定を変更しています。

.eclrc
(defparameter *deepspace-home* (si:getenv "DEEPSPACE_HOME"))
(defparameter *guix-profile* (si:getenv "GUIX_PROFILE"))
(load (concatenate 'string *deepspace-home* "/lib/asdf.lisp"))
(require 'asdf)
(setf asdf:*asdf-verbose* nil)
(setf *load-verbose* nil)
(asdf:initialize-source-registry
`(:source-registry
   (:tree ,(concatenate 'string *guix-profile* "/share/common-lisp/source"))
   (:tree ,(concatenate 'string *deepspace-home* "/share/deepspace/quicklisp/dists/quicklisp/software"))
   (:tree ,(concatenate 'string *deepspace-home* "/lib/"))
   (:tree ,(namestring *default-pathname-defaults*))
   (:tree ,(concatenate 'string (namestring *default-pathname-defaults*) "lib"))
   :inherit-configuration))
(asdf:initialize-output-translations
 '(:output-translations
   :enable-user-cache
   :ignore-inherited-configuration))

多少手間はかかりますが、Quicklispが月に1度の更新で、最新の修正を取り込みたい場合や、以前のバージョンを使いたい場合など、簡単にパッケージを作成できるので、自分のプロジェクトが依存するパッケージのためのプライベートチャネルの作成を進めるのも良いかもしれません。

参考

12
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
6