(deprecated) hsenv.shを使って複数バージョンのghcをインストール

**deprecated: この記事の内容はもう古くなっていて役に立ちません。代わりに [stack](https://github.com/commercialhaskell/stack) を利用してください。**


haskell(ghc)でも、複数のバージョンのghcで動くライブラリを書きたかったり業務で使うことになるとrbenvみたいに複数バージョンをわけてインストールしたくなることがあると思います。それを実現する[hsenv](https://hackage.haskell.org/package/hsenv)というツールがありますが、最近更新が止まっているようです。そこで、[シェルスクリプト版のクローン hsenv.sh](https://github.com/saturday06/hsenv.sh)を作りました。haskellではなくシェルスクリプトで書いた理由は、この分野で実績のあるrbenvがrubyではなくシェルスクリプトで書いてあることに何らかの合理性あるのではと思い、あやかろうと思ったからです。

本家との機能の違いは下記になります。

- コンパイル済みのghcを探して優先的にインストールする。ない場合はソースからインストール。
- インストールしたghcのバージョンに対応したcabalも自動でインストールする
  - この機能は本家にも[Pull Request](https://github.com/tmhedberg/hsenv/pull/39)されている
- Windows(msys,msys2)、Solarisでも動作する

# hsenv.shのインストール

まずは、`~/.hsenv`へソースをクローンします。クローンする場所はどこでも良いですが、rbenvに倣って僕はいつも`~/.hsenv`にしています。

```shell-session
$ git clone https://github.com/saturday06/hsenv.sh.git ~/.hsenv
```

次に、`~/.hsenv/bin`へパスを通します。これで`hsenv`コマンドが使えるようになります。

```shell-session
$ export PATH="$HOME/.hsenv/bin:$PATH"
```

# ghcのインストール

`~/projects/myapp`へ、ghcのバージョン7.8.1を使う環境を準備することとします。まずは`~/projects/myapp`へ移動して

```shell-session
$ mkdir -p ~/projects/myapp
$ cd ~/projects/myapp
```

次に引数`--ghc=バージョン`を指定してhsenvコマンドを実行します<sub><a href="#1">1</a></sub>

```shell-session
$ hsenv --ghc=7.8.1
Install to /home/saturday06/projects/myapp/.hsenv
GHC version=7.8.1
Downloading `https://www.haskell.org/ghc/dist/7.8.1/ghc-7.8.1-x86_64-unknown-linux-deb7.tar.xz'
Extracting...
Installing...
Bootstrap cabal-install
Found: Cabal-1.18.1.3
Install: cabal-install-1.18.0.5
Downloading `https://hackage.haskell.org/package/cabal-install-1.18.0.5/cabal-install-1.18.0.5.tar.gz'
Installing...
Done

To activate the new environment use `source .hsenv/bin/activate'
```

これで`projects/myapp/.hsenv`へインストールが完了します。インストールしたghcをつかうためには、そのディレクトリのhsenv環境を有効化する必要が有ります。それを行うコマンドは`source .hsenv/bin/activate`です。

```shell-session
$ source .hsenv/bin/activate
Activating  Virtual Haskell Environment (at /home/saturday06/projects/myapp).

Use regular Haskell tools (ghc, ghci, ghc-pkg, cabal) to manage your Haskell environment.

To exit from this virtual environment, enter command 'deactivate_hsenv'.
```
これで、ディレクトリ固有のghcやその周辺コマンドを使うことができます。

```shell-session
$ which ghc
/home/saturday06/projects/myapp/.hsenv/ghc/bin/ghc
$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 7.8.1
$ ghc-pkg --version
GHC package manager version 7.8.1
$ cabal --version
cabal-install version 1.18.0.5
using version 1.18.1.3 of the Cabal library
```

使い終わったら無効化します。無効化するコマンドは`deactivate_hsenv`です。

```shell-session
$ deactivate_hsenv
Deactivating  Virtual Haskell Environment (at /home/saturday06/projects/myapp).
Restoring previous environment settings.
```

上記activate/deactivateは面倒ですが、最近のモダンなシェルの場合は自動化することができます。下記の設定をシェルの設定に書いておけば、hsenvが設定されているディレクトリへ入った時、また出た時に自動でactivate/deactivateが動くようになります。

```bash:~/.bashrc
precmd() {
  local search_dir=$PWD
  while [ $search_dir != "/" ]; do
    local hsenv_found=false
    for dir in `cd $search_dir && find . -maxdepth 1 -type d -name ".hsenv*"`; do
      if $hsenv_found; then
        echo multiple environments in $search_dir , manual activaton required
        return        
      elif [ -n "$dir" ] && [ -e $search_dir/$dir/bin/activate ]; then
        hsenv_found=true
      fi
    done
    if ! $hsenv_found; then
      search_dir=`cd $search_dir/.. && pwd`
      continue
    fi
    if [ -n "$HSENV" ] && [ "$HSENV" != "$search_dir" ]; then
      deactivate_hsenv
    fi
    if [ -z "$HSENV" ]; then
      pwd_backup=$PWD
      cd $search_dir
      source .hsenv*/bin/activate
      cd $pwd_backup
    fi
    return
  done
  if [ -n "$HSENV" ]; then
    deactivate_hsenv
  fi
}
export PROMPT_COMMAND=precmd
```

Enjoy!

- - -
<a name="1">1.</a> ちなみに引数無しで`hsenv`コマンドを呼び出すと、`cabal sandbox`とほぼ同等の処理が実行されます。`cabal sandbox`がほぼデファクトになったと思うので、その機能はもう使われなくなると思います。