我最近开始在Haskell中使用stack,为项目指定外部依赖项时。有时你会把它放在.cabal文件中,而其他时候你会把它放在.yaml文件中。
我想知道,当你将其放入cabal文件中时,它只会在stackage存储库中查找您的软件包。然而,当你把它放在你的.yaml文件中时,如果在任何快照中都找不到它,它还会在Hackage服务器中搜索吗?
您项目中所有的依赖关系都放在 .cabal
文件中。但是,有时您也会在 stack.yaml
文件中列出软件包,这可能会令人感到困惑。为什么呢?
嗯,.cabal
文件始终表示您对软件包的依赖关系,但是 stack.yaml
文件实际上配置了软件包来自哪里。通常情况下,使用 stack
时,软件包来自于您在 stack.yaml
文件中指定的 resolver 的 Stackage 。然而,Stackage 并不包括 Hackage 中的所有软件包,也不打算这样做——当您需要使用 Stackage 之外的软件包时,必须在 stack.yaml
文件中指定它们。
为什么会这样呢?因为 resolver 自动将两个重要信息捆绑在一起:软件包名称 及其 版本号。 Stackage 解析器提供了一个(弱)保证,即单个解析器中的所有软件包都可以一起工作。因此,当一个软件包来自于解析器时,就无需手动选择要使用的版本。相反,Stackage 将为您决定。
从 Hackage 获取软件包时,您就没有这种便利,所以需要使用 extra-deps
指定软件包 及其 版本。例如,您可能会像这样设置:
extra-deps:
- crypto-pubkey-openssh-0.2.7
- data-bword-0.1
- data-dword-0.3
此条目具体确定应从Hackage而不是Stackage拉取哪些软件包的哪些版本。
在构建应用程序时,这似乎有点冗余 —— 您也可以在.cabal
文件中指定版本约束条件,那么为什么要在stack.yaml
文件中重复呢?然而,在构建库时,区别就显得更加重要: .cabal
文件表达了您的库实际的版本约束条件(如果有的话),但stack.yaml
文件则指定了在本地开发时实际安装的精确版本。
在这种意义上,stack.yaml
文件类似于其他包管理器的Gemfile.lock
或npm-shrinkwrap.json
文件,尽管stack
的职责并不像这些文件那么明确(部分原因是由于Haskell包系统的历史原因以及它过去存在的一些问题)。