web-dev-qa-db-ja.com

cabalとnixを連携させる方法

私が理解している限り、Nixcabal sandboxの代わりになります。ついにNixをインストールできましたが、サンドボックスを置き換える方法がまだわかりません。

NixとラップバージョンのGHCを使用する陰謀団は必要ないことを理解しています。ただし、パッケージを公開する場合は、ある時点でcabalを使用してパッケージ化する必要があります。したがって、NIX内でcabal構成を記述してテストできる必要があります。どうやってそれをしますか?

理想的には、陰謀団のサンドボックスに似ているが、NIX内に「含まれている」環境が欲しいのですが、それは可能ですか?実際、私が本当に望んでいるのは、ネストされたサンドボックスに相当するものです。通常、複数のパッケージで作成されたプロジェクトで作業します。

現在のワークフローに関する更新

現在、私は2つまたは3つの独立したプロジェクト(P1、P2、P3)に取り組んでいます。これらは、それぞれ2つまたは3つのcabalモジュール/パッケージで構成されています。たとえば、P1:L11、L12(ライブラリ)、およびE11(実行可能ファイル)です。 E11はL11に依存するL12に依存します。実行可能ファイルはプライベートであり、プライベートgitリポジトリに保持されているため、主にライブラリから実行可能ファイルを分割します。

理論的には、各プロジェクトはこの独自のサンドボックス(サブモジュール間で共有)を持つことができます。私はそれを試しましたが(L11 L12とE11に共通のサンドボックスがあります)、L11を変更すると、E11がそれに依存しているため再構築できないため、すぐに面倒です。そのため、L11を再コンパイルするには最初にE11をアンインストールする必要があります。正確には当てはまらないかもしれませんが、私は同様の問題に遭遇します。たまにL11を変更していれば問題ありませんが、実際にはE11よりも変更しました。

共有サンドボックスが機能しないため、パッケージソリューションごとに1つのサンドボックスに戻りました。動作していますが、理想的とは言えません。主な問題は、L11を変更した場合、2回コンパイルする必要があることです(1回はL11で、次にもう一度E11で)。また、誰もが知っているように、新しいサンドボックスを開始するたびに、すべてのパッケージがダウンロードされて再コンパイルされるまでしばらく待つ必要があります。

したがって、Nixを使用することで、プロジェクトごとに個別の陰謀団の「環境」を設定できるようになり、上記のすべての問題が解決されます。

これがより明確になることを願っています。

33
mb14

最近はNixとcabalを使ってすべての開発を行っていますが、それらは非常にうまく調和していると喜んで言えます。私の現在のワークフローは非常に新しく、マスターブランチに到達したばかりのnixpkgsの機能に依存しています。そのため、最初に行う必要があるのは、Githubからnixpkgsを複製することです。

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化するための最初のステップは、個々の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を実行する前に再構築します。

47
ocharles