clearpathrobotics / nix-ros-base

40 stars 2 forks source link

nix-ros-base

This repository supplies the base Nix content which underpins the generated package definitions available in nix-ros. Included here are overrides and patches for various upstream packages, new dependencies which aren't packaged upstream, plus the bits of plumbing needed to make package and workspace building function.

The included flake.nix does not actually provide any buildable packages as outputs— currently its outputs are exclusively intended to be consumed by the generated snapshot flakes. However, the flake.lock in this repo is critically important, as it controls which versions of our upstream dependencies (nixpkgs, nix-ros-overlay) we are pinned to.

This repo is supplementary content to a talk given at ROSCon 2022, in Kyoto, Japan.

Video: https://vimeo.com/showcase/9954564/video/767139940

Slides: http://download.ros.org/downloads/roscon/2022/Better%20ROS%20Builds%20with%20Nix.pdf

Nix Installation

You can get Nix by the upstream-suggested curl install, by installing the apt package on an OS new enough to support it, or by using the the container.

To use the upstream-suggested installation, run:

sh <(curl -L https://nixos.org/nix/install) --daemon

Or, if you're on Ubuntu Jammy+, you can bootstrap Nix directly from a distro package:

sudo apt install -y nix-setup-systemd

# Optional but recommended; allows nix usage without root. Must log out
# and in following this invocation:
sudo usermod -a -G nix-users $(whoami)

As a final alternative, you can pull and use the Nix container in docker or podman.

Nix Configuration

Our work heavily leverages the upcoming Flakes feature, so this must be manually enabled in your Nix environment:

# Or to /etc/nix/nix.conf if you're running Nix as root.
echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf

Add the repositories to your nix flake registry with:

nix registry add ros github:clearpathrobotics/nix-ros
nix registry add ros-base github:clearpathrobotics/nix-ros-base

And finally, we suggest setting up Cachix so that you can pull pre-built binaries rather than building everything locally:

# Enter a temporary shell where cachix is available.
nix shell github:cachix/cachix
cachix use nix-ros
exit

Usage

We can now build a ROS environment that holds the packages present in ros_base with:

# ROS 2 "rolling" is also supported; switch to that if you prefer.
nix build ros#noetic.ros_base.ws.contents

You can also reference a specific flake tag snapshot if desired:

nix build ros/20221020-1#noetic.ros_base.ws.contents

A result symlink is now available to inspect a ros installation that has everything in ros_base. This symlink ensures that Nix garbage collection will not remove these paths from the store.

To use this installation we can enter a subshell that uses the binaries of this installation with:

nix develop ros#noetic.ros_base.ws

This environment provides the tools and dependencies that were used to build this package (or packages). The executables from ros_base are available in this subshell, so rostopic and other base tools are available. This step is equivalent to sourcing a ros installation and after this step developer workspaces can be created to extend the base ROS installation.

Architecture

This demonstration uses the ROS package definitions from upstream rosdistro:

https://github.com/ros/rosdistro/

The Noetic and Rolling distributions are frozen and snapshotted daily by a Github Action in our snapshots repo:

https://github.com/clearpathrobotics/rosdistro-snapshots

The snapshots are then cached by our colcon-distro instance, for example:

http://colcon-distro.ext.ottomotors.com/get/noetic/snapshot/20221020.json

The code for this caching layer is in these two repos:

The cache allows the generator in this repo to have access to package content hashes without needing to download the source.

Guide

Some starting points to find your way around in this repository.

lib

The lib directory contains the 'meat' of this repository. This provides the main functionality necessary to build and use ROS through nix;

overrides

Some packages may need extra overrides to ensure they build correctly, or changes to the source code may be necessary to accomodate their use in Nix.

If you wish to iterate on the overrides, it's easy to change or add additional ones by modifying the files in that folder, and then re-running your build with a Nix input override:

nix build ros/20221020-1#noetic.ros_base.ws.contents --override-input base /path/to/nix-ros-base

One obvious and common override when iterating on a package that fails to build is to simply point the src attribute at a local source checkout:

  roscpp = rosPrev.roscpp.overrideColconAttrs (_: {
    src = /path/to/ros_comm/clients/roscpp
  });

And then build just that one package:

nix build ros/20221020-1#noetic.roscpp --override-input base /path/to/nix-ros-base --impure -L

The --impure flag is required so that this sandboxed build will be able to "see" the whole filesystem, and -L makes the log spool visible without having to inspect it afterward with nix log.

nix_generator

The nix_generator directory holds the Python files and templates that are used to generate the nix files found in the main nix-ros flake repository. You can iterate on the generator and then run it locally with:

nix run /path/to/nix-ros-base#generate -o /path/to/nix-ros
nix develop /path/to/nix-ros#noetic.ros_base.ws

However, this will rebuild the module each time the source changes, so for development, it may be more ergonomic to do poetry install and then poetry run generate.

This directory also holds various tools that allow interacting with Hydra through a commandline interface or Python class. This can, for example be used to control Hydra from a different CI system like Jenkins, Actions, or GitLab CI. Use this with poetry run hydra.

colcon & flags

The colcon directory holds various colcon plugins and the actual closures that contain colcon and the correct plugins to be used for particular tasks like building documentation, building packages or for interactive use by developers.

The flags directory holds handling of compilation flags, this is done by providing various colcon mixins. These mixins are then combined into a single directory that can be used with a COLCON_HOME variable. These also provide a default set of mixins to be used whener colcon build without any arguments is invoked. This provides developers with sane defaults that are exactly identical to what is used to build the package itself. Also provided are mixins to compile with clang or ccache.

Credit

Our work would not have been possible without lopsided98's efforts on packaging ROS for Nix in the nix-ros-overlay repository, and in particular doing the work needed to ship the ROS system underlay, including packages like catkin_pkg and Gazebo.

Some key differences between the approach there and this one include:

Overall, nix-ros-overlay strives to align more closely to upstream Nix packaging conventions and expectations than this one does.

Disclaimer

We're delighted to collaborate long-term with other users of Nix and ROS, however there's no commitment to offer ongoing support for the nix-ros and nix-ros-base repositories; these were prepared specifically for a talk given at ROSCon 2022.