カラクリサイクル

「人並みの人生」なんて失かった人の技術ブログ

CPMFindPackage や FetchContent_Declare を使った CMake プロジェクトを nixpkgs でビルトする

あとで忘れると面倒くさそうなのでメモ。

話の前提

Nixを使ってCMakeを使ったプロジェクトをビルドしようとすると、時々 CPMFindPackageFetchContent_Declare を使ったプロジェクトに出くわします。

CPMFindPackageFetchContent_Declare はプロジェクトの configure 時にネットワークを利用するため、Nixのビルドシステムと相性が悪いのですが、とは言えこれをビルドするにはどうしたらいいんだ?というのが今回のメモです。

解決策

以下の二つをやる。

  1. cmakeFlags-DCPM_USE_LOCAL_PACKAGES=YES-DFETCHCONTENT_FULLY_DISCONNECTED=YES を指定する
  2. build/_deps/${name}-src に依存するファイルを突っ込む

まず(1)について。

これは CPMFindPackageFetchContent_Declare のネットワークアクセスを無効化するオプションで、この二つを指定することによって configurePhase でのネットワークアクセスを完全に遮断できます。

次に(2)についてですが、これは CPMFindPackageFetchContent_Declare は依存の解決時に build/_deps/${name}-src を参照するため、ここにソースを突っ込めば万事解決、という訳です。

ちょっとした具体例

例えば nlohmann_jsonCPMFindPackage で取得していた場合、まず fetchFromGitHub で適当な変数へソースファイルのパスを突っ込みます:

nlohmann_json = fetchFromGitHub {
  owner = "nlohmann";
  repo = "json";
  rev = "230bfd15a2bb7f01ebb3fcd3cf898b697ef43c48";
  hash = "sha256-baz2yhWPjz2anjOComV3ju3dG42bXxV9erWfj5WiSGw=";
};

次いで preConfigure フェーズへ下記のようなコードを仕込みます:

  preConfigure = ''
    mkdir -p build/_deps
    cp -r --no-preserve=ownership,mode ${nlohmann_json} build/_deps/nlohmann_json-src
  '';

最期にこれを使うCMakeプロジェクトをビルドすればOK、という事なります。

ただこの preConfigure の書き方は依存が大量にあると面倒なので、実際には下記のようなコードを利用しています:

  preConfigure = let
    deps = {
      nlohmann_json = fetchFromGitHub {
        owner = "nlohmann";
        repo = "json";
        rev = "230bfd15a2bb7f01ebb3fcd3cf898b697ef43c48";
        hash = "sha256-baz2yhWPjz2anjOComV3ju3dG42bXxV9erWfj5WiSGw=";
      };
    };
  in ''
    mkdir -p build/_deps
    ${lib.concatMapAttrsStringSep "\n" (
      name: src: "cp -r --no-preserve=ownership,mode ${src} build/_deps/${name}-src"
    ) deps}
  '';

以上

と言うことで大雑把なメモは以上です。分かってしまえば簡単ですね(本当か?)