さくらのレンタルサーバ スタンダードに Haskell 環境を構築する手順


私の使用している「さくらのレンタルサーバ スタンダード」は FreeBSD 9.1-RELEASE-p24 amd64 という環境です。root 権限はないものの、ディスクスペースは 100GB あるので、ここに ghc、cabal-install を導入して、Haskell が動作する環境を整えます。

以下のブログエントリが大変参考になりました。

* [さくらのレンタルサーバーにGHC+Cabalを導入した | 雑記帳](http://d-poppo.nazo.cc/blog/2014/07/ghc-on-rental-server/)


# ghc 導入

結論から言うと、2015 年 12 月時点の最新 ghc-7.10.x は root 権限がないと導入が難しいです。なので今回は ghc-7.8.x 系の最新版である ghc-7.8.4 を導入しました。

`.bash_profile` は以下のようにしておきます。

```.bash_profile
alias cabal='TMPDIR=~/.tmp LANG=en_US.UTF-8 cabal'
export PATH=$HOME/usr/bin:$PATH
export PATH=$HOME/.cabal/bin:$PATH
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/rts-1.0
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/ghc-prim-0.3.1.0
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/integer-gmp-0.5.1.0
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/base-4.7.0.2
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/filepath-1.3.0.2
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/array-0.5.0.0
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/deepseq-1.3.0.2
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/bytestring-0.10.4.0
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/containers-0.5.5.1
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/old-locale-1.0.0.6
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/time-1.4.2
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/unix-2.7.0.1
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/directory-1.2.1.0
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/process-1.2.0.0
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/hpc-0.6.0.1
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/pretty-1.1.1.1
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/template-haskell-2.9.0.0
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/Cabal-1.18.1.5
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/binary-0.7.1.0
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/bin-package-db-0.0.0.0
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/hoopl-3.10.0.1
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/transformers-0.3.0.0
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/xhtml-3000.2.1
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/terminfo-0.4.0.0
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/haskeline-0.7.1.2
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/ghc-7.8.4
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/old-time-1.1.0.2
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/haskell98-2.0.0.3
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/${HOME}/usr/lib/ghc-7.8.4/haskell2010-1.1.2.0
```

cabal の alias を指定しています。cabal がパッケージをビルドする際に、デフォルトで `/var/tmp` が使用されるのですが、これが時々以下のようなエラーを吐きます。

```bash
$ cabal install --only-dependencies
...(snip)
checking whether we are cross compiling... configure: error: in `/var/tmp/cabal-tmp-8769/network-2.6.2.1':
...(snip)
cabal: Error: some packages failed to install:
network-2.6.2.1 failed during the configure step. The exception was:
ExitFailure 1
```

これを `$HOME/.tmp` を指定することで回避しています。

ghc のインストール先は `$HOME/usr` に指定するのですが、ghc ビルド時にライブラリが見つからないというエラーを、上記のように `LD_LIBRARY_PATH` を指定しておくことで回避します。ついでに ghc と cabal のインストール先にも PATH を通しておきます。

もし、ghc や cabal を何度か導入しようとして挫折したことがある場合、`.ghc` や `.cabal` が存在するかも知れません。これらは消しておかないとトラブルの元になる可能性があります。

```bash
$ rm -rf ~/.ghc ~/.cabal
```

環境がきれいになったところで ghc を以下のようにインストールします。

```bash
$ wget -c --no-check-certificate https://www.haskell.org/ghc/dist/7.8.4/ghc-7.8.4-x86_64-portbld-freebsd.tar.xz
$ tar xf ghc-7.8.4-x86_64-portbld-freebsd.tar.xz
$ cd ghc-7.8.4
$ ./configure --prefix=$HOME/usr
$ gmake install
```

これで ghc が使用できるようになります。

```bash
$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 7.8.4
```

簡単なコードならコンパイルして実行することも可能です。

```bash
$ echo 'main = putStrLn "hello"' > hello.hs
$ ghc hello.hs
[1 of 1] Compiling Main             ( hello.hs, hello.o )
Linking hello ...
$ ./hello 
hello
```

# cabal-install の導入

ghc だけでは何もできないので、cabal-install を導入します。cabal-install は最新の 1.22.6.0 が導入できました。

```bash
$ curl -O http://hackage.haskell.org/package/cabal-install-1.22.6.0/cabal-install-1.22.6.0.tar.gz
$ tar xf cabal-install-1.22.6.0.tar.gz
$ cd cabal-install-1.22.6.0
$ vi bootstrap.sh
```

`bootstrap.sh` を実行する前に、以下のように修正する必要があります。

```diff
+ LINK=/usr/bin/ld
+ #LINK="$(for link in collect2 ld; do
+ #  echo 'main;' | ${CC} -v -x c - -o /dev/null -\#\#\# 2>&1 | grep -qw $link &&
+ #  echo 'main;' | ${CC} -v -x c - -o /dev/null -\#\#\# 2>&1 | grep -w  $link |
+ #  sed -e "s|\(.*$link\).*|\1|" -e 's/ //g' -e 's|"||' && break
+ #done)"
- LINK="$(for link in collect2 ld; do
-   echo 'main;' | ${CC} -v -x c - -o /dev/null -\#\#\# 2>&1 | grep -qw $link &&
-   echo 'main;' | ${CC} -v -x c - -o /dev/null -\#\#\# 2>&1 | grep -w  $link |
-   sed -e "s|\(.*$link\).*|\1|" -e 's/ //g' -e 's|"||' && break
- done)"
```

要するに環境から適切な ld コマンドを探しだしている部分を、`LINK=/usr/bin/ld` と決め打ちにしています。これを行わないと、`'/usr/bin/ld""--eh-frame-hdr""-V""-dynamic-linker""/libexec/ld' does not refer` という不可解な結果が `LINK` に入ってしまい、スクリプトがこけます。

修正を行ったら、以下のように実行します。

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

結構時間がかかりますが、お茶でも飲みながら待ちます。

```bash
$ cabal --version
cabal-install version 1.22.6.0
using version 1.22.4.0 of the Cabal library
```

# コードを書く

こんな感じで始めます。

```bash
$ mkdir foo
$ cd foo
$ cabal sandbox init
$ cabal init
```

最近は `cabal` よりも `stack` を使うのが主流になってきているようですが、`stack` は動向が激しいので、落ち着くまでは枯れた `cabal` を使用します。

# 補足

2018 年 10 月に確認したところ、[Stack の FreeBSD 版バイナリ](https://docs.haskellstack.org/en/stable/install_and_upgrade/#freebsd) が公開されていたため、こちらを動作させることができないか検証してみましたが無理でした。

1. 必要なライブラリが多数存在しない（ライブラリを個別にビルドすればできなくはない）
1. FreeBSD 9.1 に存在しないシステムコールを使用している

いくつかの足りないライブラリを解決していき、引数なしの `stack` コマンドが動作するようにはなったものの、`stack setup` を実行すると「存在しないシステムコール: 12」というエラーメッセージが表示されてしまい、お手上げでした。Stack のサイトにも FreeBSD 11 以降と記載さてているため、システム構成が古いさくらのレンタルサーバでは GHC 7.8.4 を Cabal で運用するのが限界そうです。