The goal of the ROS Central Registry is to provide a Bazel build system for Robot Operating System (ROS) applications. Our philosophy is to build everything from source, using the dependency management system provided by the Bazel modules ecosystem to ensure consistency across ROS releases. In our approach, every ROS package has a corresponding Bazel module. A lot of the work in this project is inspired by Milan Vukov's rules_ros2 project, one of several existing Bazel build systems for ROS.
Warning
This repository is a proof of concept and under active open development, and so no guarantees are made about stability. Please do not depend on this code until we have an official release!
The table below summarizes the status of the github workflows exercising various platforms:
Platform | x64 | arm64 |
---|---|---|
Ubuntu 24.04 | ||
MacOS 15 | ||
Windows 11 |
In terms of features, this is what we currently support:
- Message language bindings
-
c
-
cpp
-
py
-
rust
-
- Type supports:
-
rosidl_typesupport_introspection
-
rosidl_typesupport_fastrtps
-
rosidl_typesupport_protobuf
-
- Middleware:
-
rmw_cyclonedds_cpp
-
rmw_fastrtps_cpp
-
rmw_fastrtps_dynamic_cpp
-
rmw_zenoh_cpp
-
rmw_connextdds_cpp
-
rmw_gurumdds_cpp
-
- Core:
-
rcl
-
rcl_action
-
rcl_lifecycle
-
rclcpp
-
rclcpp_action
-
rclcpp_lifecycle
-
Our intention is to ultimately host a CI plan that responds to new ROS releases by automatically creating a set of Bazel modules and running tests. For now, however, we are working off a snapshot of the rolling release from June 2025 to determine the long term feasibility of this concept.
Right now, we only support Ubuntu 24.04. You must first install git
and and bazelisk in order to run or edit code. The project downloads a LLVM toolchain with clang, which means that you don't need any compiler or toolchains installed in your host environment. Th only thing you will need is a functioning build environment, because some packages use rules_foreign_cc
and require autoconf
to build correctly. To add this tool, run the following:
apt install build-essential automake autoconf libtool valgrind
You will need need to install homebrew first, and then add a few packages before trying to build any examples.
brew install automake autoconf libtool zstd rust bazelisk
The automake
, autoconf
, and libtool
packages are needed by rules_foreign_cc
to detect system features when generating Makefiles. The zstd
package is needed by the protocol buffer rules. The rust
package provides the cargo
binary, which is needed for a Zenoh build. The bazelisk
package provides the bazel
command, which bootstraps a bazel build tool for this project.
Currently the toolchains_llvm
project does not offer a functional compiler setup for windows environments. For more information, please see this issue.
First, checkout this repository:
git clone https://github.com/intrinsic-opensource/ros-central-registry.git
If you're goign to be developing add --recurse-submodules
but it's not necessary for just the examples.
We have included a small self-contained example workspace showing a minimal C++ publisher and subscriber exchanging a custom message. By default we use the FastRTPS middleware. Start by opening two terminals at the example
directory from within this project.
In terminal 1, start a ROS node to publish a custom message.
cd example
bazel run //:example_ros_publisher_cc
In terminal 2, start a ROS node to subscribe to the custom message.
cd example
bazel run //:example_ros_subscriber_cc
We also support several other RMW middleware implementations -- rmw_cyclonedds_cpp
, rmw_zenoh_cpp
and rmw_fastrtps_dynamic_cpp
. You must specify which one you want to use, either permanently in the .bazelrc
or as an argument to every Bazel action. For zenoh you must also run the zenohd
router, like this:
In terminal 1, start the zenohd router.
cd example
bazel run @rmw_zenoh_cpp//:rmw_zenohd
# In terminal 2
cd example
bazel run //:example_ros_publisher_cc \
--@rmw_implementation//:rmw=rmw_zenoh_cpp
# In terminal 3
cd example
bazel run //:example_ros_subscriber_cc \
--@rmw_implementation//:rmw=rmw_zenoh_cpp
We have also included protocol buffer type support, which allows you to interact with messages, services and actions through the protocol buffer C++ API. The protocol bufer type adapter automatically converts to and from the protocol buffer bindings, preventing the developer from having to write message-specific type converters, which is both laborious and prone to error.
ROS is a federated system, which means that its code is spread across multiple repositories. This makes managing a feature branch more challenging, because you have to keep several repositories in sync with each other. While we migrate to using the wstool
or vcs
tools, this repo uses submodules.
To setup your developer environment, simply do this from the root directory of this project. This will take a bit of time recursively pulling all dependent projects to the submodules
folders. The submodule
folder is where our ROS packages live, while the thirdparty
folder contains vendored dependencies.
git submodule update --init --recursive
Now, take a look at the base folder structure of this project.
+ .github/ # CI workflows for checking various platforms.
+ docs/ # Output modules from the scraping process.
+ example/ # Standalone example showing how to use our modules.
# src/ # Some examples showing how to use the developer environment.
+ tools/ # Tools for transforming repos into Bazel modules.
+ submodules/ # Bazel modules we expect to always live in the RCR ***
+ thirdparty/ # Bazel modules we expect to eventually live in the BCR ***
Right now the developer workflow is to modify the submodules directly as you test. If you look at the MODULE.bazel
file in the root of this project you will see that a local_path_override
masks the Bazel module with a local copy while you test. Once you have finished making changes and testing, you must commit your changes to the rolling-bazel
branch of each repo you modified:
As an example, lets assume you made a change to rclcpp
. To push the change upstream, you will need write permission to the repo. Right now we are in the process of setting up a better way of handling this.
cd submodules/rclcpp
git pull
git checkout rolling-bazel
git commit -m "Added new tests"
git push
Note that you will also need to push the updated submodule commit hash on this repo, so that the developer workspace now points to a rclcpp
repo commit containing your change. Before we do this, however, we want to first make sure that we have regenerated our bazel modules files:
bazel run //tools:regenerate_modules -- $PWD
This tool iterates over all submodules in submodules
and thirdparty
and calculates a diff between the upstream versioned release and the rolling-bazel
branch, and then transforms this into Bazel module in the docs
folder. If you run git diff
you should see changes in docs
to the rclcpp
package.
Once you are happy with the change to the submodule commit and docs
folder, you can commit and push your code to a new branch and setup a PR.
git checkout -b feature/rclcpp-test-fixes
git add .
git commit -m "Add some rclcpp fixes"
git push
When you open a pull request containing your changes, you will see some CI plans run. These let you know whether the changes you have made are functional across a variety of different platforms.
Right now we will periodically update modules but keep the same version number. Bazel aggressively caches based on the version numbers. If you find that you are getting a download hash mismatch for modules, make sure that you remove the MODULE.bazel.lock
file in the root workspace. If you still have issues, clean the workspace by running bazel clean
followed by bazel shutdown
. If you still have issues, you can try running rm -rf $(bazel info repository_cache)
but note that this will clear all repository cache, and a build will need to re-download the LLVM toolchain.
If you are running in docker, there is a known issue with valgrind. Before running any tests you must set your ulimit down from the default of 1073741804 to something more reasonable, like 4096. Do this with ulimit -n 4096
, otherwise valgrind will error on initialization.
There is no straightforward way of running a full test suite across all package imports. Bazel doesn't support to support a wildcard expansion for test targets that span multiple modules. For this reason we have a Distribution File and supporting rule in our .bazelrc
file that enables you to run all tests across all repos in the following way:
bazel test --config=distribution