昨天我了解了一个名为Stack的新 Haskell 工具。乍一看,它看起来和Cabal做的工作差不多。那么,它们之间有什么区别呢?堆栈是阴谋集团的替代品吗?在哪些情况下我应该使用 Stack 而不是 Cabal?Stack能做什么Cabal不能?
3 回答
堆栈是阴谋集团的替代品吗?
是和否。
在哪些情况下我应该使用 Stack 而不是 Cabal?Stack能做什么Cabal不能?
Stack默认使用精选的 stackage 包。既然如此,已知任何依赖项都是一起构建的,从而避免了版本冲突问题(当它们在 Haskell 体验中很常见时,曾经被称为“阴谋集团地狱”)。最新版本的阴谋集团也有防止冲突的措施。尽管如此,使用 Stack 设置一个可重现的构建配置,您可以准确地知道将从存储库中提取什么。请注意,还有使用非堆栈包的规定,因此即使堆栈快照中不存在包,您也可以继续使用。
就个人而言,我喜欢 Stack 并且会推荐每个 Haskell 开发人员使用它。他们的发展很快。它有一个更好的用户体验。Stack 做了一些 Cabal 没有提供的事情:
- Stack 甚至会为您下载 GHC 并将其保存在一个孤立的位置。
- Docker 支持(这对于部署您的 Haskell 应用程序非常方便)
- 可重现的 Haskell 脚本:您可以查明软件包的版本,并可以保证它始终可以毫无问题地执行。(Cabal 也有一个脚本功能,但要完全确保它的可重复性并不那么简单。)
- 做事的能力
stack build --fast --file-watch
。如果您更改存在的本地文件,这将自动重建。将它与--pedantic
选项一起使用对我来说是一个交易破坏者。 - Stack 支持使用模板创建项目。它还支持您自己的自定义模板。
- Stack 有内置的hpack支持。它提供了另一种(IMO,一种更好的)使用 yaml 文件编写 cabal 文件的方法,该文件在行业中使用更广泛。
- 在使用 Stack 时, Intero 具有流畅的体验。
有一篇很好的博客文章解释了差异:为什么 Stack 不是 Cabal?虽然在那篇文章之后的几年里,Cabal 已经发展到克服了那里讨论的一些问题,但对 Stack 背后的设计目标和理念的讨论仍然具有相关性。
在下文中,我将比较的两个工具称为cabal-install和stack。特别是,我将使用cabal-install来避免与Cabal库混淆,Cabal 库是两种工具都使用的通用基础架构。
从广义上讲,我们可以说cabal-install和stack是Cabal的前端。这两种工具都可以构建 Haskell 项目,这些项目的依赖集可能在单个系统的范围内相互冲突。它们之间的主要区别在于它们如何实现这一目标:
默认情况下,当被要求构建项目时, cabal-install
.cabal
将查看其文件中指定的依赖项,并使用依赖项求解器找出一组满足它的包和包版本。这个集合是从整个Hackage中提取的——所有包和所有版本,过去和现在。一旦找到可行的构建计划,所选版本的依赖项将被安装并索引到~/.cabal
. 通过根据版本(以及其他相关配置选项)对已安装包进行索引来避免依赖项之间的版本冲突,以便不同的项目可以检索到他们需要的依赖项版本,而不会互相影响。这种安排是什么cabal-install文档是指“Nix-style local builds”。当被要求构建一个项目时,stack会而不是去 Hackage,而是查看
resolver
.stack.yaml
在默认工作流程中,该字段指定Stackage 快照,它是具有已知相互兼容的固定版本的 Hackage 包的子集。然后堆栈将尝试仅使用快照提供的内容来满足.cabal
文件(或者可能是project.yaml
文件——不同格式,相同角色)中指定的依赖关系。从每个快照安装的软件包都注册在单独的数据库中,它们不会相互干扰。
我们可能会说,在指定构建配置时,堆栈方法用一些设置灵活性换取了简单性。特别是,如果您知道您的项目使用 LTS 15.3 快照,您可以转到其 Stackage 页面,一眼就知道任何依赖堆栈的版本都可能从 Stackage 中提取。也就是说,这两种工具都提供了超出基本工作流程的功能,因此,总的来说,每个工具都可以做对方所做的所有事情(尽管可能以不太方便的方式)。例如,有一些方法可以冻结已知良好构建配置的确切版本,并使用cabal-install解决旧状态 Hackage 的依赖关系,并且在使用stack时可能需要非 Stackage 依赖项或覆盖快照包版本。
最后, cabal-install和stack之间的另一个区别足以在本概述中值得一提的是,stack旨在提供完整的构建环境,具有自动 GHC 安装管理和Docker 集成等功能。相比之下,cabal-install旨在与生态系统的其他部分正交,因此它不会尝试提供此类功能(特别是,必须单独安装和管理 GHC 版本,例如通过ghcup工具)。
从我可以从常见问题解答中收集到的信息,Stack 似乎使用了 Cabal 库,而不是cabal.exe
二进制文件(更正确地称为 cabal-install)。看起来该项目的目标是自动沙盒和避免依赖地狱。
换句话说,它使用相同的 Cabal 包结构,只是提供了一个不同的前端来管理这些东西。(我认为!)