Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![Conan create ros-kilted](https://github.com/conan-io/ros-conan/actions/workflows/conan-create-ros-kilted.yml/badge.svg)](https://github.com/conan-io/ros-conan/actions/workflows/conan-create-ros-kilted.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)

Conan recipes for building [ROS 2](https://docs.ros.org/) from source. Pull ROS 2 and all its dependencies with a single `conan install`, no `rosdep`, `apt`, `brew` or `choco` required. Works with plain CMake projects and `colcon` workspaces, on Windows, macOS and Linux.
Conan recipes for building [ROS 2](https://docs.ros.org/) from source. Pull ROS 2 and all its dependencies with a single `conan install`, no `rosdep`, `apt`, `brew` or `choco` required. Works with plain CMake projects, `colcon` workspaces, and [Conan workspaces](https://docs.conan.io/2/tutorial/developing_packages/workspaces.html), on Windows, macOS and Linux.

---

Expand Down Expand Up @@ -89,6 +89,7 @@ pinned to. The Conan version `YYYY.MM.DD` maps 1:1 to the rosdistro tag
| ------------------------------------------------------------- | --------------------------------------------------------------------------- |
| [`consumer_cmake`](examples/consumer_cmake/readme.md) | Pure-CMake consumer using `rclcpp` via `CMakeDeps`, no `colcon` needed. |
| [`consumer_colcon`](examples/consumer_colcon/readme.md) | `colcon` workspace consuming the ROS runtime from Conan via `ROSEnv`. |
| [`conan_workspace`](examples/conan_workspace/readme.md) | Same `src/` layout as `consumer_colcon`, orchestrated with a Conan workspace (CMake only). |
| [`pose_estimation`](examples/pose_estimation/readme.md) | `ros-kilted` + `opencv` + `tensorflow-lite` publishing a skeleton overlay. |
| [`consumer_desktop`](examples/consumer_desktop/readme.md) | Installs the `desktop` variant and runs its GUI tooling (`rviz2`, `rqt`). |

Expand Down
18 changes: 18 additions & 0 deletions examples/conan_workspace/ci_test_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import platform

from test.examples_tools import VARIANT_ARGS, run

run(
f"conan workspace build --profile ../../profiles/ros {VARIANT_ARGS} --build=missing"
)

if platform.system() == "Windows":
run(
r"call .\src\consumer_node\build\generators\conanrun.bat && "
r".\src\consumer_node\build\Release\consumer_node.exe"
)
else:
run(
". ./src/consumer_node/build/Release/generators/conanrun.sh && "
"./src/consumer_node/build/Release/consumer_node"
)
6 changes: 6 additions & 0 deletions examples/conan_workspace/conanws.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
name: conan_workspace
packages:
- path: src/dummy_lib
ref: dummy_lib/0.1
- path: src/consumer_node
ref: consumer_node/0.1
105 changes: 105 additions & 0 deletions examples/conan_workspace/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# conan_workspace

Same layout as [`consumer_colcon`](../consumer_colcon/readme.md) — two packages under
`src/` — but orchestrated with a [Conan workspace](https://docs.conan.io/2/tutorial/developing_packages/workspaces.html)
instead of `colcon`. There is no `package.xml`, no `ament_cmake`, and no `colcon`:
each package is a plain CMake project with its own `conanfile.py`. Workspace packages
are resolved as [editables](https://docs.conan.io/2/tutorial/developing_packages/editable_packages.html)
and built in dependency order.

- `dummy_lib` — a static library with no ROS dependencies, used to demonstrate
cross-package linking inside the workspace.
- `consumer_node` — depends on `dummy_lib` and `ros-kilted` (`rclcpp`), prints a
message and starts a short-lived node.

[← back to main README](../../README.md)

## Layout

```text
conan_workspace/
├── conanws.yml # workspace root + package inventory
└── src/
├── dummy_lib/
│ ├── conanfile.py # replaces package.xml
│ ├── CMakeLists.txt
│ ├── include/
│ └── src/
└── consumer_node/
├── conanfile.py
├── CMakeLists.txt
└── src/
```

Conan walks up from the current directory until it finds `conanws.yml` and/or
`conanws.py`; that folder is the workspace root. Paths in `conanws.yml` are
relative to it.

This example only needs `conanws.yml`. A `conanws.py` is optional Python
customization (`root_conanfile()` for a monolithic super-build, custom
`add`/`clean`/`build_order`, or `get_ref()` when name/version come from
`python_requires`). Orchestrated `conan workspace build` does not use any of
that.

This example uses the **orchestrated** workspace flow (`conan workspace build`),
which is the closest analogue to `colcon build`: each package is configured and
built on its own, in topological order, with workspace members consumed as
editables.

Conan workspaces are experimental and subject to breaking changes — see the
[Conan stability notes](https://docs.conan.io/2/introduction.html#stability).

## How it is wired

| Piece | Role |
| ----- | ---- |
| [`conanws.yml`](conanws.yml) | Lists `src/dummy_lib` and `src/consumer_node` as workspace packages. |
| [`src/dummy_lib/conanfile.py`](src/dummy_lib/conanfile.py) | CMake library recipe: `CMakeToolchain` + `CMakeDeps`, `cmake_layout()`. |
| [`src/consumer_node/conanfile.py`](src/consumer_node/conanfile.py) | Requires `dummy_lib/0.1` (editable, from this workspace) and `ros-kilted/2026.06.17`. |
| CMake | Plain `find_package(dummy_lib)` / `find_package(rclcpp)` — configs come from Conan, not from sourcing a ROS `setup` script. |

`conan workspace build` is `conan build` for every workspace package, in the
right order. External dependencies (`ros-kilted` and its graph) are installed
from the cache/remotes; `dummy_lib` is never looked up as a binary because it
is in the workspace.

## Prerequisites

- A C++17 compiler.
- CMake ≥ 3.22 (the [profile](../../profiles/ros) tool-requires `cmake/3.29.3`).
- Conan 2.31+ (For `conan workspace build`, as the feature has received recent improvements).
- A Conan remote that exposes `ros-kilted` — see the
[main README](../../README.md#quick-start).

## Build & run

From this directory:

```bash
conan workspace build --profile ../../profiles/ros --build=missing
```

Then activate the consumer's Conan run environment and execute the node:

**Windows (cmd):**

```bat
call src\consumer_node\build\generators\conanrun.bat
src\consumer_node\build\Release\consumer_node.exe
Comment thread
danimtb marked this conversation as resolved.
```

**macOS / Linux (bash/zsh):**

```bash
. ./src/consumer_node/build/Release/generators/conanrun.sh
./src/consumer_node/build/Release/consumer_node
```

Expected output (truncated):

```text
[dummy_lib] hello from library
[INFO] [...] [workspace_consumer_node]: Conan workspace consumer_node: rclcpp linked and node started.
```

The exact CI invocation lives in [`ci_test_example.py`](ci_test_example.py).
8 changes: 8 additions & 0 deletions examples/conan_workspace/src/consumer_node/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.22)
project(consumer_node CXX)

find_package(dummy_lib REQUIRED)
find_package(rclcpp REQUIRED)

add_executable(consumer_node src/main.cpp)
target_link_libraries(consumer_node PRIVATE dummy_lib::dummy_lib rclcpp::rclcpp)
26 changes: 26 additions & 0 deletions examples/conan_workspace/src/consumer_node/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from conan import ConanFile
from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout


class ConsumerNodeConan(ConanFile):
name = "consumer_node"
version = "0.1"
package_type = "application"
settings = "os", "compiler", "build_type", "arch"
exports_sources = "CMakeLists.txt", "src/*"

def layout(self):
cmake_layout(self)

def requirements(self):
self.requires("dummy_lib/0.1")
self.requires("ros-kilted/2026.06.17")

def generate(self):
CMakeDeps(self).generate()
CMakeToolchain(self).generate()

def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
15 changes: 15 additions & 0 deletions examples/conan_workspace/src/consumer_node/src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#include <memory>

#include <dummy_lib/print.hpp>
#include <rclcpp/rclcpp.hpp>

int main(int argc, char ** argv)
{
dummy_lib::print_hello();

rclcpp::init(argc, argv);
auto node = std::make_shared<rclcpp::Node>("workspace_consumer_node");
RCLCPP_INFO(node->get_logger(), "Conan workspace consumer_node: rclcpp linked and node started.");
rclcpp::shutdown();
return 0;
}
13 changes: 13 additions & 0 deletions examples/conan_workspace/src/dummy_lib/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
cmake_minimum_required(VERSION 3.22)
project(dummy_lib CXX)

add_library(dummy_lib STATIC src/print.cpp)
target_include_directories(dummy_lib PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:include>")

install(TARGETS dummy_lib
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)
install(DIRECTORY include/ DESTINATION include)
29 changes: 29 additions & 0 deletions examples/conan_workspace/src/dummy_lib/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from conan import ConanFile
from conan.tools.cmake import CMake, CMakeDeps, CMakeToolchain, cmake_layout


class DummyLibConan(ConanFile):
name = "dummy_lib"
version = "0.1"
package_type = "static-library"
settings = "os", "compiler", "build_type", "arch"
exports_sources = "CMakeLists.txt", "src/*", "include/*"

def layout(self):
cmake_layout(self)

def generate(self):
CMakeDeps(self).generate()
CMakeToolchain(self).generate()

def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()

def package(self):
cmake = CMake(self)
cmake.install()

def package_info(self):
self.cpp_info.libs = ["dummy_lib"]
12 changes: 12 additions & 0 deletions examples/conan_workspace/src/dummy_lib/include/dummy_lib/print.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef DUMMY_LIB__PRINT_HPP_
#define DUMMY_LIB__PRINT_HPP_

namespace dummy_lib
{

/** Writes a fixed dummy message to stdout (example library API). */
void print_hello();

} // namespace dummy_lib

#endif // DUMMY_LIB__PRINT_HPP_
13 changes: 13 additions & 0 deletions examples/conan_workspace/src/dummy_lib/src/print.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include <cstdio>

#include "dummy_lib/print.hpp"

namespace dummy_lib
{

void print_hello()
{
std::puts("[dummy_lib] hello from library");
}

} // namespace dummy_lib
Loading