GHC 環境構築 概観 と PowerShell

Haskell の開発環境を構築する方法は何通りかあり、新しいツールが出ると「今はこれだ」とほめるブログも公開されますがそれが初学者を混乱させることがよくあります。

本記事ではビルドツールのインストールにしぼり、開発支援、例えば ghc-mod・haskell-ide-engine・hhp には言及しません。

いくつか典型的な構築方法を確認した後、新たに私が作成したツールを紹介しより初学者を混乱に落とし入れます。

重鎮 Haskell Platform

www.haskell.org

Haskell 解説書史1の第1波から第3波までのデファクトスタンダードであった重鎮 Haskell Platform です。コンパイラGHC とパッケージマネージャー Cabal、それにいくつかの準標準ライブラリーをまとめてインストールできるツールでこれをインストールするだけで入門書のコードはすぐ動くというようなものです。

現在では Windows 向けにのみ提供されています。Haskell Platform のページでは macOS 向けには下記で紹介する Stack がすすめられています。Linux 向けには Stack と、同じく下記で紹介する Ghcup またはディストリビューション付属のパッケージマネージャー(apt や yum など)がすすめられています。

救世 Stack

www.haskellstack.org

前世紀、人々は依存地獄に苦しめられていました。その苦しみを取り除くために救世主がごとく現れたのが Stack でした。

依存地獄とは依存ライブラリーのバージョン解決時に遭遇する問題でこれを解決しなければビルドができません。例えば A と B というパッケージに依存していたとしましょう。A はまた C に依存し同じく B は C に依存していたとします。このとき、A が要求する C のバージョンと B が要求する C のバージョンが同じであれば何も問題はありません。問題があるのは同じでない場合です。A または B 自体のバージョンを下げるなどして C のバージョンが合うように調整しないといけません。

OK

  • A
    • depends C-1
  • B
    • depends C-1

Error

  • A-3
    • depends C-2
  • B-1
    • depends C-1

Resolve (e.g.)

  • A-2
    • depends C-1
  • B-1
    • depends C-1

Stack は、主要なライブラリーに関してこの問題が解決されたバージョンのセットとそれをビルドできる GHC バージョンをペアにしたものを resolver として管理し提供しました。

また、ライブラリーや GHC のインストールされる場所をグローバルではなく隔離された場所にすることで、1つのマシンに入っている別々のプロジェクトが別々のバージョンのライブラリーや GHC を利用することを容易にしました。当時の Cabal はそれができませんでした2

これによって、ユーザーは resolver を指定することで依存地獄を見ることなくアプリケーション開発ができ、また複数プロジェクトの開発でわずらわされることがなくなりました。

新生 Cabal

www.haskell.org

Cabal は環境構築ツールではありませんが Stack と比較するという意味でここで紹介します。

Cabal は Haskell 標準のパッケージマネージャーで、Haskell Platform でインストールされますし、Stack も Cabal をラップして使用しています。

Stack が大躍進を遂げたことで、それまでライバルのいなかった Cabal にも変化が求められました。これまで Cabal のサブコマンドだった build などは v1-build とされ、新たに互換性のない v2-build が導入されました。v2-build では Stack の特徴の1つである「隔離してインストールする」機能が搭載されグローバルを汚染することがなくなりました(注:コメントを参照)3。build サブコマンドは v1-build の別名でしたが Cabal 3.0.0.0 でついに v2-build に変更されました。

この大幅改善によって一時は Stack に移行していたユーザーの一部は直接 Cabal を使うように戻ったようです。

甲殻 Ghcup

www.haskell.org

世の中では Haskell 以外の言語も生まれ進化しています。その内の1つに Rust があります。Rust はコンパイラー rustc とパッケージマネージャー Cargo の管理のために Rustup を開発しました。

Rustup は指定したバージョンの rustc と cargo をインストールする機能と、rustc コマンドで実際に呼び出されるコンパイラーを切り替える機能のあるものです。これと同じものを GHC も導入し ghcup としました。これによって複数の GHC をインストールしそれを切り替えて使用することが簡単にできるようになりました。

