The purpose of ROS-specific version of buildEnv in this overlay is to
reduce the length of environment variables when using many ROS
packages. However, currently it works only for ROS 1 and not for
ROS 2. This commit is an attempt to fix that.
Although the change looks trivial, it took me multiple full days to
figure out what to change and how. The following is my understanding
of how handling of environment variables works in ROS 2 and in
nix-ros-overlay and why the change in this commit works. I'm not
completely sure that it's all correct so feel free to complain if not.
- Every ament_cmake ROS package contains a $out/share/*/local_setup.sh
script, generated by ament CMake macros, which is responsible for
setting environment variables required for proper function of the
package under ROS 2. Every package extends AMENT_PREFIX_PATH and it
may extend other variables such as PATH. The default prefix used for
extending the variables is specified at compile time and is equal to
package's Nix store path ($out).
- local_setup.sh files are sourced when building dependent ROS
packages. In nix-ros-overlay, this is accomplished by
ament-cmake-core-setup-hook, which is automatically propagated to
all dependents.
- ROS-specific buildEnv ensures that ROS packages are not further
propagated downstream but non-ROS packages are.
ament-cmake-core-setup-hook is a non-ROS package (it's a Nix native
package) so if any package in the buildEnv depends on it, it is
propagated out of buildEnv. Therefore dependents of the buildEnv
source all local_setup.sh files from the buildEnv (and from other
ROS packages outside of buildEnv, if there are any).
- The problem when sourcing local_setup.sh files now is the default
prefix built into them, which causes every package to have a
separate entry in the extended variables. However, if the file is
sourced with AMENT_CURRENT_PREFIX variable set, its value overrides
the default prefix. That's what we do in this commit. We set
AMENT_CURRENT_PREFIX to the store path of the sourced package; in
case of normal ROS packages it's equal to the default builtin
prefix, but in case of buildEnv, it's different and all packages in
the environment share the same prefix.
I'm testing this change with the following flake.nix:
{
inputs = {
nix-ros-overlay.url = "/path/to/repo/with/this/commit";
nixpkgs.follows = "nix-ros-overlay/nixpkgs";
};
outputs = { self, nixpkgs, nix-ros-overlay }:
let
pkgs = import nixpkgs {
system = "x86_64-linux";
overlays = [ nix-ros-overlay.overlays.default ];
};
rosDistro = pkgs.rosPackages.humble;
buildEnv = rosDistro.buildEnv {
paths = with rosDistro; [
demo-nodes-cpp
];
};
in
{
devShells.x86_64-linux.default = pkgs.mkShell {
name = "ros-env-test";
packages = [ buildEnv ];
};
packages.x86_64-linux = {
default = buildEnv;
inherit (rosDistro) demo-nodes-cpp;
};
};
}
Running `nix develop` and then:
echo $AMENT_PREFIX_PATH | tr : \\n | wc -l
without this commit returns 71 entries, while with this commit the
result in a single entry!