☰
使用 Devbox 在 Haskell 项目中搭建 Stack 开发环境
2026/10/2 2:23:01 网站建设 项目流程
  • 开发工具
  • CLI

【免费下载链接】devbox

Instant, easy, and predictable development environments

项目地址:https://gitcode.com/GitHub_Trending/dev/devbox
点击查看免费下载

导读

本文基于 Devbox 仓库中的 Haskell 实战示例(examples/development/haskell/my-project/README.md),讲解如何借助 Devbox 为基于 Stack 工具链的 Haskell 项目构建开箱即用的可复现开发环境。你将掌握从零初始化一个 Stack 项目、在 Devbox Shell 中执行构建与运行、理解devbox.json中 GHC/Stack/Cabal 等关键包的配置,以及 Devbox Haskell 插件在底层如何组合这些工具链。

示例概览:Devbox 中的 Haskell + Stack 组合

仓库中examples/development/haskell/目录提供了一个完整的 Haskell 开发环境示例。其核心思路是:Haskell 项目如果使用 Stack 工具链,只需要在 Devbox 中安装 Stack、Cabal 以及编译所需的基础库,即可在隔离且可复现的 Shell 中完成全部开发工作(参见 examples/development/haskell/README.md)。

示例项目my-project由stack new生成,其结构如下:

examples/development/haskell/my-project/ ├── app/ # 可执行程序入口 │ └── Main.hs ├── src/ # 库代码 │ └── Lib.hs ├── test/ # 测试套件 │ └── Spec.hs ├── package.yaml # hpack 项目描述(Stack 默认生成) ├── my-project.cabal # 由 hpack 从 package.yaml 生成 ├── stack.yaml # Stack 解析器与构建配置 └── stack.yaml.lock

入口程序 app/Main.hs 导入库模块并调用someFunc:

module Main (main) where import Lib main :: IO () main = someFunc

对应的库实现 src/Lib.hs 输出一行文本:

module Lib ( someFunc ) where someFunc :: IO () someFunc = putStrLn "someFunc"

三步复现:从零生成一个同款 Haskell 项目

示例文档给出了最简单的复现路径——复制devbox.json并运行devbox shell(见 examples/development/haskell/my-project/README.md)。具体操作如下:

  1. 准备一个工作目录,将示例的 devbox.json 复制进去;
  2. 在目录中运行devbox shell激活开发环境;
  3. Shell 激活后,依次执行 Stack 的项目生成、构建与运行命令:
stack new my-project cd my-project stack build stack exec my-project-exe

其中:

  • stack new my-project基于默认模板生成新项目骨架(即上面展示的目录结构);
  • stack build依据stack.yaml中的解析器(snapshot)解析依赖并编译库、可执行程序与测试套件;
  • stack exec my-project-exe运行编译好的可执行程序,终端将输出someFunc。

示例的devbox.json还内置了一个便捷脚本run_test(详见下文配置小节),它等价地完成"进入项目目录 → 构建 → 运行"的全流程:

devbox run run_test

配置详解:devbox.json中的 Haskell 工具链

示例目录下的 devbox.json 是整套环境的配置核心:

{ "packages": [ "ghc@latest", "gmp@latest", "stack@latest", "cabal-install@latest", "zlib@latest", "hpack@latest" ], "env": { "PATH": "$PATH:/usr/bin" }, "shell": { "init_hook": null, "scripts": { "run_test": [ "cd my-project", "stack build", "stack exec my-project-exe" ] } } }

各配置项的含义与作用:

配置项说明
packages声明环境所需的软件包。@latest后缀表示取最新可用版本;如需指定其他版本,可用devbox search <pkg>查询可安装版本(参见 examples/development/haskell/README.md)。
ghcHaskell 编译器。Stack 需要 GHC 才能实际编译源码,因此显式安装。
gmpGNU 多精度算术库,GHC 运行时依赖的底层数学库,缺少它编译与运行都会失败。
stackStack 构建工具,负责解析器(snapshot)解析、依赖管理与多包构建。
cabal-installCabal 包管理与构建系统,Stack 的底层依赖,stack build最终交由 Cabal 编译。
zlibzlib 压缩库,是 Stack/Cabal 下载与解析包时可能链接的原生依赖。
hpack从package.yaml自动生成.cabal文件的工具,stack new生成的模板默认使用 hpack。
env.PATH追加/usr/bin到 PATH,保证 Shell 内能调用系统级基础命令。
shell.scripts定义项目级快捷命令。run_test演示了"构建 + 运行"的完整闭环,可通过devbox run run_test调用。

提示:示例目录下还提供了 devbox.lock,它精确锁定了各包在四个平台(aarch64-darwin、aarch64-linux、x86_64-darwin、x86_64-linux)上解析出的 Nix 存储路径,这正是 Devbox 环境可复现性的保证——同一份锁文件在任何机器上都会得到完全一致的二进制。

从锁文件看版本解析结果

devbox.lock 记录了本示例实际解析到的工具链版本,可作为"@latest"具体指向的参考:

包解析版本来源
ghc9.10.3Nixpkgs(含out、doc两个输出)
stack2.13.1Nixpkgs
cabal-install3.16.1.0Nixpkgs
hpack0.38.3Nixpkgs
zlib1.3.2Nixpkgs(含out、dev、static输出)
gmp6.3.0Nixpkgs(含out、dev、info输出)

