35

据我了解,Nixcabal sandbox的替代品。我终于设法安装了 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。我主要从库中拆分可执行文件,因为它们是私有的并且保存在私有 git 存储库中。

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

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

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

希望这更清楚。

4

1 回答 1

52

这些天,我使用 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

于 2015-01-15T18:43:22.687 回答