昨日第23回Haskellもくもく会 @ 朝日ネットで初めてstackを触ったのですが、
あまりにも簡単・高速にパッケージ作りの準備ができたので、やったことを共有したいと思います。
GHC(Haskellの最も有名なコンパイラ)のインストールまでやってくれるので、これからHaskell始めます!みたいな人にもオススメです。
stack自体が何かは @tanakh さんのHaskellのビルドツール"stack"の紹介をご覧ください。
一言で言うと「GHCのインストールからパッケージのインストールにビルドまで、ワンストップでやってくれる神ツール」ですかね。
インストール
各OSごとに微妙に違うみたいなので、公式ページの解説をご覧ください。
とはいえ、基本的には実行ファイルをPATH
のどこかに置くだけなので、この手の作業に慣れている人には朝飯前でしょう。
1ファイルだけでインストールできちゃうのも魅力ですね!
すでにcabalをお使いの方へ
くれぐれもcabal install stack
はしないでください。
あれはstack自身の開発者向けのパッケージです。
cabal
の難しいところをカバーするためにstack
があるのですから、cabal
のことは一旦忘れましょう。
プロジェクトディレクトリーの作成
stack new
コマンドで適当なプロジェクト名を指定すれば、適当なプロジェクトテンプレートが入ったディレクトリーを作ってくれます。
第2引数にテンプレートの名前を指定すればもっとよいものを提供してくれるみたいですが、今回はとりあえず簡単に。
$ stack new foobar-project
Downloading template "new-template" to create project "foobar-project" in foobar-project/ ...
Using the following authorship configuration:
author-email: example@example.com
author-name: Example Author Name
Copy these to /home/yu/.stack/stack.yaml and edit to use different values.
Writing default config file to: /home/yu/tmp/foobar-project/stack.yaml
Basing on cabal files:
- /home/yu/tmp/foobar-project/foobar-project.cabal
Checking against build plan lts-3.2
Selected resolver: lts-3.2
Wrote project config to: /home/yu/tmp/foobar-project/stack.yaml
$ cd foobar-project/
$ ls
LICENSE Setup.hs app foobar-project.cabal src stack.yaml test
stack 1.6.1未満を使っている場合のエラー
手元で試したところ、stack
のバージョンが1.5.1などのバージョンの場合、下記のAesonException
が起こるようです。
$ stack new hoge
Downloading template "new-template" to create project "hoge" in hoge\ ...
Initialized empty Git repository in C:/Users/igrep/Downloads/tmp/hoge/.git/
Looking for .cabal or package.yaml files to use to init the project.
Using cabal packages:
- hoge\hoge.cabal
Selecting the best among 12 snapshots...
Downloaded lts-10.0 build plan.
AesonException "Error in $.packages.cassava.constraints.flags['bytestring--lt-0_10_4']: Invalid flag name: \"bytestring--lt-0_10_4\""
問題のIssueでSnoyman氏が述べているようにstack upgrade
したり、(Chocolateyでstackを入れた場合は)choco upgrade haskell-stack
するなどして、stackのバージョンを上げてください。
あるいは、ちょっと試せてないのですが、事情があってstackのアップデートができない場合、stack --resolver=lts-9.20
のように古いLTS Haskellを指定するという方法でもよいかも知れません(古いバージョンのGHCがインストールされてしまうので、推奨はしませんが)。
とにかくビルドしましょう
こちらのテンプレート、何もしなくてもとりあえずすでにビルドできる状態になっています。
文字通りstack build
を実行してください。
$ stack build
No GHC found, expected version 7.10.2 (x86_64) (based on resolver setting in /home/michael/helloworld/stack.yaml).
Try running stack setup
おっと、「何もしなくても」はさすがに大袈裟でした。
上記のように、ここで必要なバージョンのGHCがインストールされていない場合、エラーになります。
@tanakhさんの記事の時点ではstack build
だけで自動的にインストールまでしてくれる仕様だったようですが、あまりにもいきなりすぎると判断したんでしょう。
とはいえ、ちゃんとエラーメッセージにstack setup
してくれ、と親切にも書いてくださっているので、素直に実行しましょう。
自動的に最初にこの記事を書いた時点における最新安定版のGHC 7.10.2が入ります。
2017/12/09 追記: まだ手元で試せてはいないのですが、Stack 1.6.1から、デフォルトで、stack build
しただけでGHCのインストールも行うようになったそうです。なのでstack setup
は不要になった模様です。
$ stack setup
Downloaded ghc-7.10.2.
... 省略 ...
Installed GHC.
stack will use a locally installed GHC
For more information on paths, see 'stack path' and 'stack exec env'
To use this GHC and packages outside of a project, consider using:
stack ghc, stack ghci, stack runghc, or stack exec
ネットワークの状況にも依存するとは思いますが、GHCのインストールはやっぱり結構時間がかかりました。
待ちましょう。
インストールが終わったら、気を取り直してstack build
。
foobar-project-0.1.0.0: configure
Configuring foobar-project-0.1.0.0...
foobar-project-0.1.0.0: build
Preprocessing library foobar-project-0.1.0.0...
[1 of 1] Compiling Lib ( src/Lib.hs, .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/Lib.o )
In-place registering foobar-project-0.1.0.0...
Preprocessing executable 'foobar-project-exe' for foobar-project-0.1.0.0...
[1 of 1] Compiling Main ( app/Main.hs, .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/foobar-project-exe/foobar-project-exe-tmp/Main.o )
Linking .stack-work/dist/x86_64-linux/Cabal-1.22.4.0/build/foobar-project-exe/foobar-project-exe ...
foobar-project-0.1.0.0: install
Installing library in
/home/yu/tmp/foobar-project/.stack-work/install/x86_64-linux/lts-3.2/7.10.2/lib/x86_64-linux-ghc-7.10.2/foobar-project-0.1.0.0-E05fmeQhYiF0vVxMlsqLP6
Installing executable(s) in
/home/yu/tmp/foobar-project/.stack-work/install/x86_64-linux/lts-3.2/7.10.2/bin
Registering foobar-project-0.1.0.0...
さぁ実行だ!
stack exec
を使えば、プロジェクトの設定(stack.yaml
)毎に空気を読んでPATH
を適切に設定してくれます。
デフォルトのテンプレートでビルドした実行ファイルは<プロジェクト名>-exe
という名前になってますので、
今回の場合はstack exec foobar-project-exe
しましょう。
$ stack exec foobar-project-exe
someFunc
...お、惜しい。Hello, world!
じゃない...
せっかくなんでプロジェクトの構造を確認しつつ、Hello, world!
を出すよう編集しましょう。
お好きなエディタでapp/Main.hs
を開いてください。
module Main where
import Lib
main :: IO ()
main = someFunc
ここではHaskell自体の詳細は割愛しますが、このapp/Main.hs
のmain
という関数が、stack exec foobar-project-exe
した時に最初に実行される関数です。
この場合、Lib
というパッケージから(暗黙に)import
された、someFunc
という関数を呼んでいます。
それではLib
のsomeFunc
を覗いてみましょう。src/Lib.hs
にその正体があります。
module Lib
( someFunc
) where
someFunc :: IO ()
someFunc = putStrLn "someFunc"
さっきstack exec foobar-exe
した時に出力されたsomeFunc
という文字列はここにありました。
どうやらputStrLn
という関数で指定した文字列を出力していたようですね。
ここを我らが(?)Hello, world!
に書き換えましょう。それだけです。
module Lib
( someFunc
) where
someFunc :: IO ()
someFunc = putStrLn "Hello, world!"
後はもう一度stack build
して実行するだけ!
$ stack build
... 省略 ...
$ stack exec foobar-exe
Hello, world!
できました!これであなたもHaskellerです!
この先はどうする?
あまりにもstackが簡単だったので勢いで導入を書いてしまいました。
誰か入門を考えてください...。
すごいH本は最初ghci
から入るので、この記事の入門では不向きなのです...。
残りは気になったら読んでください。
他のパッケージを入れたい時は?
例えばおなじみ「すごいH本」を読み進めたら出てくる、Data.Map
をimport
したくなったとしましょう。
module Lib
( someFunc
) where
import qualified Data.Map as M
someMap :: M.Map String String
someMap = M.fromList [("stack exec", "Hello, world!")]
someFunc :: IO ()
someFunc = print $ M.lookup "stack exec" someMap
すごいH本には「最初から入っているから大丈夫だよ〜」と書いてありますが、ここで紹介したテンプレートで使用しようとすると、残念ながらそのままではエラーになってしまいます。
$ stack build
foobar-project-0.1.0.0-42e96c77117d3dac75f022f842817f66: unregistering (local file changes)
foobar-project-0.1.0.0: build
Preprocessing library foobar-project-0.1.0.0...
/home/yu/tmp/foobar-project/src/Lib.hs:5:18:
Could not find module ‘Data.Map’
It is a member of the hidden package ‘containers-0.5.6.2@conta_LKCPrTJwOTOLk4OU37YmeN’.
Perhaps you need to add ‘containers’ to the build-depends in your .cabal file.
Use -v to see a list of the files searched for.
ここでstack...ではなく、stackがラップしているパッケージマネージャー、cabal(これまでHaskellを使ってきた方にはおなじみですね)に、
「Data.Map
が入ってるcontainers
っていうパッケージを使いたいんだけど!!」と教えてあげましょう。
foobar-project.cabal
というファイル(通称cabalファイルと呼びます)... ではなく、package.yaml
というファイルを開いてください。
2017/12/23 追記: どうやら、stack new
した場合のデフォルトのテンプレートpackage.yaml
が含まれるようになったようです。これによって、cabalファイルを編集しても、stack build
した時点で書き換えられてしまいます。詳しくはこの記事へのコメントとその回答をご覧ください。
こんな↓感じのファイルになっています。
name: foobar-project
version: 0.1.0.0
... 省略 ...
dependencies:
- base >= 4.7 && < 5
library:
source-dirs: src
... 省略 ...
上記のdependencies:
と書かれた行の下に、次のように追記してください。
name: foobar-project
version: 0.1.0.0
... 省略 ...
dependencies:
- base >= 4.7 && < 5
- containers # <= ココ!
... 省略 ...
上のbase >= 4.7 && < 5
と書かれた行のように、特にバージョン番号を指定する必要はないようです。
stack自身が用意したlts-10.0
というバージョンのStackage(安定してビルドできるバージョンを記録したパッケージ集)から適切なバージョンを選んでくれるからでしょう。
自前でバージョン指定を考えて首をひねるのは、もう過去の出来事です 1。
さて、package.yaml
を編集したら、もう一度stack build
するだけで、新しいパッケージをとってきてくれます。
$ stack build
... 省略 ...
$ stack exec foobar-project-exe
Just "Hello, world!"
これでカンペキ!
もっと他のパッケージを入れたいときは?
冒頭でも触れた、@tanakhさんの記事をご覧ください。
foobar-project-exe とか実行ファイルの名前ダサすぎなんですけど?
こちらもstackがラップしている、cabalの設定によります。package.yaml
を開いて...
... 省略 ...
executables:
foobar-project-exe:
main: Main.hs
source-dirs: app
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- foobar-project
... 省略 ...
下記のように、executables:
の下の方にあるfoobar-project-exe:
と書かれた行を、<好きな実行ファイル名>:
に変え、stack build
し直してください。
Windows向けに拡張子.exe
は特に言わなくても付けてくれたはず。
... 省略 ...
executables:
your-cool-command: # <- ココ!
main: Main.hs
source-dirs: app
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- foobar-project
... 省略 ...
インストールしたものはどこに行くの?
まだまだ激しく開発中のツールなので今後仕様が変わるかもですが、私の環境ではこんな感じの場所にインストールされました。
だいたいみなさんのホームディレクトリーや%USERPROFILE%\AppData\Local
以下あたりのそれっぽいディレクトリーに読み替えていただければ見つかるでしょう。
-
stack install
した、プロジェクト固有の実行ファイル:~/.local/bin/
-
stack setup
でインストールしたGHC 7.10.2の実行ファイル:~/.stack/programs/x86_64-linux/ghc-7.10.2/bin/
必要に応じてこれらもPATH
に追加しちゃいましょう。
気が向いたら調べて記事にする
-
プロジェクトディレクトリーを作らないでとりあえずGHC一式だけ欲しい時の方法。
- 何にもないディレクトリーで
stack setup
するだけでとりあえずインストールされるっぽい。PATH
の設定はお好みで。
- 何にもないディレクトリーで
- デフォルトのテンプレートに入っているユーザー名やメールアドレスを変える方法。