如何让cabal和nix一起工作

mb1*_*b14 33 haskell cabal nix

据我所知,Nixcabal沙箱的替代品.我终于设法安装了Nix,但我仍然不明白它如何取代沙盒.

我知道你不需要使用Nix和封装版GHC的cabal; 但是如果你想发布一个软件包,你需要在某个时候用cabal打包它.因此,您需要能够在NIX中编写和测试您的cabal配置.你是怎样做的?

理想情况下,我想要一个类似于cabal沙箱但在NIX中"包含"的环境,这可能吗?事实上,我真正想要的是等效的嵌套沙箱 - 因为我通常使用由多个包组成的项目.

更新我当前的工作流程

目前我在2或3个独立项目(P1,P2,P3)上工作,每个项目由2或3个cabal模块/包组成,假设P1:L11,L12(库)和E11(可执行文件).E11取决于L12,它取决于L11.我主要是从库中拆分可执行文件,因为它们是私有的,并保存在私有git仓库中.

理论上,每个项目都可以拥有自己的沙箱(在其子模块之间共享).我尝试过(有一个L11 L12和E11的普通沙箱),但它很快就会烦人,因为如果修改L11,你就无法重建它,因为E11依赖它,所以我必须首先卸载E11重新编译L11.情况可能并非如此,但我遇到了类似的问题.如果我偶尔修改L11,这样会好的,但在实践中,我更改了E11.

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

因此,通过使用Nix,我正在努力为每个项目设置单独的cabal"环境",这解决了上述所有问题.

希望这更清楚.

och*_*les 47

这些天我使用Nix和cabal完成所有开发工作,我很高兴地说它们很好地协调工作.我当前的工作流程是非常新的,因为它依赖于nixpkgs刚刚到达主分支的功能.因此,您需要做的第一件事是nixpkgs从Github 克隆:

cd ~
git clone git://github.com/nixos/nixpkgs
Run Code Online (Sandbox Code Playgroud)

(将来这不是必要的,但现在是这样).

单项目使用

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

nix-env -f ~/nixpkgs -i -A haskellngPackages.cabal2nix -A haskellngPackages.cabal-install
Run Code Online (Sandbox Code Playgroud)

从这一点来看,这一切都非常明确.

如果您正在开始一个新项目,您可以cabal init像往常一样调用新目录.准备好构建时,可以将此.cabal文件转换为开发环境:

cabal init
# answer the questions
cabal2nix --shell my-project.cabal > shell.nix
Run Code Online (Sandbox Code Playgroud)

这为您提供了一个shell.nix可以使用的文件nix-shell.你不需要经常使用它 - 你经常使用它的唯一时间是cabal configure:

nix-shell -I ~ --command 'cabal configure'
Run Code Online (Sandbox Code Playgroud)

cabal configure缓存所有内容的绝对路径,所以现在当你想要构建时,你只需cabal build正常使用:

cabal build
Run Code Online (Sandbox Code Playgroud)

每当您的.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
Run Code Online (Sandbox Code Playgroud)

这些default.nix表达式是函数,所以我们现在做不了多少.要调用这些函数,我们编写自己的shell.nix文件来解释如何组合所有内容.因为engine-io/shell.nix,我们不需要做任何特别聪明的事情:

with (import <nixpkgs> {}).pkgs;
(haskellngPackages.callPackage ./. {}).env
Run Code Online (Sandbox Code Playgroud)

因为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
Run Code Online (Sandbox Code Playgroud)

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

这里的关键观察是,无论何时engine-io发生变化,我们都需要重新配置socket-io以检测这些变化.这就像跑步一样简单

cd socket-io; nix-shell -I ~ --command 'cabal configure'
Run Code Online (Sandbox Code Playgroud)

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

  • 这个命令(`cabal2nix --shell my-project.cabal> shell.nix`)对我不起作用.相反,我不得不使用`cabal2nix --shell ./.> shell.nix`并编辑`src`属性以指向`./src`. (3认同)
  • @ErikAllik我们"未来"中的haskellng现在只是nixpkgs中包装haskell东西的标准方式(我花了一段时间才弄明白我最近跳到nixos;有很多教程告诉你使用haskellng ).我尝试使用stack + nix,因为我使用的是没有nix的堆栈并且它有一些集成,但到目前为止我还是更喜欢cabal + nix; nix本身提供了沙盒,lts包集,以及依赖于非haskell项目的能力,我发现使用nix-shell比在stack exec中混合更容易. (3认同)
  • @KrisNuttycombe我认为Ollie的意思是`haskellngPackages.cabal-install`. (2认同)
  • @ErikAllik有关Stack + Nix的相关链接:http://www.tweag.io/blog/stack-nix-portable-reproducible-builds和https://github.com/commercialhaskell/stack/blob/master/doc/nix_integration .MD (2认同)