【问题标题】:What is the difference between Cabal and Stack?Cabal 和 Stack 有什么区别?
【发布时间】:2015-06-18 10:42:57
【问题描述】:

昨天我了解了一个名为 Stack 的新 Haskell 工具。乍一看,它看起来和Cabal做的工作差不多。那么,它们之间有什么区别呢?堆栈是阴谋集团的替代品吗?在哪些情况下我应该使用 Stack 而不是 Cabal? Stack 能做到 Cabal 不能做到的事情?

【问题讨论】:

  • fpcomplete.com/blog/2015/06/announcing-first-public-beta-stack (简而言之,它有点取代cabal-install 并尽可能多地使用堆栈 - 在某些时候可能会与 cabal-install 进行一些反向集成,我认为社区不确定这是否是一件好事,因为它可能会分裂社区)
  • AFAIU 堆栈可以方便地快速处理现有项目。如果你从头开始,你肯定会使用 cabal。
  • @mb14 事实并非如此。您可以使用堆栈从头开始项目。事实上,堆栈模板提供了一种简单的方法来做到这一点。
  • 查看这篇简短的文章以获得很好的概述:scs.stanford.edu/16wi-cs240h/labs/stack.html

标签: haskell cabal haskell-stack


【解决方案1】:

stack 是不是 Cabal 的替代品?

是和否。

在哪些情况下我应该使用 Stack 而不是 Cabal? Stack 能做到 Cabal 不能做到的事情?

Stack 使用 默认 的精选堆栈包。既然如此,任何依赖关系都可以构建在一起,从而避免版本冲突问题(当它们在 Haskell 体验中很常见时,曾经被称为“阴谋集团地狱”)。最新版本的阴谋集团也有防止冲突的措施。尽管如此,使用 Stack 设置一个可重现的构建配置,您可以确切地知道将从存储库中提取什么。请注意,还有使用非堆栈包的规定,因此即使堆栈快照中不存在包,您也可以继续使用。

就个人而言,我喜欢 Stack,并且会推荐所有 Haskell 开发人员使用它。他们的发展快速。它有一个很多更好的用户体验。 Stack 做了一些 Cabal 却没有提供的东西:

  • Stack 甚至会为您下载 GHC 并将其保存在一个孤立的位置。
  • Docker 支持(这对于部署您的 Haskell 应用程序非常方便)
  • Reproducible Haskell script:你可以查明一个包的版本,并且可以保证它永远执行没有任何问题。 (Cabal also has a script feature,但要完全确保可重复性并不那么简单。)
  • 能够做stack build --fast --file-watch。如果您更改存在的本地文件,这将自动重建。将它与 --pedantic 选项一起使用对我来说是一个交易破坏者。
  • Stack 支持使用templates 创建项目。它还支持您自己的自定义模板。
  • Stack 内置了hpack 支持。它提供了另一种(IMO,一种更好的)使用 yaml 文件编写 cabal 文件的方式,这种方式在业界得到了更广泛的应用。
  • Intero 体验流畅when working with Stack

有一篇很好的博客文章解释了差异:Why is Stack not Cabal? 虽然 Cabal 在自那篇文章之后的几年中不断发展,以克服那里讨论的一些问题,但讨论了 Stack 背后的设计目标和理念仍然相关。

【讨论】:

  • 自从 cabal 3 发布以来有什么变化吗?
  • @WilliamRusnack 是的,有。主要的是,默认的 Cabal 工作流程现在包含了避免依赖冲突,尽管它使用的策略与 Stack 的策略明显不同。 (@Sibi:我冒昧地更新了你的答案,以便更好地反映这些天的情况。)
【解决方案2】:

在下文中,我将比较的两个工具称为 cabal-installstack。特别是,我将使用 cabal-install 以避免与 Cabal 库混淆,这是两种工具都使用的通用基础架构。

广义而言,我们可以说 cabal-installstackCabal 的前端。这两种工具都可以构建 Haskell 项目,这些项目的依赖集可能在单个系统的范围内相互冲突。它们之间的主要区别在于它们如何实现这一目标:

  • 默认情况下,cabal-install 将在被要求构建项目时查看其.cabal 文件中指定的依赖项,并使用依赖项求解器找出一组包和包满足它的版本。这个集合来自Hackage 作为一个整体——所有包和所有版本,过去和现在。一旦找到可行的构建计划,将安装所选版本的依赖项并在~/.cabal 某处的数据库中建立索引。通过根据版本(以及其他相关配置选项)对已安装包进行索引来避免依赖项之间的版本冲突,以便不同的项目可以检索到他们需要的依赖项版本,而不会互相影响。这种安排是 cabal-install 文档中 "Nix-style local builds" 的意思。

  • 当被要求构建项目时,stack 将查看 stack.yamlresolver 字段,而不是去 Hackage。在默认工作流程中,该字段指定一个Stackage 快照,它是具有已知相互兼容的固定版本的 Hackage 包的子集。 stack 将尝试仅使用快照提供的内容来满足.cabal 文件中指定的依赖项(或者可能是the project.yaml file -- 不同的格式,相同的角色)。从每个快照安装的包都注册在不同的数据库中,它们不会相互干扰。

我们可能会说,在指定构建配置时,stack 方法用一些设置灵活性换取了简单性。特别是,如果您知道您的项目使用 LTS 15.3 快照,您可以转到 its Stackage page 并一目了然地知道任何依赖项的版本 stack 可能从 Stackage 中提取。也就是说,这两种工具都提供了超出基本工作流程的功能,因此,总的来说,每个工具都可以做对方所做的所有事情(尽管可能以不太方便的方式)。例如,freeze exact versions of a known good build configurationsolve dependencies with an old state of Hackagecabal-install 的方法,并且可以在使用 stackrequire non-Stackage dependencies or override snapshot package versions

最后,cabal-installstack 之间的另一个区别足以在本概述中一提,即 stack 旨在提供完整的构建环境,具有automatic GHC installation managementDocker integration等功能。相比之下,cabal-install 旨在与生态系统的其他部分正交,因此它不会尝试提供此类功能(特别是必须安装和管理 GHC 版本分开,例如通过the ghcup tool)。

【讨论】:

    【解决方案3】:

    根据我从常见问题解答中收集到的信息,Stack 似乎使用了 Cabal 库,而不是 cabal.exe 二进制文件(更正确地称为 cabal-install)。看起来该项目的目标是自动沙盒和避免依赖地狱。

    换句话说,它使用相同的 Cabal 包结构,只是提供了一个不同的前端来管理这些东西。 (我想!)

    【讨论】:

    • 除了cabal,他们的源代码似乎也在使用docker。虽然我不知道他们是否还在使用它。
    • @Sibi 是的,看起来你可以选择把东西扔到 Docker 中,而且它是可以工作的。我还没有进一步研究它......
    猜你喜欢
    • 2014-05-24
    • 2015-07-16
    • 2017-04-05
    • 1970-01-01
    • 2016-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-02
    相关资源
    最近更新 更多