Just $ A sandbox

プログラミングと計算機科学とかわいさ

Yes, Yesod!

abstract: this article shows how to install and run Yesod, a famous Haskell web framework for its simplicity to use and its difficulty to install. I wrote how I did it for whoever wants to install Yesod, and for myself.

Yesodのインストールにまる1日かかりましたが何とか上手くいったので、その方法をまとめておきます。

はじめに

ご存知の通り、YesodHaskellで書かれたwebフレームワークです。初心者にとって比較的扱いやすい反面、インストールまでが修羅の道ということで非常に有名ですね。
今回はその悪名高いYesodの環境構築方法をまとめました。

さてYesodのインストールがなぜそんなに鬼門かということですが、基本的にはそれが依存関係との戦いになるからです。歴戦のHaskellerほどたくさんの野良パッケージを入れており、依存関係がぐちゃぐちゃになっているためYesodのような莫大な数と種類のパッケージを扱うツールだとどれかで依存関係が上手く解消できずにコケることになるからです。
よって、「Haskell platformをつい最近入れたばかりで変なパッケージを入れたりましてや--force-reinstallsなんてしたこともない!」という人はあまり問題にはならないと思います。むしろいろんなパッケージを好き放題入れて、そのたびに--force-reinstallsを気軽にする(私のような)人ほど厄介なエラーに悩まされると思います。

という訳で依存関係がぐちゃぐちゃだという自覚がある人は最初から3のようにクリーンインストールした方がいいかもしれません。時間もかかるし面倒ですが確実だと思います。
とにかく、どうかみなさんが、1or2の方法で上手く行かれますよう祈っております。

動作環境

Haskell-platformは事前にインストールされているものとします。

# OS: ubuntu 12.04 (+ Xfce)

$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 7.4.1
$ cabal --version
cabal-install version 0.14.0
using version 1.14.0 of the Cabal library 

1.cabalだけでそのまま入れる方法

公式にも紹介されている方法です。

$ cabal install yesod-platform
# インストールのために大量のパッケージがインストールされる

$ yesod init
# 分からなければProject nameは"Test"を入力し次はSQLiteを選べばよいでしょう

$ cd [Project name]
$ cabal install --only-dependencies # どうやら最初だけはこうしておいたほうが良いらしいです
$ yesod devel # 場合によっては $ yesod --dev devel
# http://localhost:3000 にブラウザでアクセス!

以上です!
この方法で上手く行ったあなたは非常に幸運な人か、Haskellに普段あまり触れない人でしょう。幸運を噛み締めながらどうぞYesodとHaskellの勉強を楽しんでください。

この記事はもちろん上で上手く行かない人向けなのでこれでダメだったら次に進みましょう。
私はここで「'yesod-ghc-wrapper'が見つからない」というエラーに遭遇しました。

2.cabal-devを導入する方法

追記: 最新のcabalではcabal sandboxという機能が追加されているのでそちらを使ってください。yesodの公式ドキュメントでもcabal sandboxを使ったビルドが推奨されています。