从锁文件可见,示例中stack的解析时间(2024 年)早于其他包(2026 年),这是因为stack@latest与其余包分别解析自不同时刻的 Nixpkgs commit——这正是 Devbox 按包粒度锁定解析结果的体现。

Stack 配置与项目骨架:stack.yaml和package.yaml

stack.yaml:解析器决定工具链版本

stack.yaml 是 Stack 项目的核心配置,它通过resolver指定 Stackage 快照(snapshot),从而一次性锁定编译器版本与依赖包集合:

resolver: url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/20/4.yaml packages: - .
  • resolver指向 LTS-20.4 快照,其中定义了 GHC 版本与可用的依赖版本;
  • packages声明构建的本地包(.即当前目录);
  • 文件注释中还给出了其他常见用法:extra-deps添加快照之外的依赖(可固定到 git commit)、system-ghc控制是否使用 PATH 中的 GHC、compiler-check允许快照指定的 GHC 更新小版本等。

package.yaml 与 hpack 的协作

package.yaml 采用 hpack 的 YAML 格式描述包元数据,字段与生成的.cabal文件一一对应:

name: my-project version: 0.1.0.0 dependencies: - base >= 4.7 && < 5 ghc-options: - -Wall - -Wcompat - -Widentities - -Wincomplete-record-updates - -Wincomplete-uni-patterns - -Wmissing-export-lists - -Wmissing-home-modules - -Wpartial-fields - -Wredundant-constraints library: source-dirs: src executables: my-project-exe: main: Main.hs source-dirs: app ghc-options: - -threaded - -rtsopts - -with-rtsopts=-N dependencies: - my-project tests: my-project-test: main: Spec.hs source-dirs: test dependencies: - my-project

该文件在构建时由 hpack 生成 my-project.cabal(文件头部标注"generated from package.yaml by hpack version 0.35.0")。关键配置解读:

  • dependencies: base >= 4.7 && < 5指定基础库版本范围;
  • 一组严格的-Wall警告选项默认开启,有助于及早发现潜在问题;
  • library.source-dirs: src将src/编译为库模块Lib;
  • 可执行程序my-project-exe的入口是app/Main.hs,并依赖本地库my-project;-threaded、-rtsopts、-with-rtsopts=-N分别启用多线程运行时、运行时选项与多核并行;
  • 测试套件my-project-test以 test/Spec.hs 为入口(当前为占位实现,输出 "Test suite not yet implemented")。

底层原理:Devbox Haskell 插件如何组合工具链

在 Devbox 中,Haskell 环境并非简单地把各包二进制扔进 PATH,而是由官方插件(plugins/haskell.json)注入一个 Nix Flake 来实现包间联动。插件配置声明如下:

{ "name": "haskell", "version": "0.0.2", "description": "Haskell plugin", "packages": [ "path:{{ .Virtenv }}/flake" ], "__remove_trigger_package": true, "create_files": { "{{ .Virtenv }}/flake/flake.nix": "haskell/flake.nix" } }

其工作方式(可从源码结构推断):

  1. 插件在虚拟环境目录({{ .Virtenv }})创建flake/flake.nix,内容来自模板 plugins/haskell/flake.nix;
  2. 该 Flake 的default输出由ghcWithPackages构造——它会将项目声明的包分类处理:
    • stack、cabal-install这类工具被识别为编译链组件;
    • 形如haskellPackages.*或haskell.packages.<版本>.*的包则作为额外 Haskell 库注入 GHC 环境;
    • 其余包被过滤掉(模板中通过builtins.match逐项匹配并拼接结果);
  3. ghc包被识别为编译器的版本锚点,用于决定使用哪个 Haskell 包集合;
  4. 插件通过__remove_trigger_package移除触发包,保证最终环境干净。

因此,当你在devbox.json中声明ghc、stack、cabal-install、zlib、hpack、gmp等包后,Devbox 会在 Shell 中组合出一个具备完整构建能力的 GHC + Stack 工具链,无需再手动安装任何系统级依赖。这也是示例 README 中"复制 devbox.json →devbox shell→stack new→stack build"全流程得以一键跑通的根本原因。

进阶指引

  • 想为项目增加其他 Haskell 库依赖,可在devbox.json的packages中加入haskellPackages.<包名>(插件 Flake 会自动注入),或在stack.yaml中通过extra-deps声明;
  • 锁定具体工具版本时,先devbox search <pkg>查询可用版本,再替换@latest;
  • 在 examples/development/haskell/README.md 中可以查看该示例的完整说明;示例的devbox.json与devbox.lock则可以作为任何新 Haskell 项目的起点配置。
  • 开发工具
  • CLI

【免费下载链接】devbox

Instant, easy, and predictable development environments

项目地址:https://gitcode.com/GitHub_Trending/dev/devbox
点击查看免费下载
上一篇:Roc 语言 Dict.from_iter 实战指南:从键值对迭代器构建字典的完整行为解析
下一篇:ZeroClaw 多智能体实战指南:添加第二智能体、跨智能体文件/记忆访问与对等组配置

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询