Ghcup と Cabal の v2 をインストールし、Stack が提供するライブラリーバージョンのセットを Cabal から使うとほぼ Stack がやっていたことができるようになります。

拙作 Ghcups

www.powershellgallery.com

私にとって Ghcup には1つ問題があり、それは Ghcup が sh 製であることです。私は Windows ユーザーで PowerShell を常用しています。これまでは Stack を使ってきていましたが、GHC を切り替える機能が欲しくなり同様の機能を持つ Ghcups を作りました。Ghcup と PowerShell(PS)のかばん語です。

実装の話をすると、Rustup や Ghcup は rustc や ghcシンボリックリンクとして実際の実行ファイルを指すようにしていますが、Windows ではシンボリックリンクの生成は管理者権限を必要とするため使いたくありません4。Ghcups では環境変数 Path を編集することで実現することにしました。副効果として、その Path の編集は1つの PowerShell プロセスに閉じるため複数の PowerShell があるときに同時にそれぞれ別々のバージョンを指定することができるようになりました。欠点としては PowerShell を経由しない GUI アプリケーションに対しては影響を及ぼせません。

GHC と Cabal のインストールは現状 Chocolatey に依存しています。これは実装を省いてとりあえず動くものが欲しかったのでこうなっています。要求があれば非依存にするかもしれません。

結局どれを選べばよいのか

