关于Stack中package.yaml与stack.yaml的差异及支持情况的技术问询
我来帮你理清楚package.yaml(hpack格式)和stack.yaml之间的核心差异,这俩确实因为文档零散容易搞混:
核心定位差异
这是最本质的区别:
package.yaml是包描述文件,属于hpack生态,用来替代传统的.cabal文件,专门描述单个Haskell包的元数据与构建规则。stack.yaml是构建工具配置文件,是Stack构建工具本身的顶层配置,和hpack无关——哪怕你不用hpack,直接写.cabal文件,也必须有stack.yaml来告诉Stack怎么构建你的项目。
功能与职责划分
package.yaml的职责
它只关心单个包的“内在属性”:
- 包的基础信息:名称、版本、作者、许可证、描述
- 依赖管理:声明该包依赖的其他Haskell包(比如
base,text) - 模块配置:自动生成/手动指定暴露给外部的模块(
exposed-modules)、内部模块(other-modules) - 编译与构建规则:指定GHC编译选项、语言扩展、组件配置(比如库、可执行文件、测试套件、基准测试)
stack.yaml的职责
它管的是整个项目的“构建环境”与执行规则:
- 指定GHC版本:通过
resolver字段选择Stack快照(比如resolver: lts-20.10),快照会固定所有依赖包的版本 - 包源配置:添加额外的Hackage镜像或本地包路径
- 多包项目管理:列出项目包含的所有本地包(比如
packages: [., ./sub-package]) - Stack工具的全局/项目级设置:比如是否开启Docker构建、缓存策略、编译器选项的全局覆盖
语法与特性差异
package.yaml基于YAML语法,并且带有hpack专属的便利特性:- 自动扫描生成
exposed-modules和other-modules列表,不用手动逐个添加模块 - 支持YAML的锚点(
&)与别名(*),减少重复配置(比如统一管理版本号) - 支持变量插值与简单逻辑,比如用
${version}引用包版本 - 语法比传统
.cabal的DSL更简洁易读
- 自动扫描生成
stack.yaml虽然也是YAML格式,但它的语法是Stack工具专属的配置规范,没有hpack的这些便利特性,所有配置项都是Stack定义的固定字段,用来控制构建流程。
Stack中的协作方式
当你在Stack项目中使用package.yaml时:
- 编写
package.yaml后,Stack会自动将其转换成标准的.cabal文件(你可以在项目目录看到生成的.cabal文件) - Stack实际构建时,会读取
stack.yaml的配置来确定构建环境,再结合生成的.cabal文件来构建包 - 如果是多包项目,每个子包可以有自己的
package.yaml,而stack.yaml在根目录统一管理整个项目的构建环境
总结一下:package.yaml聚焦“包是什么”,用hpack的特性简化包描述;stack.yaml聚焦“怎么构建包”,是Stack控制构建流程的核心配置。
内容的提问来源于stack exchange,提问作者hnefatl
相关产品推荐
相关产品推荐

