#:g1: 単一ファイル構成のプロジェクトの読み込み

Posted 2020-09-11 19:31:26 GMT

ちょっとした内容を単一ファイルに記述し、それをロードして実行させたいことは結構あります。
こういう場合には論理パスを使うのが便利だということを最近発見したので、それについて書きたいと思いますが、その前に一般的な方法も改めて考察してみましょう。

ASDFを使う

ASDFを使うまでもない、という感もあるのですが、Quickproject等、プロジェクトの雛形をさっと作れるツールがあるので、中身が1ファイルしかないといっても対した手間ではないでしょう。
実際Quicklispにも単一ファイル規模のプロジェクトは結構あります。

ただ、quicklispがセットアップできてなかったり、ASDFのシステムがうまく登録されてなかったりで、すったもんだすることは割とあります。

(ql:quickload 'foo)

(foo::main)

みたいなファイルを、lisp --load foo.lisp したりするわけですが、おや結局foo.lispはどこに置けば良いのだろう、などということにもなったりもします。

スクリプト化する

スクリプト実行と親和性の高いCLISPのような処理系では、手軽に#!スクリプトとしてまとめられます。

#!/usr/bin/clisp -norc -q

(ql:quickload 'foo)

(foo::main)

みたいな感じで書いて、実行可能ファイルにしてパスの通った所に置けば良いので、そこそこお手軽です。ただCLISP以外はCLISP程の手軽さは感じられないことが多いかなと思います。

また、スクリプト的に書くのか、slime上でそこそこLisp的に開発するのかの間で逡巡することもままあるかなという印象です。

読み込み時のパス変数を使う

ファイルを読み込んだ時に、*load-pathname*や、*load-truename*でパスが取得可能なので、このパスから色々することも可能です。
残念ながらLispマシン等で使われていたdefsystemがANSI Common Lispで標準化されなかったため、プロジェクトの読み込み方法が処理系ごとに大きく違ってしまっていた、1990年代〜ASDFというdefsystemが普及する2000年代あたりまでは、これらのロード時/コンパイル時パスをあれこれしてどうにか対処することもあったようです。
全体的にパスを計算する手間が面倒になる上、それに起因するバグも多くなる印象です。

論理パスを使う

論理パスでは物理パスとは独立に任意のパスを新規に定義できます。
例えば、ホームディレクトリのlispディレクトリを“lisp:”という論理ホストに設定することが可能です。

これで何が可能になるのかというと、(load "lisp:foo")で、~/lisp/foo.lispをロードすることが可能になるので、“lisp:”以下に置かれたlispファイルをロードするという行為がかなり手軽になります。
また、論理パスに対応したエディタであれば、論理パスでファイルがすぐ開けるのも便利で開発が捗ります。
(なお対応しているエディタはほぼありません)

論理パスの設定

論理パスは、logical-pathname-translationsで直に設定してしまっても良いですが、ホストマシン全体で設定する方法がCommon Lispの標準に用意されているので、その手順に従うと色々楽だったりします。

“lisp:”を設定する場合、SBCLの場合は、“sys:site;lisp.translations.newest”に

;;; -*- lisp -*-
(("**;*.*.*" #.(merge-pathnames 
                (make-pathname :name :wild
                               :type :wild
                               :version :unspecific
                               :directory '(:relative "LISP" :wild-inferiors)
                               :case :common)
                (user-homedir-pathname)))))

のような記述をすれば、

(load-logical-pathname-translations "lisp")

で上記のファイルを読み込むことが可能です。
“sys:site;lisp.translations.newest”が論理パスですが、

(translate-logical-pathname "sys:site;lisp.translations.newest")

で物理パスに変換できるので確認できるでしょう。

以上は、load-logical-pathname-translationsの作法に則った設定ですが、面倒臭ければ、/etc/sbclrc

(setf (logical-pathname-translations "lisp")
      `(("**;*.*" ,(merge-pathnames 
                    (make-pathname :name :wild :directory '(:relative "LISP") :case :common)
                (user-homedir-pathname)))))

のようなものを書いてしまっても良いでしょう。

providerequireと論理パスの組み合わせ

論理パスを設定しておけば、あまり利用することもないrequireprovideの機能を活かすことも可能になります。

上記foo.lispの例であれば、foo.lispの中に、(provide "lisp:foo")と宣言し、読み込まれたら"foo"モジュールが登録されるようにておきます。

読み込みは、

(require "lisp:foo" "lisp:foo")

のように明示的にパスを指定してやります。
明示的にパスを指定するので、loadと大差ありませんが、loadと違い、再度読み込みの防止機能があるので、まあこれはこれで便利なこともあるでしょう。

ちなみにモジュール名を論理パスと同じにすると管理が楽です。

まとめ

単一ファイル構成のプロジェクトの読み込みについて論理パスが活用できる可能性について書きました。
隅に置いやられている論理パスですが、使い様によっては結構活用できそうなので、今後も活用法を探っていきたいところです。


HTML generated by 3bmd in LispWorks Personal Edition 7.1.2

comments powered by Disqus