私の私感ですが次のように選ぶのがよいかと思います。

  • 入門書を読んだのでとりあえずサンプルを試したい
    • Haskell Platform・Stack・Ghcup どれでもよいでしょう
    • 複数の GHC を試したくなったときは Haskell Platform はおすすめしません
    • Stack の場合はコマンドを読み替える必要があります(例:ghcstack ghc --
  • アプリケーションを作りたい
    • Stack がおすすめです
    • 特に Yesod のような依存の多いものは依存地獄が起きる可能性が高いのでより Stack をすすめます
    • 依存に問題がないなら他でもよいです
  • ライブラリーを作りたい
    • Ghcup + Cabal をおすすめします
    • 複数の GHC バージョンで動作確認したりするのに Ghcup は適しています
    • Stack でも stack.yaml をバージョンごとに複数用意するなどして利用することはできます

Ghcups で環境構築する

Ghcups を使って環境構築し切り替えをするところまで説明します。

実行ポリシーを設定して管理者権限で PowerShell を起動します5

powershell -ExecutionPolicy Bypass

PowerShell Gallery に公開しているので Install-Module でインストールできます。

> Install-Module ghcups

インストールが終わると同じく管理者の PowerShell にて下記のように Chocolatey をインストールします。ユーザーの PowerShell で実行した場合は自動的に管理者権限の PowerShell が起動するようになっているのでユーザー権限でも構いません。

> Import-Module ghcups
> Install-Choco
Getting latest version of the Chocolatey package for download.
Getting Chocolatey from https://chocolatey.org/api/v2/package/chocolatey/0.10.15.
Downloading 7-Zip commandline tool prior to extraction.
Extracting C:\Users\KAZUKI~1\AppData\Local\Temp\chocolatey\chocInstall\chocolatey.zip to C:\Users\KAZUKI~1\AppData\Local\Temp\chocolatey\chocInstall...
Installing chocolatey on this machine
We are setting up the Chocolatey package repository.
The packages themselves go to 'D:\chocolatey\lib'
  (i.e. D:\chocolatey\lib\yourPackageName).
A shim file for the command line goes to 'D:\chocolatey\bin'
  and points to an executable in 'D:\chocolatey\lib\yourPackageName'.

Creating Chocolatey folders if they do not already exist.

Chocolatey (choco.exe) is now ready.
You can call choco from anywhere, command line or powershell by typing choco.
Run choco /? for a list of functions.
You may need to shut down and restart powershell and/or consoles
 first prior to using choco.
Ensuring chocolatey commands are on the path
Ensuring chocolatey.nupkg is in the lib folder

GHC と Cabal のインストールとその切り替えは下記のようにします。ユーザーの PowerShell にて下記のようにセットアップします。管理者権限でないことの確認をされますがそのまま実行して大丈夫ですので y を選択してください6

> Import-Module ghcups
> Install-Ghc 8.8.1
Chocolatey v0.10.15
Chocolatey detected you are not running from an elevated command shell
 (cmd/powershell).

 You may experience errors - many functions/packages
 require admin rights. Only advanced users should run choco w/out an
 elevated shell. When you open the command shell, you should ensure
 that you do so with "Run as Administrator" selected. If you are
 attempting to use Chocolatey in a non-administrator setting, you
 must select a different location other than the default install
 location. See
 https://chocolatey.org/install#non-administrative-install for details.


 Do you want to continue?([Y]es/[N]o): y

Installing the following packages:
ghc
By installing you accept licenses for the packages.
Progress: Downloading ghc 8.8.1... 100%

ghc v8.8.1 [Approved]
ghc package files install completed. Performing other installation steps.
The package ghc wants to run 'chocolateyInstall.ps1'.
Note: If you don't run this script, the installation will fail.
Note: To confirm automatically next time, use '-y' or consider:
choco feature enable -n allowGlobalConfirmation
Do you want to run the script?([Y]es/[A]ll - yes to all/[N]o/[P]rint): a

Downloading ghc 64 bit
  from 'https://downloads.haskell.org/~ghc/8.8.1/ghc-8.8.1-x86_64-unknown-mingw32.tar.xz'
Progress: 100% - Completed download of D:\chocolatey\lib\ghc.8.8.1\tmp\ghcInstall (377.31 MB).
Download of ghcInstall (377.31 MB) completed.
Hashes match.
D:\chocolatey\lib\ghc.8.8.1\tmp\ghcInstall
Extracting D:\chocolatey\lib\ghc.8.8.1\tmp\ghcInstall to D:\chocolatey\lib\ghc.8.8.1\tools...
D:\chocolatey\lib\ghc.8.8.1\tools
Extracting D:\chocolatey\lib\ghc.8.8.1\tools\ghcInstall~ to D:\chocolatey\lib\ghc.8.8.1\tools...
D:\chocolatey\lib\ghc.8.8.1\tools
PATH environment variable does not have D:\chocolatey\lib\ghc.8.8.1\tools\ghc-8.8.1\bin in it. Adding...
Hiding shims for 'D:\chocolatey\lib\ghc.8.8.1\tools'.
Environment Vars (like PATH) have changed. Close/reopen your shell to
 see the changes (or in powershell/cmd.exe just type `refreshenv`).
 The install of ghc was successful.
  Software installed to 'D:\chocolatey\lib\ghc.8.8.1\tools'

Chocolatey installed 1/1 packages.
 See the log for details (D:\chocolatey\logs\chocolatey.log).
> Install-Ghc 8.6.5
(省略)
> Install-Cabal 3.0.0.0
(省略)
> Set-Ghc 8.8.1
> ghc --version
The Glorious Glasgow Haskell Compilation System, version 8.8.1
> Set-Ghc 8.6.5
> ghc --version
The Glorious Glasgow Haskell Compilation System, version 8.6.5

Haskell ユーザーで PowerShell ユーザーの方がいればぜひ試してみてください7


  1. Haskell 解説本 小史 - golden-luckyの日記

  2. cabal-dev を使えばできた。

  3. v2 は常用していないのでまちがっていればツッコミがほしい。

  4. 追記:ジャンクションなら管理者権限は必要なかった。

  5. “Chocolatey detected you are not running from an elevated command shell (cmd/powershell).” の確認をしないオプションをご存じの方いれば教えてください。“Do you want to run the script?” の確認はしたいです。

  6. Set-ExecutionPolicy を使用してグローバルに制限を緩める方法がよく紹介されますがセキュリティの観点からこちらの方をすすめます。ショートカットをオプション付きで設定して作成するとよいです。

  7. 何人いるんだろう。