リモート swank サーバに繋ぐ俺の設定
この文章は、 lisp Advent Calendar 2018 - Qiita の 12/1 分の記事として書かれました。
最近はやはり、 AWS 上のインスタンスに接続して作業したり、さらにそのインスタンスに Lisp 処理系をインストールし、そこに繋いで開発することが多いです。
そういうわけで Emacs ユーザの僕は、 tramp-mode で繋いで、そこで起動した Lisp 処理系に slime-connect
して作業しています。
ここでは、最近使ってる僕の設定を紹介します。
趣旨は Emacs+SLIMEでCommon Lispの開発をリモートでするまとめ - masatoi’s blog と同じです。
Concept
- わざわざ ssh forward のために別ターミナルを起こすなどするの面倒
→ なので、 ssh-config いじって、 Emacs が tramp-mode で張る ssh 接続に同居させる。
- あんまりコード書かずに Remote Swank サーバを起こしたい
→ slime のコードに付属されてるのを直接呼べばいいや
- 色々なサーバに swank を起こすコードを持っていくのは面倒
→ いつも僕は M-x shell
を使っているので、 shell-mode
の abbrev にコードを登録すればいいでしょ。
設定
.ssh/config
にポートフォワード設定を書く。
HOST home-xubuntu USER y2q HostName 192.168.3.100 LocalForward 4005 localhost:4005
重要なのは LocalForward
の設定です。
ここでは、 home-xubuntu
ホスト上の localhost:4005
に対して、接続元の 4005 ポートから繋げるようにしています。
これを行うことで、 home-xubuntu
ホストに Emacs から tramp-mode 経由で接続すれば、自動的にこのポートフォワードがされるようになります。
Emacs で slime-tramp
をloadするようにする
(use-package slime :config (add-to-list 'slime-contribs 'slime-fancy) (add-to-list 'slime-contribs 'slime-tramp) ; この行を足す。 (add-to-list 'slime-contribs 'slime-xref-browser))
Emacs に slime-tramp
が load されるよう、 slime-contribs
に slime-tramp
を足してから slime の初期化を行います。
Emacs 上で slime-filename-translations
を設定する。
(eval-after-load 'slime-tramp '(progn (add-to-list 'slime-filename-translations (slime-create-filename-translator :remote-host "home-xubuntu" ;; I got below by evaluating `(cl:machine-instance)' by SBCL in the 'home-xubuntu' host. :machine-instance "y2q-PC-VK17HBBCD" :username "y2q"))))
slime に tramp パスを渡す場合、それをどのように変換して Lisp 処理系に渡すかを教えてあげる必要があり、
その設定は、 slime-filename-translations
に行います。
この内容は slime-create-filename-translator
関数で作ると便利です。
:remote-host
には、 ssh で接続する先のホスト名を渡します。 ここでは上の ssh config に書いた "home-xubuntu" にしてます。:machine-instance
は、繋ぐ先の Lisp 処理系で(cl:machine-instance)
を評価した結果の値を書きます。 この値は、ホスト毎、処理系毎に取得し、設定する必要があります。今回は、たまたま "y2q-PC-VK17HBBCD" でした。:username
は、ssh での接続時のユーザ名を渡します。今回は "y2q" にしました。
shell-mode の abbrev に処理系を起こすコマンドを足す
「処理系を立ち上げて swank サーバを起こして待つ」というワンライナーを書いて、 abbrev に仕込みました。
SBCL の場合のコードはこんな感じ:
find ./ ~/quicklisp -name start-swank.lisp -exec nohup sbcl --non-interactive --load {} --eval '(swank::add-hook swank::*connection-closed-hook* (lambda (_) (sb-ext:exit)))' --eval '(cl:sleep most-positive-fixnum)' \\; -quit &
やってることは・・
- slime 付属の
start-swank.lisp
を探して load する。 nohup
つきで起動する。- 接続が切れたら終了してほしいので、
swank::*connection-closed-hook*
に書いておく。 - あとはずっと待つ。 標準出力から EOF を掴むと終了したり、 バックグラウンドプロセスが read 時に入力が空だと SIGTTIN を食らって停止したりするので、
sleep
を入れる。
Allegro だとこんな感じ:
find ./ ~/quicklisp -name start-swank.lisp -exec nohup alisp --batch --backtrace-on-error -L {} -e '(swank::add-hook swank::*connection-closed-hook* (lambda (_) (excl:exit :no-unwind t)))' -e '(cl:sleep most-positive-fixnum)' \\; -quit &
起動手順
emacs tramp-mode の ssh で繋ぐ
M-x dired
に /ssh:y2q@home-xubuntu:~/
渡すなどします。
tramp の remote shell 上で Lisp を起こす
M-x shell
で shell を起こして、上で書いたワンライナーを動かす。
abbrev-mode に入れておけば、以下のように打つだけで済みます。
ralisp C-x '
slime-connect で 繋ぐ
M-x slime-connect
ののち、localhost
4005
として接続します。
細かい点
slime が繋がったらとりあえず current directory を合わせる
処理系の思うディレクトリと、 repl バッファのディレクトリがずれることがあります。
M-x cd
などで合わせましょう。
:username
は、 tramp パスに与えるユーザ名と同じにする
ssh config に USER
を書くと tramp パス上のユーザ名を省略できます。
一方、 slime からファイルを開くと、 slime-create-filename-translator
に :username
で与えたユーザ名を付けてファイルを開きます。
ここで、省略する設定と省略しない設定が混在すると、同じファイルを別の tramp パス名で開いてしまい、大混乱が起きます(起きました)。
まとめ
slime-filename-translations
を解説する記事が少ないので書いてみました。
slime-connect は便利なので使いましょう。