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