lopsided98 / nix-ros-overlay

ROS overlay for the Nix package manager
Apache License 2.0
174 stars 68 forks source link

depthai* packages fail to build downloading hunter dependencies to /homeless-shelter #412

Open thearthur opened 1 month ago

thearthur commented 1 month ago

the depthai packages are failing to build because they try to download dependencies to /homeless-shelter

ros-humble-depthai> -- Generating new toolchain...
ros-humble-depthai> -- Using toolchain file: /build/depthai-core-release-release-humble-depthai-2.24.0-1/build/generated/toolchain.cmake
ros-humble-depthai> CMake Error at cmake/HunterGate.cmake:241 (file):
ros-humble-depthai>   directory
ros-humble-depthai>
ros-humble-depthai>     "/homeless-shelter/.hunter/_Base/Download/Hunter/0.23.322/cb0ea1f"
ros-humble-depthai>
ros-humble-depthai>   creation failed (check permissions).
ros-humble-depthai> Call Stack (most recent call first):
ros-humble-depthai>   cmake/HunterGate.cmake:509 (hunter_gate_download)
ros-humble-depthai>   CMakeLists.txt:39 (HunterGate)
ros-humble-depthai>
ros-humble-depthai>
ros-humble-depthai> -- Configuring incomplete, errors occurred!

here is a minimal flake with the issue, it contains my attempt to fix it by setting HOME in an override (which i don't think is correct)

{
  description = "Hero Jr.";
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs?ref=master";
    flake-utils.follows = "ros-flake/flake-utils";
    ros-flake.url = "github:lopsided98/nix-ros-overlay";
  };

  outputs = { self, nixpkgs, ros-flake, flake-utils }:
    flake-utils.lib.eachDefaultSystem
      (system:
        let
          ros = ros-flake.legacyPackages.${system};
          pkgs = import nixpkgs { inherit system; overlays = [  ]; };
          humble-overrided = ros.humble.overrideScope (final: prev: {
            new-depthai = prev.depthai.overrideAttrs (old: {
              cmakeFlags = [ "-DDEPTHAI_ENABLE_BACKWARD=OFF_____THIS_DOES_NOT_HAPPEN________________" ];
              preBuild = ''
                          export HOME=$(mktemp -d)
                         '';
            });});
        in
        {
          inherit pkgs;
          packages = {};
          devShells.default =
            pkgs.mkShell {
              buildInputs = (with humble-overrided; [
                              ros-core
                              depthai
                            ]);
             };
        }
      );

  nixConfig = {
    extra-substituters = [ "https://ros.cachix.org" "https://robossembler.cachix.org" ];
    extra-trusted-public-keys = [
      "ros.cachix.org-1:dSyZxI8geDCJrwgvCOHDoAfOm5sV1wCPjBkKL+38Rvo="
      "robossembler.cachix.org-1:56jBJHroRQSGpZFkW8XMquuzQTjAF/XTo6MogmBM7SQ="
    ];
  };
wentasah commented 1 month ago

Hi! The root of the problem is that the package tries to download the dependencies at build time. Nix builds are run in a sandbox without network access, so the build would fail even if you create the directory (as you're trying in your example).

We solve these issues in this overlay with the help of patchVendorUrl function, which replaces external URLs with prefetched Nix store paths. See for example here. With this package, the complication (from my POV) is that they use some kind of package manager (Hunter) and with it this simple patching would probably not work.

I'm not sure whether it's possible to persuade cmake not to use hunter, but system-provided dependencies. There is a HUNTER_ENABLED cmake option, but simple disabling of it doesn't help much. cmake then seems to use find_package to find the bzip2 library, but it fails to find it because it doesn't contain *.cmake file, only *.pc files. Simple adding pkg-config doesn't help either.

So I ended here. You can continue by studying how Hunter works and how to replace it with Nix. It will require patching of cmake code and maybe other things. This is the derivation I ended up experimenting with:

new-depthai = ros.humble.depthai.overrideAttrs (old: {
  postPatch = ''
    sed -i -e '2a find_package(PkgConfig REQUIRED)' CMakeLists.txt
  '';
  cmakeFlags = [ "-DHUNTER_ENABLED=OFF" ];
  nativeBuildInputs = old.nativeBuildInputs ++ [
    pkgs.pkg-config
  ];
  propagatedBuildInputs = old.propagatedBuildInputs ++ [
    pkgs.bzip2
  ];
});
thearthur commented 1 month ago

@wentasah it looks like pre-populating the .hunter/ directory from a tarball hosted separately could work through i'm not sure if that's a wise course or not because every specific hash of depthai would need specific build files, and would not benefit from the rest of the dependency management system. Does this sound worth pursuing?

wentasah commented 1 month ago

Yeah, this might work. Actually, this would be similar to how Gradle applications are packaged in nixpkgs. Their dependencies are provided as a fixed-output derivation (FOD). This has the advantage that FODs can access network to download the dependencies. Then, the application has this FOD as one of the buildInputs.

Here, in the simplest case, one could set HUNTER_ROOT to the path of this FOD. In practice, something more complex will probably be needed, because it seems that hunter intermixes downloaded data with .lock files, so one would need to copy them from the Nix store (which is read-only) to some writable location.

With respect to updating the hash - yes, it would be annoying, but IMO updating a single hash is still better than requiring everybody to build the package manually. It seems depthai in ROS has just a few updates a year so it won't be big problem. And if it is, update of the hash could be automated in the CI.