Emacs+SLIMEでCommon Lispの開発をリモートでするまとめ

ディープラーニングなどの重い処理を含むプログラムを出先から開発したいというときがよくある。
そういうときまずやるのが、SSHGPUを積んだ開発マシンにリモートログインしてターミナル上でEmacs/Vimで開発するというやり方だが、LTEで速くなったとはいえ入力の反映がもたつくことがよくあり、非常にストレスが溜まる。moshも使ってみたが大して差は感じられなかった。その他にもCtrlとMeta以外のモディファイアキーを使いたいなど、やっぱりGUI版のEmacsで開発したいと思うことがよくある。
SLIMEはLisp処理系側で動くSwankと呼ばれるサーバと、それに接続するEmacs側フロントエンドの機能で構成されている。このサーバとクライアントの通信はローカルネットワークに限らないので、リモートからLisp処理系に接続することもできるのだ。知らないけど同じSwankクライアントであるslimv.vimatom-slimeでも原理的にはできるはずである。

1. SSHでSwankのポートをポートフォワーディングして開発マシンに接続する

ホストの設定は~/.ssh/configでしておく。

Host myhost
    HostName xxx.yyy.com
    Port 22
    User hoge
    identityfile ~/.ssh/myhost_rsa

開発マシンの4005番をローカル(出先マシン)の4005番に繋げるには、

hoge@local$ ssh -L 4005:localhost:4005 myhost

2. 開発マシンでSwankサーバを立ち上げる

接続が切れても再開できるようにscreen上でLisp処理系を立ち上げる。

hoge@remote$ screen -S swank ros -Q -L sbcl-bin dynamic-space-size=4096

3. Swankサーバを起動する

(require :swank)
(swank:create-server :port 4005)

これでサーバの4005番をSSH経由でローカルの4005番に繋げられた。もちろんポート番号は自由に設定できる。

4. ポートフォワーディングしたローカルのポートに対してslime-connectする。

SLIMEをインストール済のEmacsを起動して、 M-x slime-connect RET RET RETlocalhost:4005に接続して開発マシンのREPLがローカルのEmacs上に現われる。この時、「ローカルのSLIMEとリモートのSwankサーバのバージョンが違うけど大丈夫?」というプロンプトが出ることがある。これが邪魔なときは.emacsに以下のように書いておく。

(setq slime-protocol-version 'ignore)

一連のコマンドをまとめる

ややこしいので2、3のコマンドで済むようにしておく。まずローカルの~/.bashrcなどにエイリアスを書いておく。

alias ssh-swank='ssh -L 4005:localhost:4005 myhost'

次に3.のSwankサーバを起動するLispコードをファイルに保存して開発マシンの~/swank-start.lispに置いておく。それから開発マシンの~/.bashrcなどに処理系を起動してSwank起動コードを読み込むためのエイリアスを書く。

alias swank-start="screen -S swank ros -Q -L sbcl-bin dynamic-space-size=4096 run -l $HOME/swank-start.lisp"

なお、sshで接続すると~/.bashrcを読まないらしいので、~/.bash_profile に~/.bashrcを読むように書いておく。

if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi

これでターミナルからssh-swank、パスフレーズ入力、swank-start、Emacs起動、M-x slime-connect RET RET RETでREPLが立ち上がる。

TRAMPでリモートのファイルを編集する

リモートのファイルを編集するにはEmacsに標準搭載されているTRAMPが使える。 ~/.emacs にこう書いておく。

(require 'tramp)
(setq tramp-default-method "scp")
(setq tramp-auto-save-directory "/tmp")

オートセーブの度にリモートと通信しようとしてEmacsが止まるので、オートセーブファイルはローカルの/tmpに保存するようにしておく。これで単にC-x C-f /ssh:myhost:~/file.lisp RET などとすることによりリモートのファイルを開ける。

magitも動く!

驚くべきことにtrampでリモートのファイルを開いた状態でM-x magit-statusすると普通にmagitが使えるし、コミットもプッシュもできることに気付く。ただし通信が発生するので多少待たされはする。

まとめ

  • サーバ側でSwankサーバを立てておくことにより出先からEmacs+SLIMEでリモート開発できる
    • 出先のノートPCで重い処理を回してもCPU使用率が最低レベルなのでバッテリーも長持ち
    • ローカル/リモートに関わらずLisp式単位で開発マシンのREPLで評価できる
  • リモートのファイルの編集はEmacsの機能TRAMPによりできる
    • magitもリモートでできる
    • ローカルのEmacsの編集機能がそのまま使えるためにキビキビ動く。低速回線でもストレスがない。