Skip to content

Fix Rolling build: fmt::runtime, Qt5/Qt6 dual-support, rviz Display::update, char8_t - #754

Open
nbbrooks wants to merge 4 commits into
moveit:ros2from
PickNikRobotics:nbbrooks/rolling-ecosystem-compat
Open

Fix Rolling build: fmt::runtime, Qt5/Qt6 dual-support, rviz Display::update, char8_t#754
nbbrooks wants to merge 4 commits into
moveit:ros2from
PickNikRobotics:nbbrooks/rolling-ecosystem-compat

Conversation

@nbbrooks

@nbbrooks nbbrooks commented Aug 3, 2026

Copy link
Copy Markdown

Why

Four Rolling/Resolute incompatibilities, all found by an end-to-end source build in an ubuntu:resolute container.

# Problem
1 fmt v10+ made format strings consteval. Runtime-composed format strings in core/src/cost_terms.cpp and core/src/stage.cpp no longer compile.
2 rviz switched to Qt6. find_package(Qt5 REQUIRED) collides with a Qt6 rviz.
3 rviz's Display::update signature changed from (float, float) to (std::chrono::nanoseconds, std::chrono::nanoseconds) at RCLCPP_VERSION_GTE(30, 0, 0). TaskDisplay's override no longer matches, so the class stops being a concrete Display — the plugin fails to load and won't build with -Werror.
4 C++20 char8_t. u8"…" literals need reinterpret_cast<const char*> to feed Qt tr().

How

  • fmt: wrap runtime-composed format strings in fmt::runtime().
  • Qt: select Qt6 when building against rviz >= 15.1.14, else Qt5, with qt5_wrap_ui/qt6_wrap_ui switched to match. Gated on rviz_common_VERSION rather than Qt6 availability — see below.
  • Display::update: dual-signature guarded on RCLCPP_VERSION_GTE(30, 0, 0); the Rolling branch takes nanoseconds, converts, and calls the existing implementation. humble/jazzy/kilted keep the old override.
  • char8_t: reinterpret_cast<const char*> at each affected tr() call.

Why the Qt gate is on rviz's version, not Qt6 availability

find_package(Qt6 QUIET) succeeds whenever Qt6 is merely installed, which says nothing about which Qt rviz was built against — and this package links rviz_common/rviz_default_plugins, so its Qt must match. Ubuntu 24.04 ships both, so on jazzy or kilted with qt6-base-dev present the probe doesn't quietly mis-select — it aborts the configure, because rviz_common has already defined the versionless Qt::Core target:

CMake Error at Qt6CoreVersionlessTargets.cmake:42:
  Some (but not all) targets in this export set were already defined.
  Targets Defined: Qt::Core
  Targets not yet defined: Qt::CorePrivate

QUIET doesn't suppress that — it's a FATAL_ERROR inside Qt6's own config, not a not-found condition, so the Qt5 fallback is never reached.

The threshold is 15.1.14, not 15.1: ros2/rviz#1635 merged 2025-12-08 but first shipped in the 15.1.14 tag on 2025-12-17 — 15.1.0 through 15.1.13 are still Qt5.

distro rviz Qt
humble 11.2 Qt5
jazzy 14.1 Qt5
kilted 15.0 Qt5
lyrical 15.2 Qt6
rolling 16.0 Qt6

package.xml also needed fixing

visualization/package.xml requested qtbase5-dev unconditionally, which resolves to Qt5 on every platform — so rosdep would install Qt5 while CMake selects Qt6, which is precisely how the collision above arises. Switched to the versionless qt-base-dev, which rosdep maps per-platform (jammy/nobleqtbase5-dev, *qt6-base-dev) — the same move ros2/rviz#1635 made in rviz_common's own package.xml.

Both fixes mirror PickNikRobotics/rviz_visual_tools#300, merged and green on all five distros.

Verification

Verified by an end-to-end source build of moveit_task_constructor (core + capabilities + visualization + demo) in ubuntu:resolute against a Rolling workspace. Every guarded branch preserves existing behavior on humble/jazzy/kilted.

Note the two Resolute CI jobs will fail on ros-{lyrical,rolling}-moveit-core not existing — moveit_core is not yet published for Resolute, which blocks every downstream package there. Unrelated to this change; those jobs are non-blocking.

🤖 Generated with Claude Code

nbbrooks and others added 4 commits July 13, 2026 07:30
On ROS Rolling (fmt >= 10) format strings must be consteval. cost_terms.cpp
builds format strings by concatenating PREFIX at runtime; stage.cpp uses a
generic auto... args lambda that fmt::format then can't verify at compile
time. Wrap both call sites with fmt::runtime() to tell fmt these are real
runtime format strings.

No behavior change on humble/jazzy/kilted where fmt was more permissive.
Try Qt6 first, fall back to Qt5. Ubuntu Resolute removes Qt5 from the
default apt indexes; humble/jazzy/kilted still have Qt5. Additive-only.
qt_wrap_ui macro gets a conditional qt5/qt6 branch.
- task_list_model.cpp, remote_task_model.cpp: reinterpret_cast<const char*>
  around u8"..." literals so they can feed Qt tr() under C++20's char8_t
  distinction.
- task_display.{h,cpp}: dual-signature update() override guarded on
  RCLCPP_VERSION_GTE(30, 0, 0). Rolling switched Display::update from
  (float, float) to (std::chrono::nanoseconds, std::chrono::nanoseconds);
  Rolling branch converts to float seconds and calls the existing body.
… rosdep key

Two corrections to the Qt5/Qt6 dual-support commit.

1. Gate on rviz_common_VERSION, not Qt6 availability

find_package(Qt6 QUIET) succeeds whenever Qt6 is merely installed, which
says nothing about which Qt rviz was built against -- and this package links
rviz_common/rviz_default_plugins, so its Qt must match rviz's. Ubuntu 24.04
ships both, so on jazzy or kilted with qt6-base-dev present the probe does
not silently mis-select; it aborts the configure, because rviz_common has
already defined the versionless Qt::Core target:

  CMake Error at Qt6CoreVersionlessTargets.cmake:42:
    Some (but not all) targets in this export set were already defined.

QUIET does not suppress that -- it is a FATAL_ERROR inside Qt6's own config,
not a not-found condition, so the Qt5 fallback is never reached.

rviz switched to Qt6 in 15.1.14: ros2/rviz#1635 (merged 2025-12-08) first
shipped in that tag on 2025-12-17. Note 15.1.0 through 15.1.13 are still
Qt5, so the threshold is 15.1.14 rather than 15.1.

  humble  rviz 11.2  -> Qt5     lyrical rviz 15.2 -> Qt6
  jazzy   rviz 14.1  -> Qt5     rolling rviz 16.0 -> Qt6
  kilted  rviz 15.0  -> Qt5

rviz_common is already find_package'd above the Qt block, so the version is
in scope. Also carries the QT_DIR hint for transitive deps whose
find_package(QT NAMES Qt6 Qt5 ...) can mis-resolve under CMake's ascending
path order.

2. package.xml still requested Qt5 unconditionally

  <build_depend>qtbase5-dev</build_depend>

That resolves to Qt5 on every platform, so rosdep would install Qt5 while
CMake selects Qt6 -- which is exactly how the collision above arises. The
versionless key maps per-platform, the same move ros2/rviz#1635 made in
rviz_common's own package.xml:

  key            jammy         noble         * (resolute)
  qt-base-dev    qtbase5-dev   qtbase5-dev   qt6-base-dev

That agrees with the CMake gate on every distro this branch ships to.

Same pair of fixes as PickNikRobotics/rviz_visual_tools#300.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant