y2q_actionman’s ゴミクズチラ裏

内向きのメモ書きを置いてます

リモート 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 経由で接続すれば、自動的にこのポートフォワードがされるようになります。

Emacsslime-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))

Emacsslime-tramp が load されるよう、 slime-contribsslime-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 は便利なので使いましょう。