さくらのレンタルサーバーにGHC+Cabalを導入した

環境

  • さくらのレンタルサーバー スタンダード
  • FreeBSD 9.1-RELEASE-p15 (x86_64)
  • もちろんroot権限なし
  • ここでは、シェルはbashを使う(デフォルトはcshだった気がする)
  • ここでは、プレフィックスは $HOME/usr にする($HOME/usr/bin とか $HOME/usr/lib にファイルが入るということ)

1. GHCをインストールする

FreeBSD向けにはHaskell Platformは出ていない。しかしGHCのバイナリは配布されているので、ここからとってくる。この記事を書いている2014年7月6日の時点では、最新バージョンは7.8.2である。

$ curl -O http://www.haskell.org/ghc/dist/7.8.2/ghc-7.8.2-x86_64-portbld-freebsd.tar.xz
$ tar xf ghc-7.8.2-x86_64-portbld-freebsd.tar.xz
$ cd ghc-7.8.2
$ ./configure --prefix=$HOME/usr

この後に gmake install をするのだが、ghc-pkgやghcが使っている共有ライブラリにパスが通っていないので、 LD_LIBRARY_PATH を設定してやる。…なんかもっといい方法があると思う。

$ echo "export LD_LIBRARY_PATH=$HOME/usr/lib/ghc-7.8.2/terminfo-0.4.0.0:$HOME/usr/lib/ghc-7.8.2/bin-package-db-0.0.0.0:$HOME/usr/lib/ghc-7.8.2/binary-0.7.1.0:$HOME/usr/lib/ghc-7.8.2/Cabal-1.18.1.3:$HOME/usr/lib/ghc-7.8.2/process-1.2.0.0:$HOME/usr/lib/ghc-7.8.2/pretty-1.1.1.1:$HOME/usr/lib/ghc-7.8.2/directory-1.2.1.0:$HOME/usr/lib/ghc-7.8.2/unix-2.7.0.1:$HOME/usr/lib/ghc-7.8.2/time-1.4.2:$HOME/usr/lib/ghc-7.8.2/old-locale-1.0.0.6:$HOME/usr/lib/ghc-7.8.2/filepath-1.3.0.2:$HOME/usr/lib/ghc-7.8.2/containers-0.5.5.1:$HOME/usr/lib/ghc-7.8.2/bytestring-0.10.4.0:$HOME/usr/lib/ghc-7.8.2/deepseq-1.3.0.2:$HOME/usr/lib/ghc-7.8.2/deepseq-1.3.0.2:$HOME/usr/lib/ghc-7.8.2/array-0.5.0.0:$HOME/usr/lib/ghc-7.8.2/base-4.7.0.0:$HOME/usr/lib/ghc-7.8.2/integer-gmp-0.5.1.0:$HOME/usr/lib/ghc-7.8.2/ghc-prim-0.3.1.0:$HOME/usr/lib/ghc-7.8.2/rts-1.0:$HOME/usr/lib/ghc-7.8.2/haskeline-0.7.1.2:$HOME/usr/lib/ghc-7.8.2/ghc-7.8.2:$HOME/usr/lib/ghc-7.8.2/transformers-0.3.0.0:$HOME/usr/lib/ghc-7.8.2/template-haskell-2.9.0.0:$HOME/usr/lib/ghc-7.8.2/hpc-0.6.0.1:$HOME/usr/lib/ghc-7.8.2/hoopl-3.10.0.1" > ~/ghc-ld-path.sh
$ source ~/ghc-ld-path.sh
$ gmake install

2. Cabalをインストールする

このへんからCabalのソースコードを落としてくる。

$ curl -O http://www.haskell.org/cabal/release/cabal-install-1.20.0.2/cabal-install-1.20.0.2.tar.gz
$ tar xf cabal-install-1.20.0.2.tar.gz
$ cd cabal-install-1.20.0.2
$ emacs bootstrap.sh

本来なら cabal-install-* の中にある bootstrap.sh を実行すればいいのだが、sedの仕様の違いかなんだか知らないがリンカのコマンドがおかしなことになるので、テキストエディタで bootstrap.sh を編集してリンカを ld に決め打ちしてやる。

LINK=/usr/bin/ld

また、そのままだと tar が /dev/sr0 だかなんだかにアクセスして死ぬので、ググって出てきた情報を元に tar の代わりに tar -f - を使うようにする。これは bootstrap.sh を書き換えなくても環境変数で上書きできる。

あと、Haddockでドキュメントを生成するのがうまくいかなさそうな気配を感じたので、 --no-docをつけてドキュメントを生成しないようにする。

$ TAR="tar -f -" ./bootstrap.sh --no-doc

これでインストールされるはず。

環境変数 PATH がcabalとかを見に行くように、.bash_profile をいじってやる。

$ emacs ~/.bash_profile
export PATH=$HOME/.cabal/bin:$HOME/usr/bin:$PATH

あとは普通にcabalが使える。

$ cabal update
$ cabal install cabal-install

3. せっかくなのでCabalでいろいろインストールしてみる

なんとなくIdrisを入れてみよう!と思った。依存関係がよくわからないが、コマンドとしては

$ cabal install --upgrade-dependencies --force-reinstalls idris

ぐらいでいけるはず。…だが現実はそううまくはいかない。

遭遇した問題としては大きく分けて二つあって、テンポラリディレクトリ /var/tmp 以下で作業してるのがなぜか実行権限が与えられなくてconfigureとかでこけるのと、ソースコード中に非US-ASCII文字が入っていてこけるの。

前者は、テンポラリディレクトリを自前で用意したディレクトリに変えれば良い。つまり ~/tmp 的なディレクトリを作ってやって、環境変数 TMPDIR=~/tmp とすればよい。

後者は、 hGetContents が失敗する的なエラーが出る。

hGetContents: invalid argument (invalid byte sequence)

file コマンドで問題のファイルを見るとUS-ASCIIではなくUTF-8になっているのが分かる。そこで、問題のファイルから非US-ASCII文字を探し出してやって、それをUS-ASCII文字で置き換えてやればファイルがUS-ASCIIになって hGetContents で問題なく読み込める…という方法でビルドしたが、冷静に考えてHaskellはUnicode対応してるはずだし hGetContents でUTF-8を読み込めないのがおかしい。終わった後に気づいたが、おそらく文字エンコーディングが設定されていない的な問題な気がするので、 LANG=en_US.UTF-8 あたりを指定すれば良かった。

結局、

$ mkdir ~/tmp
$ TMPDIR=~/tmp LANG=en_US.UTF-8 cabal install --upgrade-dependencies --force-reinstalls idris

とすれば深いこと考えずにビルドできるはず。

以前やった時はどこかで挫折してしまっていたが、今回は気合いでなんとか頑張った。普段OS X と (Arch) Linux ばかり触っていて、 FreeBSD はよくわからないのだが、まあなんとかなった。

あとはレンタルサーバーの環境にnode.jsが入れば楽しそうなのだが…。

共用サーバーに処理系をいろいろ入れていろいろやりたいというのが間違いで、そういうのがしたいならVPSでも契約しろというのは正論だろう。