Building a ROS Package
This guide shows how to build a ROS package into a conda package with Pixi using the pixi-build-ros
backend.
To understand the build feature, start with the general Build Getting Started guide. For ROS without Pixi building (not packaging), see the ROS 2 tutorial. You may also want to read the backend documentation for pixi-build-ros.
Warning
pixi-build
is a preview feature and may change before stabilization.
Expect rough edges; please report issues so we can improve it.
Create a Pixi workspace#
Initialize a new workspace and install the ROS 2 CLI so you can scaffold packages via the ros2
cli.
pixi init ros_ws --channel https://prefix.dev/robostack-jazzy --channel https://prefix.dev/conda-forge
cd ros_ws
pixi add ros-jazzy-ros2run
This adds the ros2
cli command to your Pixi environment.
In all examples below, ensure the build preview is enabled in your workspace manifest:
Resulting workspace manifest:
[workspace]
channels = [
"https://prefix.dev/robostack-jazzy",
"https://prefix.dev/conda-forge",
]
platforms = [
"osx-arm64",
"win-64",
"linux-64",
] # Your platform here, e.g. "linux-64", "osx-arm64", "win-64"
preview = ["pixi-build"]
[dependencies]
ros-jazzy-ros2run = ">=0.32.4,<0.33"
Creating a Python ROS package#
We'll be creating a normal ROS2 package using ament_python
and then adding Pixi support to it.
Most of the logic is done by the ROS2 CLI, so you can follow normal ROS 2 package creation steps.
Initialize a ROS package#
Use the ROS CLI to generate an ament_python
package skeleton within the workspace.
pixi run ros2 pkg create --build-type ament_python --destination-directory src --node-name my_python_node my_python_ros_pkg
You should now have something like:
ros_ws/
├── pixi.toml
└── src/
└── my_python_ros_pkg/
├── package.xml
├── resource/
├── setup.cfg
├── setup.py
├── test/
└── my_python_ros_pkg/
├── __init__.py
└── my_python_node.py
Add Pixi package info to the new package#
Create a pixi.toml
inside src/my_python_ros_pkg
so Pixi can build it using the ROS backend. The backend reads most metadata from package.xml
, so you only need to specify the backend and distro.
[package.build.backend]
channels = [
"https://prefix.dev/pixi-build-backends",
"https://prefix.dev/conda-forge",
]
name = "pixi-build-ros"
version = "*"
[package.build.config]
distro = "jazzy"
Notes:
- When
package.build.config.distro
is set, the produced package name is prefixed likeros-<distro>-<name>
. - The backend automatically reads
package.xml
(name, version, license, maintainers, URLs, dependencies). Any explicitly set fields inpixi.toml
overridepackage.xml
. - Dependencies in
package.xml
are mapped to conda packages via RoboStack (for examplestd_msgs
→ros-<distro>-std-msgs
). Unknown deps pass through unchanged.
Add the package to the pixi workspace#
Tell the root workspace to depend on the package via a path dependency that matches the ROS-prefixed name:
[dependencies]
ros-jazzy-ros2run = ">=0.32.4,<0.33"
ros-jazzy-my-python-ros-pkg = { path = "src/my_python_ros_pkg" }
Testing your package#
Now install and run:
Outputs:Create a CMake ROS package#
Creating a C++ or mixed package using ament_cmake
.
Scaffold a C++ package:#
pixi run ros2 pkg create --build-type ament_cmake --destination-directory src --node-name my_cmake_node my_cmake_ros_pkg
Add the pixi package info#
Create a pixi.toml
inside src/my_cmake_ros_pkg
so Pixi can build it using the ROS backend.
The backend reads most metadata from package.xml
, so you only need to specify the backend
and distro
.
[package.build.backend]
channels = [
"https://prefix.dev/pixi-build-backends",
"https://prefix.dev/conda-forge",
]
name = "pixi-build-ros"
version = "*"
[package.build.config]
distro = "jazzy"
Add the package to the pixi workspace#
Tell the root workspace to depend on the package via a path dependency that matches the ROS-prefixed name:
[dependencies]
ros-jazzy-ros2run = ">=0.32.4,<0.33"
ros-jazzy-my-python-ros-pkg = { path = "src/my_python_ros_pkg" }
ros-jazzy-my-cmake-ros-pkg = { path = "src/my_cmake_ros_pkg" }
Testing your package#
Now install and run:
Outputs:Building a ROS conda package#
With the package(s) added to the workspace, you can now build them.
You can now upload these artifacts to a conda channel and depend on them from other Pixi workspaces.
Tips and gotchas#
- ROS distro and platform: pick the correct RoboStack channel (e.g.
robostack-humble
,robostack-jazzy
) and ensure your platform is supported. - Keep
package.xml
accurate: name, version, license, maintainers, URLs, and dependencies are read automatically; but you can override them in the pixi manifest. - Backend docs: see the pixi-build-ros documentation for configuration details like
env
,distro
andextra-input-globs
. - Colcon vs pixi build: you don’t need
colcon
when usingpixi
; the backend invokes the right build flow. But since you don't have to change your package structure, you can still usecolcon
if you want. - Not all ROS packages are available in RoboStack. If you depend on a package not in RoboStack, you can:
- Recommended: Contribute to RoboStack to add it; see the RoboStack Contributing page
- Package it yourself with Pixi in a separate workspace and upload it to your own conda channel.
- Optionally, this could use an out of tree package definition to build the package without changing its source code.
Conclusion#
You can package ROS projects as conda packages with Pixi using the pixi-build-ros
backend.
Start simple, keep package.xml
truthful, add ROS dependencies as needed, and iterate with the preview build feature.
Once built, you can upload artifacts to a conda channel and depend on them from other Pixi workspaces.