nix-ros-overlay/distros/build-env/default.nix
Jeremy Kolb a6cc2182f7 Use makeWrapper as a native build input
Fixes cross-compilation
2022-07-16 23:41:21 -04:00

95 lines
3.5 KiB
Nix

# Provides a specialized version of buildEnv, designed specifically for ROS
# packages. It is useful when using a large number of ROS packages that would
# otherwise cause ROS_PACKAGE_PATH or other environment variables to become too
# long.
#
# All ROS packages in the 'paths' closure are added to the environment, while
# other packages are propagated. This makes it usable in nix-shell, while
# preventing ROS_PACKAGE_PATH and CMAKE_PREFIX_PATH from becoming too large due
# to a huge number of ROS packages.
#
# By default, all binaries in the environment are wrapped, setting the relevant
# ROS environment variables, allowing use outside of nix-shell.
{ lib, stdenv, buildPackages, writeText, buildEnv, makeWrapper }:
{ paths ? [], wrapPrograms ? true, ... }@args:
with lib;
let
propagatePackages = packages: let
validPackages = filter (d: d != null) packages;
partitionedPackages = partition (d: d.rosPackage or false) validPackages;
rosPackages = partitionedPackages.right;
otherPackages = partitionedPackages.wrong;
rosPropagatedPackages = unique (concatLists (catAttrs "propagatedBuildInputs" rosPackages));
recurse = propagatePackages rosPropagatedPackages;
in if length validPackages == 0 then {
rosPackages = [];
otherPackages = [];
} else {
rosPackages = unique (rosPackages ++ recurse.rosPackages);
otherPackages = unique (otherPackages ++ recurse.otherPackages);
};
propagatedPaths = propagatePackages paths;
env = (buildEnv (args // {
name = "ros-env";
# Only add ROS packages to environment. The rest are propagated like normal.
# ROS packages propagate a huge number of dependencies, which are added all
# added to the environment with nix-shell -p, but would not normally not be
# added with buildEnv. This file adds all specified ROS packages and their
# ROS dependencies to the environment, while propagating other packages like
# nix-shell -p does.
paths = propagatedPaths.rosPackages;
nativeBuildInputs = optional wrapPrograms makeWrapper;
postBuild = ''
"${buildPackages.perl}/bin/perl" "${./setup-hook-builder.pl}"
'' + optionalString wrapPrograms ''
if [ -d "$out/bin" ]; then
find -L "$out/bin" -executable -type f -xtype l -print0 | \
while IFS= read -r -d "" link; do
file="$(readlink "$link")"
rm "$link"
# Remove unwrapped versions of binaries
if [[ "$(basename "$link")" == .*-wrapped ]]; then continue; fi
makeWrapper "$file" "$link" \
--prefix PATH : "$out/bin" \
--prefix CMAKE_PREFIX_PATH : "$out" \
--prefix AMENT_PREFIX_PATH : "$out" \
--prefix ROS_PACKAGE_PATH : "$out/share"
done
fi
'';
passthru.env = stdenv.mkDerivation {
name = "interactive-ros-env";
buildInputs = [ env ];
buildCommand = ''
echo >&2 ""
echo >&2 "*** ROS 'env' attributes are intended for interactive nix-shell sessions, not for building! ***"
echo >&2 ""
exit 1
'';
};
})).overrideAttrs ({ buildCommand, passAsFile ? [], ...}: {
# Hack to allow buildEnv to use propagatedBuildInputs
buildCommand = null;
oldBuildCommand = buildCommand;
passAsFile = (if passAsFile == null then [] else passAsFile) ++ [ "oldBuildCommand" ];
propagatedBuildInputs = propagatedPaths.otherPackages;
buildPhase = ''
runHook preBuild
. "$oldBuildCommandPath"
runHook postBuild
'';
phases = [ "buildPhase" "fixupPhase" ];
});
in env