gpt4 book ai didi

haskell - 如何让 cabal 和 nix 一起工作

转载 作者:行者123 更新时间:2023-12-03 08:39:23 26 4
gpt4 key购买 nike

据我了解,尼克斯 的替代品 cabal 沙盒 .
我终于设法安装了 Nix,但我仍然不明白它如何取代沙箱。

我知道您不需要使用 Nix 和 GHC 的包装版本的 cabal;但是,如果你想
要发布一个包,您有时需要使用 cabal 对其进行打包。因此,您需要能够在 NIX 中编写和测试您的 cabal 配置。你是怎样做的?

理想情况下,我想要一个类似于 cabal 沙盒但“包含”在 NIX 中的环境,这可能吗?事实上,我真正想要的是嵌套沙箱的等价物——因为我通常从事由多个包组成的项目。

更新我当前的工作流程

目前我从事 2 或 3 个独立项目(P1、P2、P3),每个项目由 2 或 3 个 cabal 模块/包组成,假设 P1:L11、L12(库)
和 E11(可执行文件)。 E11 依赖于 L12,而 L12 又依赖于 L11。我主要从库中拆分可执行文件,因为它们是私有(private)的并且保存在私有(private) git 存储库中。

理论上,每个项目都可以拥有自己的沙箱(在其子模块之间共享)。我试过了(L11 L12 和 E11 有一个公共(public)沙箱),但它很快就很烦人,因为如果你修改 L11,你不能重建它,因为 E11 依赖它,所以我必须先卸载 E11 才能重新编译 L11。
可能并非完全如此,但我遇到了类似的问题。
如果我偶尔修改 L11,这会很好,但实际上,我对它的修改比 E11 更多。

由于共享沙箱不起作用,所以我为每个包解决方案返回了一个沙箱。它正在工作,但并不理想。
主要问题是如果我修改 L11,我需要编译两次(一次在 L11 中,然后再次在 E11 中)。此外,众所周知,每次我开始一个新的沙箱时,我都需要等待一段时间才能下载并重新编译所有包。

因此,通过使用 Nix,我希望能够为每个项目设置单独的 cabal “环境”,从而解决上述所有问题。

希望这更清楚。

最佳答案

这些天,我使用 Nix 和 cabal 进行所有开发,我可以很高兴地说它们非常和谐地工作。我当前的工作流程非常新,因为它依赖于 nixpkgs 中的功能。刚刚到达主分支。因此,您需要做的第一件事是克隆 nixpkgs来自 Github:

cd ~
git clone git://github.com/nixos/nixpkgs

(将来这不是必需的,但现在是)。

单个项目使用

现在我们有了 nixpkgs克隆,我们可以开始使用 haskellng套装。 haskellng是对我们如何在 Nix 中打包东西的重写,我们感兴趣的是更可预测(包名称与 Hackage 包名称匹配)和更可配置。首先,我们将安装 cabal2nix工具,它可以为我们自动化一些事情,我们还将安装 cabal-install提供 cabal可执行:

nix-env -f ~/nixpkgs -i -A haskellngPackages.cabal2nix -A haskellngPackages.cabal-install

从这一点来看,一切都非常清晰。

如果您开始一个新项目,您可以调用 cabal init像往常一样在新目录中。当你准备好构建时,你可以打开这个 .cabal文件进入开发环境:

cabal init
# answer the questions
cabal2nix --shell my-project.cabal > shell.nix

这会给你一个 shell.nix文件,可与 nix-shell 一起使用.不过,您不需要经常使用它——您通常会使用它的唯一一次是与 cabal configure 一起使用。 :

nix-shell -I ~ --command 'cabal configure'
cabal configure缓存所有内容的绝对路径,所以现在当你想要构建时,只需使用 cabal build像平常一样:

cabal build

每当您的 .cabal您需要重新生成的文件更改 shell.nix - 只需运行上面的命令,然后 cabal configure然后。

多项目使用

该方法可以很好地扩展到多个项目,但需要更多的手动工作才能将所有内容“粘合”在一起。为了演示这是如何工作的,让我们考虑一下我的 socket-io 图书馆。这个库依赖于 engine-io ,我通常同时开发两者。

Nix-ifying 这个项目的第一步是生成 default.nix每个人旁边的表达式 .cabal文件:

cabal2nix engine-io/engine-io.cabal > engine-io/default.nix
cabal2nix socket-io/socket-io.cabal > socket-io/default.nix

这些 default.nix表达式是函数,所以我们现在无能为力。为了调用这些函数,我们编写了自己的 shell.nix解释如何组合所有内容的文件。对于 engine-io/shell.nix ,我们不必做任何特别聪明的事情:
with (import <nixpkgs> {}).pkgs;
(haskellngPackages.callPackage ./. {}).env

对于 socket-io ,我们需要依赖 engine-io :
with (import <nixpkgs> {}).pkgs;
let modifiedHaskellPackages = haskellngPackages.override {
overrides = self: super: {
engine-io = self.callPackage ../engine-io {};
socket-io = self.callPackage ./. {};
};
};
in modifiedHaskellPackages.socket-io.env

现在我们有 shell.nix在每个环境中,所以我们可以使用 cabal configure和以前一样。

这里的关键观察是,每当 engine-io更改,我们需要重新配置 socket-io来检测这些变化。这就像运行一样简单

cd socket-io; nix-shell -I ~ --command 'cabal configure'

Nix 会注意到 ../engine-io已更改,并在运行前重建它 cabal configure .

关于haskell - 如何让 cabal 和 nix 一起工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27968909/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com