cabal-devを導入したら上手く行った事例(cabal の使い方 - melpon日記 - HaskellもC++もまともに扱えないへたれのページとかyesod - http://localhost:3000 表示まで - 335gのブログ)もあります。
cabal-devを使えば必要なパッケージを一旦別のフォルダで0から全てインストールして、必要なパッケージを新たにインストールしたもののみを参照しながら走らせることができます。予めインストールされているパッケージを使わないので依存関係のエラーはかなり出にくくなります*1

また、cabalではできない「インストールしたパッケージを削除する」こともできるので、cabalの代わりとしてパッケージ管理で使っている人もいるみたいですね。

$ git clone git://github.com/creswick/cabal-dev.git
$ cd cabal-dev
$ cabal update
$ cabal install

でcabal-devのインストールは終わります(cabal install cabal-devでも入るんですがこれはよくないという報告がされているのでソースからビルドしたほうが安全でしょう)。

そして

$ cabal-dev install --sandbox=~/cabal-dev/yesod
# sandboxにはyesodを入れておくためのフォルダを指定します。`~/cabal-dev`の下とかが推奨ですね

$ ~/cabal-dev/yesod/bin/yesod init
# yesod initします。指定したフォルダの下のbinに入っていると思いますが、面倒であればexportでPATHに追加しておいた方が良いかもしれませんね

$ cd [Project name]
$ cabal-dev install
$ ~/cabal-dev/bin/yesod --dev devel

とすれば上手く行く…んじゃないでしょうか多分。
私は変数が多重定義されています、みたいなエラーが出ていた気がします。

3.クリーンインストール後速攻でYesodをインストール

おそらく一番確実ですが時間もかかるし何より今までインストールしたパッケージが全て吹き飛ぶので多少の覚悟が必要です(ghc-pkg listとして今までインストールしたパッケージの一覧が出るのでこれをメモっておいてあとで復元してください)。
ただし私はこれ(とあといくつかのエラーが出ましたが無事に解消して)で上手くできたので、上手く行かない場合は最後の手段としてお試しください。

まずはghc, cabalをアンインストールします。

$ sudo apt-get remove ghc
$ sudo apt-get remove cabal

そしてインストールしたパッケージを全て削除します。
基本的なやり方はHaskellのパッケージ管理システムCabalでinstallしたものをデリート(in Ubuntu) | 雑記帳に沿っています。

$ rm -rf ~/.cabal/
$ sudo rm -rf /usr/local/lib/[パッケージ名] # 独立して入れたものとかがあれば個別に消します
$ sudo rm -rf /usr/local/bin/[パッケージ名]
$ rm -rf /var/lib/ghc-7.0.3/package.conf.d/

さて、これで依存関係のめちゃくちゃなパッケージ群は全て消滅しました。あとは1.のようにインストールを行います。

$ cabal install yesod-platform
$ yesod init
$ cd [Project name]
$ cabal install --only-dependencies
$ yesod devel

私はここでも依存関係が解消できないみたいなエラーを頂きましたが、以下のケーススタディのようにしたら上手く行ったので参考にしてください。

番外編:cabal-devの代わりにvirthualenv

virthualenvというのを使ったら上手く行った、という事例(Haskell Platformをアンインストールして綺麗な環境を取り戻すとかhttp://d.hatena.ne.jp/littlefive/20130101/1357008588)も報告されていますが、私の環境では上手く行きませんでした。
cabal-devみたいな感じで使えるツールじゃないかと睨んでいますが詳しくは調べていないのでよく分かりません。

$ cabal install virthualenv
$ virthualenv
$ source ~/.virthualenv/bin/activate
$ cabal install yesod-platform

とすると、deactivateするまではこのフォルダ内のパッケージを参照してインストールができるらしいです。

ケーススタディ

'ghc'か'yesod-ghc-wrapper'が見つからない

$ yesod devel
Yesod devel server. Press ENTER to quit
Configuring Test-0.0.0...
yesod: user error (Cannot find the program 'ghc' at 'yesod-ghc-wrapper' or on the path)

私の環境では1.を実行した後にこのエラーに遭遇しました。
内容としてはghc, yesod-ghc-wrapperが見つからないというものです。

まず、PATHが正しく通っているかを確認しましょう。ubuntuでなら

$ echo $PATH
/usr/lib/...

と出てくると思いますが、'ghc'と'yesod-ghc-wrapper'のパスが含まれていることを確認してください。'yesod-ghc-wrapper'の方はcabalで入れれば~/.cabal/binとかになると思います。
正しくPATHが通っていなければexportで通してください。

また、~/.cabal/binを/home/username/.cabal/binに変えるとエラーメッセージが変わる事例も報告されているので参考までに。

変数が多重定義されている

GHCi runtime linker: fatal error: I found a duplicate definition for symbol
   ...
whilst processing object file
   /home/... # 私はbytestringで言われてました
This could be caused by:
   * Loading two different object files which export the same symbol
   * Specifying the same object file twice on the GHCi command line
   * An incorrect `package.conf' entry, causing some object to be
     loaded twice.

StackOverflowで同じエラーが出る事例は見つけましたがこちらはYesodインストールでコケたわけではないのであまり参考にはならないかもしれません。
この場合、PATHで同じ場所が複数指定されていないかどうかを確認してください。
どうしても解決しない場合は、残念ですがておくれなので3.の方法をお試しください。。。

依存関係が解消できない(と言ってたくさんのパッケージが出てくる)

$ yesod devel
Yesod devel server. Press ENTER to quit
Resolving dependencies...
Configuring testYesod-0.0.0...
cabal: At least the following dependencies are missing:
data-default -any,
hamlet ==1.1.*,
hjsmin ==0.1.*,
http-conduit >=1.5 && <1.7,
monad-control ==0.3.*,
persistent ==1.0.*,
persistent-sqlite ==1.0.*,
shakespeare-css ==1.0.*,
shakespeare-js ==1.0.*,
shakespeare-text ==1.0.*,
wai-extra ==1.3.*,
warp ==1.3.*,
yaml ==0.8.*,
yesod ==1.1.*,
yesod-auth ==1.1.*,
yesod-core >=1.1.2 && <1.2,
yesod-default ==1.1.*,
yesod-form ==1.1.*,
yesod-static ==1.1.*,
yesod-test ==0.3.*

みたいなエラーが出る時があります。StackOverflowに似た事例が報告されています。

参照しているパッケージの依存関係がおかしいので、cabal-devなどでsandboxを指定して全て入れなおす、などの方法をお勧めします(もしくは全て手動で入れなおすでも可)。
もしもすでにcabal-devを使っていてこのエラーが出た場合、cabal-devで指定したsandboxのPATHを正しく参照しているかどうかを確認してください。

language-javascriptでコケる

Registering yesod-1.1.8...
cabal: Error: some packages failed to install:
Test-0.0.0 depends on language-javascript-0.5.7 which failed to install.
hjsmin-0.1.4 depends on language-javascript-0.5.7 which failed to install.
language-javascript-0.5.7 failed during the configure step. The exception was:
ExitFailure 1

みたいな感じでlanguage-javascriptでコケる場合です。

このエラーは割と有名なようで、いくつか似た事例(yesod0.10をいれてcabal installしたらコケた問題 - プログラミングお勉強きろくとかProblems while installing language-javascript and yesod - WILT)を発見することが出来ました。

結論から言うとlanguage-javascriptかその界隈を適当にインストールしなおせば上手く行くことが多いようです。

# 以下を適当に試す
$ cabal install language-javascript
$ cabal install alex
$ cabal install happy
$ cabal install hjsmin

また、私の場合はyesod周りのパッケージをcabal-devで入れた時にそっち側にパスが通っていなかったことが原因でこのエラーになりました。cabal-devを使う場合は必ずalex,happyなどが入っているフォルダにパスを通してください。

まとめ

色々書いてありますが、実際私はこれを全て試して(ケーススタディも全て実際に遭遇したエラーです)やっとYesodが動く環境を得たわけで、まさに闇*2としか言いようがありません。
しかしYesod自体は本当に素晴らしいフレームワークですので、この私の山のようなトライアンドエラーを是非参考に、Yesodを動かしてみて欲しいと思います。

(というかどこを探してもここまで失敗しまくっている事例は発見出来なかったのですが、私はもしかしてやばいものに引っかかりすぎてるんでしょうか…?><)

参考文献

*1:それでも上手く行かなかった私の話はやめてください!!!

*2:Haskellは光の言語なのに!