lopsided98 / nix-ros-overlay

ROS overlay for the Nix package manager
Apache License 2.0
198 stars 79 forks source link

nix shell .#rosPackages.humble.ros2cli fails because of rcutils #215

Closed kjeremy closed 1 year ago

kjeremy commented 2 years ago

It fails with Package 'rcutils' exports the library 'rcutils' which couldn't be found

nix log /nix/store/9f26igdgy7n72f4hs95kq37h8i1qzjnh-ros-humble-rcl-logging-interface-2.3.0-r2.drv
@nix { "action": "setPhase", "phase": "unpackPhase" }
unpacking sources
unpacking source archive /nix/store/1f891w21mvz88jfsflndf92cxmsmwpbw-2.3.0-2.tar.gz
source root is rcl_logging-release-release-humble-rcl_logging_interface-2.3.0-2
setting SOURCE_DATE_EPOCH to timestamp 1650419914 of file rcl_logging-release-release-humble-rcl_logging_interface-2.3.0-2/test/test_get_logging_directory.c>
@nix { "action": "setPhase", "phase": "patchPhase" }
patching sources
@nix { "action": "setPhase", "phase": "configurePhase" }
setting SOURCE_DATE_EPOCH to timestamp 1650419914 of file rcl_logging-release-release-humble-rcl_logging_interface-2.3.0-2/test/test_get_logging_directory.c>
@nix { "action": "setPhase", "phase": "patchPhase" }
patching sources
@nix { "action": "setPhase", "phase": "configurePhase" }
configuring
fixing cmake files...
cmake flags: -DCMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRY=OFF -DCMAKE_FIND_USE_PACKAGE_REGISTRY=OFF -DCMAKE_EXPORT_NO_PACKAGE_REGISTRY=ON -DCMAKE_BUILD_TYPE=Rel>
-- The C compiler identification is GNU 11.3.0
-- The CXX compiler identification is GNU 11.3.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /nix/store/ykcrnkiicqg1pwls9kgnmf0hd9qjqp4x-gcc-wrapper-11.3.0/bin/gcc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /nix/store/ykcrnkiicqg1pwls9kgnmf0hd9qjqp4x-gcc-wrapper-11.3.0/bin/g++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Found ament_cmake_ros: 0.10.0 (/nix/store/2lkpv7zwmq6m8xwl1g2vw0mbarcf31aj-ros-humble-ament-cmake-ros-0.10.0-r3-dev/share/ament_cmake_ros/cmake)
-- Found Python3: /nix/store/vl15w3q3ck77gk0yi03abi3xghxhlwgw-python3-3.9.13/bin/python3.9 (found version "3.9.13") found components: Interpreter 
-- Found rcutils: 5.1.1 (/nix/store/c0kq1v5q2h4ii5gq8iamsrp5nxxsfx65-ros-humble-rcutils-5.1.1-r2-dev/share/rcutils/cmake)
CMake Error at /nix/store/c0kq1v5q2h4ii5gq8iamsrp5nxxsfx65-ros-humble-rcutils-5.1.1-r2-dev/share/rcutils/cmake/ament_cmake_export_libraries-extras.cmake:48 >
  Package 'rcutils' exports the library 'rcutils' which couldn't be found
Call Stack (most recent call first):
  /nix/store/c0kq1v5q2h4ii5gq8iamsrp5nxxsfx65-ros-humble-rcutils-5.1.1-r2-dev/share/rcutils/cmake/rcutilsConfig.cmake:41 (include)
  CMakeLists.txt:19 (find_package)
lopsided98 commented 2 years ago

I can't reproduce this. nix shell .#rosPackages.humble.ros2cli is not valid, but nix shell .#humble.ros2cli builds successfully.

kjeremy commented 2 years ago

This is a bug on our end. We split catkin packages outputs into out and dev to save space:

# Overlaid buildRosPackage, with automatic support for splitting packages into
# multiple outputs for build- versus runtime components.

