Emacs で IPC や RPC (Emacs Advent Calendar jp: 2011)

Emacs Advent Calendar jp: 2011 : ATND 6日目の記事のはずでしたが、手違いでかぶってしまい、いろいろあって遅くなってしまいました。
皆様、乱してしまってすみません。

今回の記事では、EmacsでのIPC(Inter-Process Communication)やRPC(Remote Procedure Call)の方法について、自分の知っている範囲でまとめてみます。IPCは、プログラムの間で通信する仕組みです。RPCは、既に起動しているプログラムの一部(関数やサブルーチン)を別のプログラムから呼び出す仕組みです。一般的にIPCの枠にRPCが含まれます。

EmacsにはどんなIPC/RPCの実現方法があるのか、実際の応用例などを5分程度で簡単にまとめてみます。

Emacsの標準IPC手段

以下のようなものがあります。(Emacs 23 以上の場合)

ひと通り揃っていて、大体色々出来ますし、D-Bus以外はプラットフォーム中立の事を考えて作られています。

しかしながら、本格的なプログラミング環境としては細かい制御が出来ず、悔しい思いをすることが多いです。特に、共有ライブラリにリンクして、高機能・高パフォーマンスな通信手段(DB直接続とかmsgpackとか)を使うことが出来ません。

そのため、一般的には別の中継プログラムを作成して、パイプなどで通信してやりたい機能を実現するということが多いです。このあたりの歴史や状況については、 id:m2ym さんの文書 http://cx4a.org/pub/emacs-is-dead.ja.html が詳しいです。*1

IPC/RPC いろいろ

Emacsで行われている IPC/RPC の手段について簡単に紹介してみます。

コマンド起動

プログラムを起動し、結果を標準出力などからテキスト等で受け取る方式です。
同期的に呼べば簡単に使えますし、外部プログラムだけでデバッグもできるので楽です。
一方で、外部プログラムや設定がOSや環境に依存して動かないこともあります。が、他の方法よりもはるかに問題解決が楽です。

  • 例
    • Wanderlust から bogofilter, bsfilter など
      • 文字列からスパム判定
    • GCCSense
      • C/C++などの補完、定義ジャンプなど
    • rsense
      • Rubyの型推論による補完、定義ジャンプなど
      • 別にサーバーが動く
    • flymake
      • 非同期で実行、通信はしてなくて結果を受け取るだけ
      • バックグラウンドでコンパイル → エラー表示
    • その他にもたくさんある
パイプ・ソケット

バックグラウンドで外部プログラムを起動し、パイプやソケットなどで通信する方法です。
非同期プログラミングが大変ですが、常に起動しているため応答の性能も良く、また外部プログラム側も状態を持つことができるので、出来ることが大幅に増えます。

(2011/12/09 TCPソケットのところにパイプ通信が混じっていたのを修正)

D-Bus

D-Bus は Linux Desktop 上ではかなりデファクトに近いIPC環境になっています。

1対1の通信だけではなく、必要なプロセスにイベント通知させたり、オブジェクトのシリアライズ、サービスのインスペクションなども出来るため、IPCとしてはかなり高機能です。

skype.el でも使っていますが、これを積極的に利用したアプリケーションはほとんど無く、正直 D-Bus をEmacsでサポートする必要はなかった(もっと他にやることがあった?)のではないかとか思っています。

emacsclient

起動中のEmacsにファイルをオープンさせるような用途が圧倒的ですが、S式を送り込んで評価させたり出来るため、手軽なRPCとして利用できます。

HTTP / Webサービス

最近はインターネット上のサービスと通信する機会が多くなってきました。REST APIに直接アクセスしたり、XML-RPCなどで機能を手軽に呼び出すことが出来ます。

xml-rpc.el のように、標準のurlパッケージを使ってEmacs単独で通信することも出来ますが、るびきちさんも指摘する通り、細かいバグやSSL・プロキシ経由の通信で問題があるので、自前実装する場合は curl, wget を使う方が堅実だと思います。

Webサービスと通信する場合に問題になるのは認証です。一般的に以下の方法があります。

  • OAuth
    • Webアプリ向けの OAuth を実装する方法、コスト高い
    • Twitterクライアントとかだと必須
  • API key
    • ユーザーごとにAPIアクセスキーを発行し、これをリクエストパラメーターに入れて使う方法
    • クライアント向け、実装が簡単
      • cacoo.el とか
  • HTTPセッション Cookie
  • BASIC認証
    • ユーザーに認証情報を入れてもらう
    • パスワードやユーザー情報を wget などに渡す必要がある

今後、Webサービスとの通信は増えてくると思いますので、この辺りの環境が整備されてくると便利になりそうです。

EPC に続く

これまでのIPC/RPCはプリミティブすぎる(パイプとかD-Busとか)か、特定の目的のための専用スタック(pymacsとかel4rとか)なので、別のプログラムを気軽に呼び出して使えるような、汎用のRPCスタックがありません。

例えば、EmacsはDBに直接接続することが出来ませんが、DBに接続して自由にSQLを発行してデータをやり取りできると、大変夢が広がります。さらに、これがPythonやRubyなどの専用スタックではなく、インタフェースは固定のまま、自分の好きな言語で拡張できると大変素敵です。

ということで、現在 EPC(Emacs Procedure Call)なるものをつくっています。YAPC Asia 2011の時にデモしたような、EmacsからPerlを自由に呼んでやりたい放題なことを実現できるようにする予定です。

Emacs - Perl 間はだいたい動くのですが、いきなり CPAN に上げる前に PrePAN でレビューをお願いしたいと思っています。

プロトコルの詳細などのドキュメントが固まり次第、お知らせする予定です。

おわり

本当にすみません。Advent Calendar は小粒なネタで毎日続けることが重要だと思いました。来年も参加するときは気をつけようと思います。

やっぱり1時間ぐらいかかりました。

*1:ちなみに、自分も Emacs 自体が単純に肥大化していくことにはちょっと違和感があります。単純に機能が増えるよりも、パッケージや汎用的な通信手段で簡単に拡張できることに集中したほうがいいと思っています。