common lispのプログラムにemacsでアタッチ
cursesっていうターミナル表示の制御ライブラリ*1を使ってテトリスを作ってみてるのだけど、途中でエラーが起こったときにデバッグ表示が乱れる。特にマルチスレッドだと目も当てられない。そこでemacsでアタッチしてデバッグすると便利。
ちなみに↓がテトリスの動作風景。ソースはもう少し整理してから公開したいと思う。
開発してた時の手順
処理系はsbcl*2。quicklispを使っている。slimeもquicklispでインストールしてある。
環境は Mac (Mavaricks)、sbcl 1.2.11。
~/quicklisp/local-projects 以下にあるプロジェクトは設定なしに quicklisp で読めるので、
quickproject でこの下に作っている。mainという関数を作って export しておき、
$ sbcl --eval '(ql:quickload :tetris :silent t)' --eval '(tetris:main)' --quit
という感じで走らせる。もしくは
(defun make-tetris-command (&optional (name "tetris")) (sb-ext:save-lisp-and-die name :compression t :toplevel #'main :executable t))
というのを作っておくと
$ sbcl --eval '(ql:quickload :tetris :silent t)' --eval '(tetris:make-tetris-command)'
でカレントディレクトリに tetris という実行ファイルを作れるので
$ ./tetris
で走らせられる。
デバッグ
ターミナルから
$ sbcl --eval '(ql:quickload :tetris :silent t)'
で起動して
* (ql:quickload :swank) To load "swank": Load 1 ASDF system: swank ; Loading "swank" . (:SWANK) * (swank:create-server :port 5555 :style :fd-handler :dont-close t) ;; Swank started at port: 5555. 5555
とする*3。ポートがかぶったりしてたら適当に変えてください。
emacs側で M-x slime-connect localhost 5555 とすると繋がる。
あとは emacs 側のreplで
CL-USER> (tetris:main)
と打てば、コンソール側でプログラムが走り出す。何か問題が起きたら emacs 側でデバッガが立ち上がる。M-n や M-p でスタックトレースを行き来したり、ソースファイルを開いてから修正して C-c C−c でコンパイルして実行再開とかできて便利。
しかし、ゲームを作るというのは、特に曲がりなりにも動くようになってからゲームとして成立しだす時というのはなかなか面白いね。