2014-04-05-01-*features*で条件付きコンパイル
>> Site top >> weblog >> 月別アーカイブ >> 2014年04月のlog >> 2014-04-05-01-*features*で条件付きコンパイル
最終更新日付:2014/04/05 01:00:00
*features*で条件付きコンパイル
2014 年 04 月 05 日
Common Lisp では標準で *features* というダイナミック変数があって、環境や処理系の情報を格納している。で、#+ や #- というリードマクロによってそれらの情報に依存したことができる。
で、以前からやりたいと思っていた条件付きコンパイルみたいなことをそれでやってみることにした。それも、起動時点で *features* に入っている値を使うのではなく、自分で値を追加して使うというものだ。その是非については正直自信がないのだけれど。
そもそもやりたいと思ったのは、例のアレだ。STL の Common Lisp 移植である CL-STL でだ。C++ 0x11 の機能をコンパイルやロードの時点でスイッチしたいと思ったワケだ。そのために、例えば iota アルゴリズムを以下のようにしてみる。
#+cl-stl-0x11 (locally (declare (optimize speed)) (defmethod iota ((first forward-iterator) (last forward-iterator) init &optional (unary-op #'1+)) (if (iter= first last) nil (do ((acc init) (incr (clone unary-op)) (itr (clone first))) ((iter= itr last) nil) (setf (iter* itr) acc) (setf acc (functor-invoke incr acc)) (++iter itr)))))
これで、コンパイルやロードの時点で *features* に :CL-STL-0X11 がなければこれは無視されることになる。これを有効にしたければ、例えば require でやるときなら、以下のようにすることになる。
(let ((*features* (cons :cl-stl-0x11 *features*))) (require :cl-stl))
これはこれでいい。意図した通りに動作する。問題は、だ。こういう目的に *features* を使うことの是非だ。手元にある本を全部確認してみたが、そのことについてはっきり書いてあるものは見当たらなかった。ふぅ。
コメント
g000001 - 2014/04/05 20:09:00
project-enigma - 2014/04/06 18:30:00
あぁ、たしかに「条件付きコンパイル」ではありませんね。読み取り時に切り分けて、コンパイル時には全てカタはついている、と。
その点について気になっているのは、ASDF なんかで require でもって fasl の作成とロードをバックエンドに隠すような使い方をしている(私もそうですが)と、:cl-stl-0x11 があるバージョンとないバージョンの使い分けがやりにくいかな‥‥‥と感じるところですね。
このページのタグ
Page tag : Common Lisp
Page tag : STLとその移植
Copyright(C) 2005-2021 project-enigma.
Generated by CL-PREFAB.
*features* 自体はコンパイル/ロード/実行等、どのフェーズでも参照できますが、#+- はリーダーマクロのため、読み取り時以外には作用しません(読み取り時に作用が完了します)。
つまり、コードの読み取り時に *features* を参照して不要な箇所は捨てるという動作になります。このため、コンパイルするコードは切り分け後のコードになります。
今回のブログエントリーのコード例の場合、:cl-stl-0x11 が *features* にない環境で compile-file してできた fasl を load しても、iota のコードは含まれないことになります。
Common Lisp の人が良くやる *features* での切り分けは、条件付きコンパイル、ではなくて、条件付き読み取りしたコードを普通にコンパイル、ということかなと思います。