Stack#
备注
本章节选、整理并翻译自 Stack 文档。
简介#
- Stack:跨平台的 Haskell 项目管理工具,包括 GHC 安装、项目编译、依赖安装等;
- Stack 在 Cabal 的基础上做了改进,是 Cabal 的增强版;
- Cabal 过于复杂,更推荐使用 Stack 进行包和项目管理;
命令#
$ stack [options] COMMAND|FILE
- 运行 Stack 命令行;
参数
-
COMMAND
#
子命令。
-
FILE
#
指定文件名。
选项
init
#
$ stack init [DIR] [options]
- 创建 Stack 项目配置文件
stack.yaml
; - 快照:
参数
-
DIR
#
生成配置文件的目录名,默认当前目录;
选项
-
--force
#
强制覆盖已有的
stack.yaml
。
-
--ignore-subdirs
#
忽略指定子目录下的
.cabal
文件。
-
--omit-packages
#
排除冲突的包。
$ stack init
Looking for .cabal or package.yaml files to use to init the project.
We didn't find any local package directories
You may want to create a package with "stack new" instead
Create an empty project for now
...
new
#
$ stack new PACKAGE_NAME [option] [TEMPLATE_NAME] [options]
- 创建 Haskell 项目;
参数
-
PACKAGE_NAME
#
Haskell 包名,由字母数字和短横杠
-
组成。
-
TEMPLATE_NAME
#
包结构的模板,可以是 URL、本地文件名或
[[service]:username/]template
(service
可以为github
、gitlab
或bitbucket
)形式,默认为new-template
。
$ stack new helloworld new-template
Downloading template "new-template" to create project "helloworld"
in helloworld/ ...
Looking for .cabal or package.yaml files to use to init the project.
Using cabal packages:
- helloworld/
...
build
#
$ stack build [TARGET] [options]
- 编译 Haskell 项目;
- 编译:
- 编译后会生成
stack.yaml.lock
文件和.stack-work/
目录; - 编译后产生的中间文件和可执行文件都在
.stack-work/
目录下; build
命令产生的可执行文件默认名为PACKAGE_NAME-exe
;
- 编译后会生成
参数
-
TARGET
#
编译对象,默认为所有本地的包。可以为以下格式:
PACKAGE
:可指定包名;$ stack build helloworld
PACKAGE-VERSION
:可指定包标识符,即包名加版本号;$ stack build helloworld-1.4.14
[PACKAGE[:TYPE]]:COMPONENT
:可指定单个构成部分;$ stack build helloworld:test:helloworld-test $ stack build helloworld:helloworld-test $ stack build :helloworld-test
- 构成部分:可通过
stack ide targets
命令查看;:lib
:库;[:exe]:PACKAGE-exe
:可执行文件;[:test]:PACKAGE-test
:测试组;
- 指定其中一个部分不会编译其他部分;
- 构成部分:可通过
DIR
:可指定单个目录,编译该目录下的所有包和子包;
选项
-
--dry-run
#
显示编译后产生的影响,但不编译。
-
--ghc-options
#
指定 GHC 编译选项。
-
--[no-]haddock
#
禁用/启用当前目录的文档生成,默认禁用。
-
--[no-]test
#
禁用/启用当前目录的测试,默认禁用。
-
--[no-]copy-bins
#
禁用/启用将当前目录的可执行文件复制到指定二进制目录,默认禁用。
-
--[no-]bench
#
禁用/启用当前目录的标杆分析,默认禁用。
-
--[no-]test
#
禁用/启用当前目录的测试,默认禁用。
-
--no-run-tests
#
编译测试组后禁止运行测试组。
-
--no-run-benchmarks
#
编译标杆分析组后禁止运行标杆分析。
-
--skip
<ARG>
# 编译时跳过指定构成部分。
-
--coverage
#
生成代码覆盖报告。
$ stack build
Building all executables for `helloworld' once. After a successful
build of all of them, only specified executables will be rebuilt.
helloworld> configure (lib + exe)
Configuring helloworld-0.1.0.0...
helloworld> build (lib + exe)
Preprocessing library for helloworld-0.1.0.0..
Building library for helloworld-0.1.0.0..
[1 of 2] Compiling Lib
[2 of 2] Compiling Paths_helloworld
...
ghc
#
$ stack ghc [options]
- 运行 GHC 编译器;
选项
-
--
<argument(s)>
# 指定 GHC 编译器的参数。
-
--cwd
<dir>
# 运行前指定当前工作目录。
-
--package
<package(s)>
# 指定额外的包。
$ stack ghc -- app/Main.hs
[1 of 1] Compiling Main ( app/Main.hs, app/Main.o )
Linking app/Main ...
runghc
和 runhaskell
#
$ stack runghc [options]
- 运行
runghc
命令; stack runhaskell
是stack runghc
命令的别名;runghc
命令可用于脚本解释;
选项
-
--
<argument(s)>
# 指定
runghc
命令的参数。
-
--cwd
<dir>
# 运行前指定当前工作目录。
-
--package
<package(s)>
# 指定额外的包。
ghci
#
$ stack ghci [TARGET/FILE] [options]
- 运行 GHCi;
参数
-
TARGET/FILE
#
指定加载的包或文件,默认为所有本地包。
选项
-
--ghci-options
<options>
# 指定 GHCi 选项。
-
--ghc-options
<options>
# 指定 GHC 选项。
-
--with-ghc
<ghc>
# 指定使用的 GHC 编译器版本。
-
--[no-test]
#
禁用/启用测试组,默认禁用。
-
--[no-bench]
#
禁用/启用标杆分析,默认禁用。
exec
#
$ stack exec COMMAND [-- ARGUMENT(S)] [options]
- 添加、修改环境变量并执行命令;
- 命令执行:
build
命令后产生的可执行文件可通过exec
命令执行,exec
命令会自动解析可执行文件的地址,不用手动指定;exec ghci
命令可用于脚本解释;
参数
-
COMMAND
#
要执行的命令。
$ stack exec helloworld-exe
someFunc
script
#
$ stack script [option] FILE [options]
解释 Haskell 脚本;
解释器:
Stack 可用作 Haskell 源文件的解释器;
$ stack Main.hs Hello World
script
命令会忽略所有配置文件;使用
script
命令时,必须指定全局选项--resolver
;Shebang:
可以为 Haskell 源文件指定 Shebang,Shebang 后跟特殊注释以指定编译行为;
#!/usr/bin/env stack -- stack --resolver lts-18.23 script --package random
特殊注释可以为多行注释;
#!/usr/bin/env stack {- stack --resolver lts-18.23 script --package random -}
若不指定 Shebang 和特殊注释,则 Stack 默认使用
runghc
命令执行文件;
其他命令:某些命令同样可用于特殊注释中;
runghc
或runhaskell
命令:不推荐使用,更推荐script
命令;#!/usr/bin/env stack {- stack --resolver lts-18.23 --install-ghc runghc --package random -- -hide-all-packages -}
exec ghci
命令:将文件加载到 GHCi 中;#!/usr/bin/env stack {- stack --resolver lts-18.23 --install-ghc exec ghci --package random -}
参数
-
FILE
#
Haskell 源文件。
选项
-
--ghc-options
<options>
# GHC 选项。
-
--package
<package(s)>
# 安装指定的包。
-
--extra-dep
<package-version>
# 指定不在快照中的依赖。
-
--compile
#
编译文件时不作优化,并运行。
-
--optimize
#
编译文件时优化,并运行。
-
--no-run
#
编译后不运行。
test
#
$ stack test [TARGET] [options]
- 编译项目并运行测试组,实际是
stack build --test
命令的别名;
参数
- 与
build
命令相同
$ stack test
helloworld-0.1.0.0: unregistering (components added: test:helloworld-test)
helloworld> configure (lib + exe + test)
Configuring helloworld-0.1.0.0...
helloworld> build (lib + exe + test)
Preprocessing library for helloworld-0.1.0.0..
Building library for helloworld-0.1.0.0..
...
helloworld> test (suite: helloworld-test)
Test suite not yet implemented
helloworld> Test suite helloworld-test passed
Completed 2 action(s).
install
#
$ stack install [TARGET] [options]
- 编译项目并将可执行文件复制到指定二进制目录下,实际是
stack build --copy-bins
命令的别名;
参数
- 与
build
命令相同
$ stack install
Building all executables for `helloworld' once. After a successful build
of all of them, only specified executables will be rebuilt.
...
Copied executables to /Users/chattille/.local/bin:
- helloworld-exe
clean
#
$ stack clean [PACKAGE] [options]
- 清除指定包下产生的各种编译文件,即
.stack-work/dist/
目录;
参数
-
PACKAGE
#
包名,默认为所有包。
选项
-
--full
#
清除整个
.stack-work/
目录。
$ tree -L 1 .stack-work
.stack-work
├── dist
├── install
├── stack.sqlite3
└── stack.sqlite3.pantry-write-lock
$ stack clean
$ tree -L 1 .stack-work
.stack-work
├── install
├── stack.sqlite3
└── stack.sqlite3.pantry-write-lock
purge
#
$ stack purge [options]
- 清除整个
.stack-work/
目录,但不包括install
命令复制的可执行文件,可将项目还原到未编译状态,实际是stack clean --full
命令的别名;
$ ls -A
.gitignore LICENSE app src test
.stack-work README.md helloworld.cabal stack.yaml
ChangeLog.md Setup.hs package.yaml stack.yaml.lock
$ stack purge
$ ls -A
.gitignore README.md helloworld.cabal stack.yaml
ChangeLog.md Setup.hs package.yaml stack.yaml.lock
LICENSE app src test
ls
#
$ stack ls COMMAND [SUBCOMMAND] [options]
- 列出指定要素;
参数
-
COMMAND
#
命令。可以为:
snapshots
:显示快照;参数
-
COMMAND
#
子命令。可以为:
remote
:显示远程快照;local
:显示本地快照,默认命令;
选项
-
-l
,
--lts
#
只显示 LTS 快照。
-
-n
,
--nightly
#
只显示 Nightly 快照。
-
dependencies
:列出依赖包;参数
-
COMMAND
#
子命令。可以为:
text
:以文本格式输出,默认命令;tree
:以树状图格式输出;json
:以 JSON 格式输出;
选项
-
--depth
<depth>
# 指定依赖深度。
-
--prune
<packages>
# 排除指定包,多个包用逗号分隔。
-
stack-colors
或stack-colours
:列出 Stack 输出时使用的颜色;
path
#
$ stack path [options]
- 打印 Stack 的路径信息;
选项
-
--bin-path
#
PATH
环境变量。
-
--programs
#
Stack 安装的 GHC 编译器路径。
-
--stack-root
#
Stack 的根目录。
-
--project-root
#
当前项目的根目录。
-
--local-hoogle-root
#
本地 Hoogle 的根目录。
-
--local-doc-root
#
当前项目的文档根目录。
-
--local-bin
#
二进制目录,
install
命令会将可执行文件安装到此目录。
ide
#
$ stack ide [options] COMMAND
- IDE 相关命令;
参数
-
COMMAND
#
子命令。可以为:
targets
:打印所有可编译 Stack 对象;packages
:打印所有可加载的本地包;
dot
#
$ stack dot [options] [TARGET] [options]
- 用 Graphviz 格式显示依赖关系;
参数
-
TARGET
#
显示该目标的依赖关系,默认为所有本地包。
选项
-
--[no-]external
#
禁用/启用外部依赖,默认禁用。
-
--depth
<depth>
# 依赖关系的深度,默认无限。
-
--prune
<packages>
# 去除指定包,多个包用逗号分隔。
-
--test
#
包括测试组的依赖。
-
--bench
#
包括标杆分析组的依赖。
项目结构#
stack new
命令默认使用模板new-template
;- 目录结构:
.gitignore
:指定 Git 版本管理时要忽略的文件;ChangeLog.md
:项目历史;LICENSE
:项目使用的许可证;README.md
:项目简介;Setup.hs
:Cabal 编译系统的一部分,虽然技术上来说 Stack 不需要该文件,但在 Haskell 世界里推荐包含该文件;PACKAGE_NAME.cabal
:Cabal 编译使用的文件,由stack build
命令自动更新,不应做修改;app/
:生成可执行文件的目录;Main.hs
:主模块,程序的入口;
package.yaml
:包的配置文件;src/
:主模块使用的各种辅助模块;stack.yaml
:Stack 编译的配置文件,规定编译行为;test/
:测试组代码;
Stackage#
Hackage:Cabal 下载包时会从 Haskell 社区的远程库下载,该远程库为 Hackage;
-
- Stack 下载包时会从自己的远程库下载,该远程库为 Stackage,是一套稳定的从 Hackage 精选的 Haskell 包的集合;
- Stack 同样支持 Hackage;
快照:
Stackage 将多个包打包成一个集合,称为快照,供特定版本的 GHC 使用;
可通过全局选项
--resolver
或键resolver
指定快照或 GHC 版本;快照分为两种:
数据库#
数据库:Haskell 包的数据库,包含包的各种信息,包括编译库、可执行文件、文档和其他文件;
$ ls .stack-work/install/x86_64-osx/.../8.10.7/ bin doc lib pkgdb
数据库结构:Stack 的数据库是分层的,分为全局数据库、快照数据库和本地数据库,可用
ghc-pkg list
命令查看;$ stack exec -- ghc-pkg list /Users/chattille/.ghcup/ghc/.../package.conf.d Cabal-3.2.1.0 array-0.5.4.0 base-4.14.3.0 ... transformers-0.5.6.2 unix-2.7.2.2 xhtml-3000.2.2.1 /Users/chattille/.stack/snapshots/.../pkgdb random-1.2.0 splitmix-0.1.0.4 /Users/chattille/.../Test/.stack-work/install/.../pkgdb Test-0.1.0.0
- 全局数据库:GHC 编译器自带的包的数据库,由所有项目共享;
- 快照数据库:来自快照的包的数据库,储存于
~/.stack/snapshots/
目录下,使用相同快照的项目可共享,不同快照不共享; - 本地数据库:当前项目的数据库,储存于
./.stack-work/install/
目录下,不与其他项目共享;
多层数据库有利于在不同项目中复用相同的包,也能防止不同项目间的包污染;
package.yaml
#
dependencies
:指定当前项目的依赖,可用ls
命令查看依赖;dependencies: - base >= 4.7 && < 5 - text # 在这里添加
extra-deps
:指定不存在于当前快照的依赖;extra-deps: - acme-missiles-0.3 # 不在 LTS 内
resolver
:指定解析器,若本地不存在对应版本的 GHC 编译器,则自动下载;ghc-X.Y.Z
:指定具体 GHC 编译器版本;lts-X.Y
:指定 LTS 快照版本,省略Y
则指定最新lts-X
版本;nightly-YYYY-MM-DD
:指定 Nightly 快照日期;
resolver: lts-18.23