WindowsでEmacsのClojure開発環境を立ち上げる

Windowsで最低限のEmacs+Clojureの開発環境を立ち上げる手順を書いてみました。

対象読者は、あやふやです。なんとなくEmacsClojureもやったことがある、ぐらいな感じ。

ちなみに全般的にWindowsでこの手のUnix世界に塗れたものを開発するのは地獄なので、LinuxOS Xという選択肢を選べる人は素直にそちらを選んだほうがいいでしょう。

まずはChocolateyを入れる

今や常識、Windowsのパッケージ管理ツール、Chocolatey(https://chocolatey.org/)を入れましょう。

そこまでこだわりのないパッケージであればChocolatey経由でインストールしたものでまかなえます。

基本的なツールを入れる

curlwget を入れておきましょう。

choco install curl wget

MsysGit(https://msysgit.github.io/)もChocolatey経由じゃなくてもいいですが、入れておきましょう。Chocolateyでは以下。

choco install git

Clojureの実行環境を作る

http://leiningen-win-installer.djpowell.net/ というのもあるみたいですが、使いません。

まずはJDK8をインストール。

choco install jdk8

次にLeiningen(Clojureのビルド兼実行ツール)をインストール。leiningenのインストール時、お呼びでないJDK7も入れようとするので -ignoreDependencies を指定しておきます。

choco install lein -ignoreDependencies

このままだと多分Leiningenが古いので、仕上げに下記コマンドを打っておきましょう。

lein upgrade
lein self-install

JDKもLeiningen自分で入れるんじゃーい!と思った方は、OracleからJDKダウンロードしてインストールして、Leiningenも公式サイト(http://leiningen.org/)からlein.batをダウンロードしてパスを通せばOKです。

最後に下のコマンドでREPLに入れればOKです。

lein repl

Emacsを入れる

EmacsはEmacs24以上を使います。色々Windows用にビルドはあるのですが、それぞれ長所短所があり、決定打というものがありません。

今回はemacs-w64(Windows x64用のEmacs25)を使いたいと思います。おそらく、日本語入力は辛いと思うので日本語は使わない想定で… (改行コードの扱いもあやしい気がするが…)

普通に解凍して、 bin フォルダにパスを通します。起動時は runemacs.exe を使うといいでしょう。

EmacsClojureを開発できる環境を作る(Caskを入れる)

Emacsといえばその拡張性の高さが有名ですが、拡張性が高いだけで最近までいい拡張の管理方法がありませんでした。

しかし今どきはCask(https://github.com/cask/cask)というツールがあり、これにパッケージ依存性を書いたファイルを食べさせると自動でEmacsにパッケージをインストールしてくれます。

基本的にCaskはUnix上じゃないとどうも怪しい動きをしているのですが、Windowsで使えないことはありません。インストールしてみましょう。

まず、Caskの動作のためにChocolateyでPython2を入れます。残念ながらPython3は不可です。

choco install python2

(Python3と同居させたい人には、pyenvというものがWindows以外ならありますが、 https://github.com/yyuu/pyenv/issues/62Windowsだとどうすればいいんでしょうね…)

次に公式サイトに載っているコマンド(http://cask.readthedocs.org/en/latest/guide/installation.html#manual-installation)でCaskをインストールします。

curl -fsSL https://raw.githubusercontent.com/cask/cask/master/go | python

上記コマンドで %userprofile%\.cask\bincask および cask.bat が用意されます。( %HOME% 変数を定義している人は %userprofile% のかわりに、そこを探しましょう) この bin フォルダにパスを通しておきましょう。

その状態で、 %userprofile%\.emacs.d フォルダ(なければ作成)上で下記コマンドを実行し、Caskの初期ファイルを作成します。

cask init

上記コマンドで出来た Cask ファイルに下記内容を追記しましょう。Emacsでcider(Clojureの開発用)とparedit(Lispのカッコ編集用)という拡張に依存するという内容です。

(depends-on "cider")
(depends-on "paredit")

そのまま同じフォルダでCaskに依存している拡張を .emacs.d フォルダ内にインストールさせます。

cask install

なんかこのコマンド、Windows上だと一瞬で終了しちゃいますが、非同期で結果がバカバカ吐かれるので、ちょっと待ちましょう。

(この際、Emacs24から使えるGnuTLSのサポートが無いEmacs(公式配布とか)を使っていると、Caskに文句言われます。)

上記インストールが終わったら、今度は %userprofile%\.emacs.d\init.el (Emacsが起動時に読むユーザーカスタマイズ用のファイル) に下記内容を追記します。

(add-to-list 'load-path "~/.cask")

(require 'cask)
(cask-initialize)

(show-paren-mode 1)

(require 'paredit)
(add-hook 'emacs-lisp-mode-hook #'enable-paredit-mode)

(require 'cider)
(add-hook 'clojure-mode-hook #'enable-paredit-mode)
(add-hook 'cider-repl-mode-hook #'enable-paredit-mode)

追記が終わったら、 runemacs.exe を実行してみましょう。エラーなく起動すればOKです。

試しに、Clojureのプロジェクトを作ってみる

簡単なClojureのプロジェクトを作成してREPLを開いてみましょう。

どっか作業用のフォルダ上で、下記コマンドを打ち、Clojure開発用の空のプロジェクト(my-test)を作成します。

lein new my-test

できた my-test フォルダ内の project.clj ファイルを開いて、 C-c M-jキーを押せばプロジェクトに対応したClojureのREPLを立ち上げることができます。

src フォルダの中にひな形のソースファイルが入っているので C-x C-e(カーソルの前の式を評価) などを使ってREPLに投げて遊んだりしましょう。

EmacsのCIDERとLeiningenのCIDERのバージョンが合わないエラー

EmacsのCaskで入れたEmacs側のCIDERのバージョンと、LeiningenがダウンロードしたJava側のCIDER(cider-nrepl)のJARのバージョンがあってねえよと文句言われることが多々あると思います。

CIDER's version (0.8.2-snapshot) does not match cider-nrepl's version (0.8.1)

ちゃんとLeiningenが持ってくるJava側のcider-nreplのバージョンをEmacsのCIDERにあわせてあげましょう。

LeiningenのユーザごとのプロファイルにCIDERのバージョンを指定してあげます。下記のいずれかのファイルを編集します。

  • %LEIN_HOME% を定義済みならば %LEIN_HOME%\profiles.clj
  • それ以外の場合は、 %userprofile%\.lein\profiles.clj ( 多分%HOME%は見てないかも )

ファイルに下記内容を書きます。

{:user
 {:plugins [[cider/cider-nrepl "0.8.2-SNAPSHOT"]]}} ; ←ここをEmacs側のバージョンにあうように変更しましょう!

ちょっと管理上よろしくないですが、上記のプラグインの設定を各プロジェクトの project.clj:plugins に追記してもいいです。

試しに Clojure+ClojureScript (+Facebook ReactのラッパーのOm) のプロジェクトを作ってみる

ちょっとだけ背伸びをしてみましょう。プロジェクトテンプレートとして、plexus/chestnut(https://github.com/plexus/chestnut)を使います。

どっか作業用のフォルダ上で、下記コマンドを打ち、ClojureScriptを開発する雛形のプロジェクト(my-test)を作成します。

lein new chestnut my-test

その中の project.clj ファイルをEmacsで開いて C-c M-j キーを押してプロジェクトに対応したClojureのREPLを立ち上げます。

REPLはデフォルトの名前空間( my-test.server )で起動していると思いますが、そこで (run) 関数を起動してWebサーバを起動します。

; CIDER 0.8.2snapshot (package: 20141130.803) (Java 1.8.0_25, Clojure 1.6.0, nREPL 0.2.6)
my-test.server> (run)
Starting figwheel.
Starting web server on port 10555 .
#<Server org.eclipse.jetty.server.Server@e7a73f8>
my-test.server> Compiling ClojureScript.
Figwheel: Starting server at http://localhost:3449
Figwheel: Serving files from '(dev-resources|resources)/public'
Compiling "resources/public/js/app.js" from ("src/cljs" "env/dev/cljs")...
WARNING: Use of undeclared Var cljs.core.async/do-alts at line 62 file:/C:/Users/owner/.m2/repository/org/clojure/core.async/0.1.278.0-76b25b-alpha/core.async-0.1.278.0-76b25b-alpha.jar!/cljs/core/async/impl/ioc_helpers.cljs
WARNING: Bad method signature in protocol implementation, impl/Handler does not declare method called lock-id at line 214 file:/C:/Users/owner/.m2/repository/org/clojure/core.async/0.1.278.0-76b25b-alpha/core.async-0.1.278.0-76b25b-alpha.jar!/cljs/core/async.cljs
WARNING: Use of undeclared Var cljs.core.async.impl.protocols/lock-id at line 217 file:/C:/Users/owner/.m2/repository/org/clojure/core.async/0.1.278.0-76b25b-alpha/core.async-0.1.278.0-76b25b-alpha.jar!/cljs/core/async.cljs
WARNING: Bad method signature in protocol implementation, impl/Handler does not declare method called lock-id at line 214 resources\public\js\out\cljs\core\async.cljs
WARNING: Use of undeclared Var cljs.core.async.impl.protocols/lock-id at line 217 resources\public\js\out\cljs\core\async.cljs
Successfully compiled "resources/public/js/app.js" in 13.856 seconds.
notifying browser that file changed:  /js/app.js
notifying browser that file changed:  /js/out/goog/deps.js
notifying browser that file changed:  /js/out/my_test/dev.js
notifying browser that file changed:  /js/out/my_test/core.js

上記出力が終わったら http://localhost:10555 を見ればClojureで立ち上がったWebサーバ上が見えると思います。この時のサーバのページの表示はClojureScriptで行われています。

今度はClojureScriptをいじってみましょう。REPL上で

(browser-repl)

でClojureScriptのREPLを起動してみましょう。これにより cljs.user 名前空間に切り替わるので、REPL上で

(js/alert "Hello!")

とか打ってみましょう。ちゃんとブラウザ上でalertが出たのが見えるでしょうか。

つづいて、Om(React)らしく、JS上のモデルを書き換えてページのDOMが書き換わるのを観察してみましょう。

src/cljs/my_test/core.cljs を開いて参考にしつつ、ファイルに下記式を書いて評価( C-x C-e)してみましょう。

(reset! app-state {:text "Goodbye Chestnut!"})

シームレスにブラウザ上のDOMがリレンダされたのがわかるでしょうか。

このまま Omのチュートリアル(https://github.com/swannodette/om/wiki/Basic-Tutorial)にすすんでみましょう。

公式チュートリアルはLightTable前提ですが、Emacsでもやっていけるはずです。