{ lib, buildSingleOutputRosPackage }:
let
  # Deep Nix magic: extraRuntimePackages needs to be kept consistent with
  # propagatedBuildInputs, unless it is explicitly overridden.  To do
  # that, override overrideAttrs using overrideAttrs such that this
  # function's overrides are applied after other overrides.
  consistentExtraRuntimePackages = drv: fn:
    let
      overridden = drv.overrideAttrs fn;
    in
    overridden.overrideAttrs (o: {
      extraRuntimePackages = o.extraRuntimePackages or (lib.packaging.onlyInstalledOutputs o.propagatedBuildInputs or [ ]);

      # Only apply our override once after all other overrideAttrs have
      # been applied.  To do this, we apply the caller's overrides, then
      # reapply our own overlay to it.
      passthru = o.passthru or { } // {
        overrideAttrs = consistentExtraRuntimePackages overridden;
        # XXX also overrideDerivation?
      };
    });

  # Split a package into "out" and "dev" outputs.  Because the generated
  # cmake scripts contain references to other development packages in the
  # nix store, we don't want them in the final closure.  Concretely,
  # splitting packages requires:
  #  - Moving the cmake and message definition files over
  #  - Copying package.xml since catkin gets confused when it can't find it
  #    at both build- and runtime
  #  - Add a propagated-build-inputs file to the "out" output which
  #    propagates only the runtime paths for each propagated package.
  #    nix-ros-overlay's buildEnv abuses propagation to collect runtime
  #    dependencies, so we need to tell it which dependencies to collect.
  #  - Rewrite some relative paths in cmake scripts so that e.g. genmsg can
  #    find its scripts.  Catkin packages often assume that they are
  #    contained in a single directory, but we violate that assumption.
  #    This uses a simple heuristic that might not be entirely reliable:
  #    CATKIN_PACKAGE_BIN_DIR or similar in the source script means it's
  #    looking for a script or something in the root of the ROS workspace;
  #    in Nix, that's effectively $out).
  splitPackageOutputs = o: {
    outputs = lib.unique (o.outputs or [ "out" ] ++ [ "dev" ]);
    outputDev = "dev";

    postPatch = o.postPatch or "" + ''
      for f in cmake/*-extras.cmake.em; do
          p="$(sed 's:cmake/\(.*\)-extras\.cmake\.em:\1:' <<<"$f")";
          sed -i '/CATKIN_\(PACKAGE\|GLOBAL\)_[A-Z]*_DESTINATION/s:''${'"$p"'_DIR}[/.]*:'"$out"/: $f
      done
    '';
    postFixupHooks = o.postFixupHooks or [ ] ++ [
      ''
        mkdir -p $dev

        if [[ -d $out/share ]]; then
            pushd $out/share

            for d in */cmake */msg; do
                mkdir -p $dev/share/"$(dirname "$d")"
                mv $d $dev/share/"$(dirname "$d")"
            done

            for p in */package.xml; do
                mkdir -p $dev/share/"$(dirname "$p")"
                cp $p $dev/share/"$(dirname "$p")"
            done

            popd
        fi

        if [[ -e $dev/nix-support/propagated-build-inputs && -z "$dontPropagateToOut" ]]; then
            mkdir -p $out/nix-support
            echo "$extraRuntimePackages" >$out/nix-support/propagated-build-inputs
        fi
      ''
    ];
  };

  # More deep Nix magic: we're overriding buildRosPackage with a
  # function, but want buildRosPackage.overlay to continue to work.  Use
  # makeOverridable to convert our function to an overridable functor,
  # then propagate any overridden arguments into the buildRosPackage that
  # we're overriding.  Finally, actually call the overridden
  # buildRosPackage and apply our overrides to the resulting derivation.
  buildSplitRosPackage = lib.makeOverridable
    (args: attrs: lib.pipe attrs [
      (buildSingleOutputRosPackage.override args)
      (drv: consistentExtraRuntimePackages drv splitPackageOutputs)
    ])
    { };
in
buildSplitRosPackage

This works pretty well for ROS1 but ROS2 has problems with the location of ament_index and finding the lib if the index and cmake files are in the dev output.