Skip to content

Full rebuild September 2026 + Sync cross-distribution Vinca package coverage - #420

Open
Tobias-Fischer wants to merge 142 commits into
mainfrom
codex/cross-distro-sync
Open

Tobias-Fischer wants to merge 142 commits into
mainfrom
codex/cross-distro-sync

Conversation

@Tobias-Fischer

@Tobias-Fischer Tobias-Fischer commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Synchronizes portable CI/build tooling and the reusable cross-distribution workflow guidance.
  • Aligns released Vinca package seeds while retaining distro-specific platform selectors and release-owned settings.
  • Refreshes the RTAB-Map patch for its current Humble release source.

Validation

  • Configuration sorting and whitespace checks pass.
  • Exact CI Vinca generation completed locally for linux-64, linux-aarch64, osx-arm64, osx-64, win-64, and emscripten-wasm32.
  • Patch application checker: 4 passed, 0 failed.

Build note

The RTAB-Map patch itself applies cleanly; the package build is currently blocked on macOS by the existing unconditional libgl-devel recipe dependency. This PR does not alter that unrelated platform policy.

Tobias-Fischer and others added 30 commits August 28, 2026 08:25
- Port pixi.toml structural changes from jazzy main: inline platform-based
  glibc (2.17), vinca as conda dep (rev 6aacb6f), pixi-build preview,
  PYTHONIOENCODING activation env; remove [system-requirements] and
  [pypi-dependencies] sections; add curl/go-yq/colordiff deps and
  conda-build-config-upstream-diff task
- Sync .github/workflows/testpr.yml: add permissions block, upgrade
  setup-pixi to v0.10.0 (pixi v0.75.0), add 3-attempt recipe-generation
  retry loop, remove Win32 long-paths registry edit, remove
  VINCA_CUSTOM_CMAKE_BUILD_DIR, fix duplicate git-maintenance step,
  move PYTHONIOENCODING to pixi.toml activation
- Sync check_patches_clean_apply.py: narrow except to AttributeError,
  add git-cache retry on fetch failure
- Update conda_build_config.yaml: graphviz→14, libxml2→2.14,
  libhwloc→2.13.0, add vtk 9.6.2 pin
- Add new macOS-compatible patches and update existing patches for
  various packages (moveit, rtabmap, autoware, rviz, etc.)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The emscripten-wasm32 platform entry was incorrectly added to pixi.toml.
It is a rattler-build cross-compilation target, not a pixi host platform;
adding it causes pixi-build to fail resolving vinca (uv unavailable for
emscripten). Remove it from platforms and keep vinca in [pypi-dependencies]
(the pypi dep works fine for all non-cross-compilation platforms).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Update libprotobuf pin to 7.35.1 in vinca.yaml and conda_build_config.yaml
- Add cv-bridge patch: fix OpenCV 5 version detection, remove dropped
  types_c.h headers, fix AccessFlag guard (#define was only skipped for
  opencv4, not opencv5)
- Add image-geometry patch: rename calib3d→calib cmake component and
  opencv2/calib3d/calib3d.hpp→opencv2/calib3d.hpp for opencv5
- Convert iceoryx packages to conda-forge meta-packages (2.95.8) in
  pkg_additional_info.yaml; drop compiled iceoryx from ROS recipes
- Skip pinocchio on macOS (coal-python 3.0.2 / libboost 1.90.* conflict)
- Add patches: imu-transformer, magic-enum, motion-capture-tracking,
  moveit-ros-control-interface, sbg-driver, sick-scan-xd, swri-serial-util,
  web-video-server
- Update slam-toolbox, libg2o, qt-gui-cpp patches

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…n checker

- Port qt_gui_cpp/python_qt_binding/rqt_gui_cpp/rqt_image_view to PyQt6 (pyside2
  has no python 3.14 build); qt_gui/rqt_py_common get analogous qt-main->qt6-main
  swaps. All patches target humble's own package versions, not borrowed from
  another distro's rosdistro_snapshot.
- Port rtabmap's corelib to OpenCV5 (backport of introlab/rtabmap#1732) and
  disable its optional Qt-based GUI/tools/examples (WITH_QT=OFF) instead of
  porting them, since rtabmap_ros only needs the core SLAM library.
- OpenCV5 API fixes: image-rotate, stereo-image-proc, nav2-waypoint-follower,
  compressed/theora image-transport, image-proc, apriltag-mit.
- CMake<3.5 sweep across lanelet2, libnabo, libpointmatcher,
  motion-capture-tracking (including vendored deps/) and mrt-cmake-modules.
- Bump hpp_fcl 3.0.2->3.0.4 and pinocchio 4.0.0->4.1.0 (libboost 1.88->1.90),
  remove the now-stale macOS pinocchio skip in vinca.yaml.
- Fix cartographer's unpinned lua/gflags build_deps conflicting with the real
  conda-forge library; remove a stale clang<19 workaround on
  nav2_mppi_controller.
- Bump vtk mutex pin to 9.7.0, mutex build_number to 21; raise glibc floor to
  2.28 and refresh compiler pins in vinca_pinning.yaml.
- Add check_dependency_compat.py: solves one fake package containing every
  non-ROS dependency plus the mutex constraints to catch pin conflicts before
  building anything; wire up as `pixi run check-deps` and document in
  AGENTS.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- mimick_vendor (linux/osx): CMake 4 removed support for the vendored
  Mimick project's cmake_minimum_required(VERSION 2.8.12); pass
  -DCMAKE_POLICY_VERSION_MINIMUM=3.5 to its ExternalProject_Add so it
  configures anyway, as CMake's own error message recommends.
- nav2-waypoint-follower.win.patch: dropped a hunk that duplicated a
  fix already applied by the base patch, which made git apply fail on
  Windows CI ("could not find context").
- autoware-trajectory.win.patch: dropped a pretty_build.hpp hunk
  written against a since-refactored version of the file that no
  longer uses range-v3/tl::expected there, so it never applied against
  the pinned release tag.
- check_patches_clean_apply.py: recipes/*/recipe.yaml only ever lists
  the patches vinca resolved for whatever host platform generated it,
  so a .win.patch/.osx.patch never shows up there when recipes were
  rendered on Linux and this script silently never exercised it. Now
  rescans patch/*.patch directly (vinca's own naming convention) and
  builds one minimal test recipe per platform whose patch set differs,
  so every platform-specific patch gets checked regardless of host.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- rosx-introspection.win.patch: the ros_parser.cpp hunks and the
  message_definition_cache.cpp #include<functional> hunk were already
  applied upstream in the pinned 2.3.0-1 release, so they no longer
  matched (one hunk hard-failed patch application on Windows CI; the
  functional include would have silently duplicated). Kept only the
  CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS knob, which is still needed and
  wasn't upstream, rewritten with correct context (the old hunk had a
  bogus line-7 header with no real context and only "worked" by luck
  via fuzzy matching).
- testpr.yml: add a concurrency group so pushing a new commit to a PR
  cancels that PR's still-running check instead of piling up parallel
  runs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
foxglove/mcap v0.8.0's types.hpp uses uint16_t/uint64_t without
including <cstdint>, relying on a transitive include from <functional>/
<memory>/etc. GCC 15's leaner libstdc++ headers no longer provide that
transitively, so the very first error ("'uint16_t' does not name a
type") cascades into dozens of bogus "no member named ..." errors
throughout writer.hpp/writer.inl for the rest of the translation unit.

Adds patch/ros-humble-mcap-vendor.patch: a PATCH_COMMAND on the
FetchContent_Declare(mcap ...) call that applies a small nested patch
(mcap_cstdint.patch, created by the same diff) adding the missing
include to the vendored header, verified directly against the pinned
v0.8.0 tarball contents.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
get_executable_path() returns the Python interpreter as a native
Windows path (backslashes). That path gets embedded verbatim into an
install(CODE "execute_process(...)") string, which CMake re-parses as
CMake syntax when it runs the generated cmake_install.cmake at install
time — any path segment that happens to look like a backslash escape
(e.g. "...\bld\..." parsing as \b) makes that second parse fail with
"Invalid character escape", aborting the whole install step for every
package that installs Python files via these macros (hit here via
ament-cmake-test, but not specific to it).

Ported the fix RoboStack/ros-rolling already carries for this same
upstream ament_cmake_python bug: normalize the interpreter path to
forward slashes before it's embedded, alongside humble's existing
patch removing the redundant CMAKE_INSTALL_PREFIX prefix in the same
functions.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Same class of bug as the mcap-vendor fix: DDSFilterCompoundCondition.hpp
and DDSFilterValue.hpp use uint8_t/uint64_t without including <cstdint>,
relying on a transitive include GCC 15's leaner libstdc++ no longer
provides. Fast-DDS is a large codebase and this is the kind of bug that
tends to recur across multiple files, so rather than chase it file by
file across CI round-trips, force the include in for the whole target
via -DCMAKE_CXX_FLAGS="-include cstdint" (unix-only: MSVC doesn't
understand -include, and this bug is specific to GCC/libstdc++).

Verified the platform selector resolves correctly by forcing vinca's
target_platform to win-64, which correctly drops the flag entirely.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ting

The previous commit's -DCMAKE_CXX_FLAGS=-include cstdint got embedded
unquoted into the generated build_catkin.sh, so bash word-split it into
two separate argv entries at the space. CMake then saw CMAKE_CXX_FLAGS
set to just "-include" (with "cstdint" misparsed as a stray positional
source-dir argument), so every compile in the package invoked plain
"-include" with no filename — which then ate the next real flag off
the command line ("-o") as its argument, breaking even CMake's own
compiler sanity check ("-o: No such file or directory") and taking out
the whole ros-humble-fastrtps build, confirmed on both aarch64 and
linux-64 CI runs.

Embedding literal double quotes in the YAML value keeps
"-include cstdint" as one shell word after substitution. Verified with
shlex.split() against the actual regenerated build script line.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
ConfigExtras.cmake requests Boost's "system" component, which no longer
ships a package config in Boost 1.90 (Boost.System has been header-only
for a while; 1.90 finally dropped the compatibility shim), so
find_package(Boost REQUIRED ... system ...) fails outright once a
package uses Boost's CONFIG mode. Confirmed on both aarch64 and
linux-64 CI, both under ros-humble-moveit-core.

The fix already existed for osx (ros-humble-moveit-core.osx.patch
already dropped "system" from the component list) but was never
ported to the other platforms, presumably because linux was still on
an older libboost when that patch was written. Moved that hunk into a
new platform-independent ros-humble-moveit-core.patch so every
platform gets it, and dropped the now-redundant copy from the osx
patch (applying it twice would fail: the "any" patch already removes
the same line first).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Same class of bug as the mcap-vendor and fastrtps fixes: RPS98's
multirotor_simulator (fetched via FetchContent) uses assert() inside
template functions in model.hpp without including <cassert>. GCC 15's
-Wtemplate-body flags this as an error ("no arguments to 'assert' that
depend on a template parameter, so a declaration ... must be
available") since it can no longer assume the include arrived
transitively. Forces the include via CMAKE_CXX_FLAGS, unix-only, using
the same quoting fixed in 7dac607 so the flag survives the generated
build script's shell word-splitting intact.

Verified the if/then selector and quoting directly against vinca's own
config loader (this package isn't in the locally-generated recipes/
tree, same gap check_patches_clean_apply.py's cross-platform rework
exists to close for patches).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The "Save build cache" and "Upload build cache as artifact" steps
gate on steps.build-recipes.outcome, but the "Build recipes" step had
no id: build-recipes set — so that context reference was always empty,
and always() && (... == 'success' || ... == 'failure' || ... ==
'cancelled') was always false. The cache was never being saved at all,
regardless of outcome; this isn't specific to jobs cut short by the
concurrency cancellation added in a915306, it just makes the effect
more visible (every superseded run now rebuilds everything from
scratch instead of resuming from a same-PR cache that was never
written in the first place).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
python_qt_binding's SIP5+ pyproject.toml-based build path names the sip
binding "lib@PROJECT_NAME@" (see pyproject.toml.in) so the importable
Python module keeps its existing "lib"-prefixed name (e.g.
libqt_gui_cpp_sip, used elsewhere in the codebase). On Unix, qmake's own
shared-library convention then prefixes "lib" a second time onto that
already-"lib"-prefixed target, producing "liblibqt_gui_cpp_sip.so" —
but the custom_command declares its OUTPUT (and everything downstream,
including qt_gui_cpp's own install() step) as the single-"lib" name.
CI failed with "file INSTALL cannot find
.../qt_gui_cpp_sip/libqt_gui_cpp_sip.so" for exactly this reason.

Rather than rename the sip binding (which would change the Python
import name other code relies on), copy the double-lib output to the
expected single-lib name right after the pip install step. Guarded to
Unix only: qmake doesn't add its own "lib" prefix on Windows, so the
name it produces there already matches what's expected.

Note: the added hunk had to match this patch file's existing `diff
-ruN` (no `index` line) format exactly — an initial attempt using
`git diff`'s `diff --git`/`index` style, appended as a second section
for the same file, made rattler-build's patch application fail on an
unrelated, earlier hunk in the same file with a confusing error.
Consolidated into one correctly-formatted, contiguous section instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Amends bc1a83b, which diagnosed the wrong problem: the double-"lib"
named artifact liblibqt_gui_cpp_sip.so never reaches the pip install
target directory at all — PyQt-builder's own packaging step already
renames it before wheeling it up. The actual mismatch is that the
installed file carries a Python ABI tag (e.g.
libqt_gui_cpp_sip.cpython-314-aarch64-linux-gnu.so), which doesn't
match this macro's plain lib${PROJECT_NAME}${SUFFIX} expectation.
Confirmed directly from the CI log's cp/qmake -install lines showing
the actual chain of renames.

Replaces the previous (ineffective, since its source file never
existed) copy step with a glob for any lib${PROJECT_NAME}* variant
PyQt-builder actually produced and copies that to the expected name —
verified against a simulated ABI-tagged file locally.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
rmw_fastrtps_cpp is not itself skipped on Windows, but its hard
dependency rosidl_typesupport_fastrtps_c/cpp was — both skip-listed in
packages_skip_by_deps (so no recipe gets generated) and stripped from
dependency lists in packages_remove_from_deps. Its CMakeLists.txt
unconditionally does find_package(rosidl_typesupport_fastrtps_c
REQUIRED), so this guaranteed rmw_fastrtps_cpp could never configure
successfully on Windows, confirmed by CI: "Could not find a package
configuration file provided by rosidl_typesupport_fastrtps_c".

We've likely never hit this until now because earlier Windows
blockers (ament-cmake-python, mimick_vendor's CMake4 issue, etc.) kept
CI from ever reaching this package. Unlike the neighboring
ros_ign_image exclusion (which cites issue #68), these two carried no
explanation, and none of jazzy/kilted/lyrical/rolling's vinca.yaml
exclude them on Windows at all — this looks like a stale, humble-only
workaround rather than a real platform limitation. Removing it so the
next Windows run can show whether it actually builds there.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
9c968b2's fix was logically correct but still failed identically on
CI (both aarch64 and, before that, on a wrong "double lib" theory in
bc1a83b). The likely culprit: the inline `python -c "import glob, os,
shutil; want = '...'; hits = [...]; ..."` command had multiple
unescaped semicolons, which CMake's COMMAND argument handling can
treat as list separators — silently truncating or mangling the script
CMake actually hands to ninja, with no error surfacing since a
truncated "import glob, os, shutil" alone is valid Python that exits 0
having copied nothing. That matches what we saw: the build proceeds
past this step (ninja doesn't verify a custom_command's declared
OUTPUT actually appeared) all the way to the later install() step,
which is where the missing file finally surfaces.

Sidesteps the whole class of CMake-string-escaping risk by moving the
fixup into its own script, cmake/fixup_sip_module_name.py (mirroring
this same file's existing cmake/sip_configure.py convention), invoked
with plain positional arguments instead of an inline -c string.
Registered in CMakeLists.txt's install(FILES ...) list alongside the
other cmake/ helpers so it's actually present in the installed
share/python_qt_binding/cmake/ directory qt_gui_cpp reads
__PYTHON_QT_BINDING_SIP_HELPER_DIR from.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Explains why all three prior attempts (bc1a83b, 9c968b2, 801822b)
at fixing qt_gui_cpp_sip's install failure had zero effect on CI despite
each being progressively more correct: CI logs show "Skipping build for
ros-humble-python-qt-binding-1.1.3-np2py314haae1a83_20" every time —
rattler-build's --skip-existing reuses whatever build already exists
under a given (name, version, build_string) in conda-forge/
robostack-staging regardless of patch content, since that identity
hash isn't derived from patch state. An old, already-published build
(predating any of this session's fixes) was being reused on every run,
so qt_gui_cpp kept linking against the same broken sip_helper.cmake no
matter what the patch file said.

Bumping build_number forces rattler-build to treat this as a distinct,
not-yet-built artifact. Should be reverted once the fixed build has
actually landed in robostack-staging, to avoid carrying a permanent
build number bump for what's really a one-time cache-bust.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Tobias-Fischer and others added 7 commits September 8, 2026 16:10
swri_console fails to compile on MSVC with "illegal token on right
side of '::'" / unmatched-parenthesis errors -- the classic
numeric_limits<T>::max()/min() vs. windows.h's min/max macro
collision. jazzy already excludes swri_console from win-64 pending an
upstream rosdistro sync (ros/rosdistro#49750); humble was missing the
equivalent exclusion. Ported as-is rather than attempting a local
NOMINMAX/parenthesization patch, matching jazzy's own resolution.

Verified via recipe regeneration: win-64 no longer generates
ros-humble-swri-console; linux-64 still generates it normally, and no
other recipe has a dangling reference to it.
check_orphaned_platform_patches.py and pixi run sort --check both
clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
swri_serial_util's serial_port.cpp needs sys/ioctl.h, termios.h,
unistd.h and poll.h -- POSIX-only serial-port APIs with no Windows
equivalent short of a real Win32 serial port rewrite. jazzy excludes
this package entirely (linux-only), but humble already carries a
working patch adapting it for macOS too (proven: osx-64/osx-arm64
both just built it successfully in the same failing run), so this
exclusion is win-only rather than copying jazzy's broader scope --
preserves the macOS support humble already has.

Verified via recipe regeneration: win-64 no longer generates
ros-humble-swri-serial-util; osx-64 and linux-64 still generate it
normally, and no other recipe has a dangling reference to it.
check_orphaned_platform_patches.py and pixi run sort --check both
clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
velodyne_driver's input.hpp needs netinet/in.h, a POSIX/BSD sockets
header with no Windows equivalent. jazzy excludes the whole velodyne
package entirely (linux-only), but it builds fine on macOS (confirmed:
osx-64 built ros-humble-velodyne-driver successfully in the same
failing run), so this exclusion is win-only rather than copying
jazzy's broader scope. velodyne_simulator stays selected independently
and still pulls in velodyne_description/velodyne_gazebo_plugins, which
don't touch raw sockets and are unaffected.

Verified via recipe regeneration: win-64 no longer generates
ros-humble-velodyne{,-driver,-pointcloud,-laserscan,-msgs}; linux-64
still generates the full set, and no other recipe has a dangling
reference to the excluded sub-packages.
check_orphaned_platform_patches.py and pixi run sort --check both
clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Same pattern as sbg_driver: GazeboRosVelodyneLaser.hpp uses M_PI,
which MSVC only defines when _USE_MATH_DEFINES is set before <cmath>
is first included. No jazzy precedent for this one -- jazzy excludes
the whole velodyne package from win-64 (linux-only scope), so this
package is never reached there; humble keeps velodyne_simulator (and
its velodyne_gazebo_plugins dependency) selected on win-64 since only
velodyne_driver itself needed excluding (see previous commit).

Verified via recipe regeneration: win-64's build script now carries
-D_USE_MATH_DEFINES. pixi run sort --check and
check_orphaned_platform_patches.py both clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The previous _USE_MATH_DEFINES fix got past the M_PI compile error,
but the real blocker is deeper: gazebo_ros_velodyne_laser links
against Gazebo Classic's Ogre-based rendering libs, and win-64's
gazebo11 build is missing OgreBites.lib (LNK1181) -- the same known
Gazebo-Classic-broken-on-Windows issue already documented and handled
for ros_gz_sim/ros_ign_gazebo/etc. in this same packages_skip_by_deps
block. Reverted the now-moot compile-flag fix and excluded the
package instead, via both packages_skip_by_deps (stop it from being
pulled in) and packages_remove_from_deps (velodyne_simulator still
listed it as a host/run dep, which would otherwise dangle).

Verified via recipe regeneration: win-64 no longer generates
ros-humble-velodyne-gazebo-plugins, and velodyne_simulator's own
recipe no longer references it; linux-64 still generates and
references it normally. check_orphaned_platform_patches.py and
pixi run sort --check both clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fails to link on MSVC: LNK2001 unresolved external symbol
rviz_default_plugins::displays::MarkerNamespace::staticMetaObject.
This is a Qt/MOC export gap in rviz_default_plugins itself (a
foundational RViz2 plugin library), not something fixable from
vision_msgs_rviz_plugins's own recipe. jazzy already excludes this
package from win-64 for the same reason; humble was missing the
equivalent exclusion. Ported into the same
not-wasm32-and-not-win block used for the other win-64-incompatible
packages.

Verified via recipe regeneration: win-64 no longer generates
ros-humble-vision-msgs-rviz-plugins, and no other recipe has a
dangling reference to it; linux-64 still generates it normally.
check_orphaned_platform_patches.py and pixi run sort --check both
clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…imit

Unrelated to any package fix -- the actual win-64 build had finished
successfully; a separate, later step ("Generate GitHub Actions
workflows to catch post-PR problems") failed because vinca-gha's
generated win.yml grew past its own hardcoded 500 KiB size limit
(712.8 KiB with the default batch_size of 5), now that this many more
packages build successfully on win-64. Bumping batch_size from the
default 5 to 10 groups more packages per stage, cutting the file
comfortably under the limit.

Verified locally: `pixi run vinca-gha --platform win-64 ... --batch_size 10`
produces a 397 KiB win.yml (vs. 694.6 KiB at the default), and the
full `pixi run generate-gha-workflows` (all platforms) also completes
cleanly with the new default.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Tobias-Fischer

Copy link
Copy Markdown
Contributor Author

@traversaro - I think this is ready for an initial review. My suggestion would be to drop emscripten for now; I have Claude working on an alternative using zenoh-pico that we could re-add in another PR.

Sister PR for Jazzy, also ready for review: RoboStack/ros-jazzy#271

Tobias-Fischer and others added 21 commits September 9, 2026 13:36
- Remove the mutex_package.build_number override (21) and the now-dead
  distro_mutex pkg_additional_info.yaml override that tried to keep it
  in sync with the top-level build_number (20). This is exactly the
  per-package build_number drift Tobias had rolling clean up; mutex
  now inherits the top-level number like jazzy already does.
- Port rolling's win-64 MAX_PATH fixes: enable the LongPathsEnabled
  registry key and pass --no-build-id to rattler-build (drops the
  rattler-build_<name>_<timestamp> suffix from the work dir), both
  needed once a package's generated intermediate paths get long
  enough to exceed the legacy 260-char limit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Opts humble into RoboStack's shared ros2-<pkg> package namespace
(jazzy and rolling already run in this mode); each selected package
now also gets a ros-humble-<pkg> compatibility shim depending on the
new canonical name, so existing user environments keep working.

Verified locally before pushing:
- linux-64 and win-64 recipe regeneration produce exactly double the
  recipe count (real ros2-<pkg> + legacy compat per package), with
  correct package/build metadata on both.
- pixi run sort --check and check_orphaned_platform_patches.py still
  pass.
- vinca-gha's win.yml hit its 500 KiB size limit at the current
  --batch_size 10 (751 KiB) now that win-64's recipe count roughly
  doubled; bumped to --batch_size 25 (matching rolling, which is at a
  similar dual-named scale) in testpr.yml, pixi.toml, and main.yml,
  confirmed win.yml comes back at ~384 KiB with margin to spare.
- Found and fixed a real bug this surfaced: check_patches_clean_apply.py's
  cross-platform patch discovery (discover_all_patches/
  platform_patch_variants) keyed patches by each recipe's OWN
  package.name, which is now ros2-<pkg> instead of the legacy
  ros-humble-<pkg> that patch/*.patch filenames are still named after.
  This silently dropped ALL patch coverage ("No recipes with patches
  found") without failing, which would have made the CI "Check
  patches" step a false-positive no-op. Fixed by deriving the lookup
  key from the patch path vinca already resolved onto the recipe's
  source section instead of the recipe's own name. Verified: full
  non-dry run now finds and cleanly builds all 185 patched recipes
  (previously 0).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
conda-forge's sip 6.16.x (6.16.1 uploaded 2026-09-08) broke ABI
targeting for PyQt5-based bindings: sip-build now fails with "ABI v12
is being targeted but the <module> module doesn't support it" for any
package building against pyqt5-sip's fixed ABI v12, e.g. qt_gui_cpp_sip.

This actually broke jazzy's CI (osx-arm64 + linux-aarch64, both hit a
fresh qt_gui_cpp_sip build the day after the bad sip landed; win-64/
linux-64/osx-64 were unaffected only because they still had a cached
build). humble carries qt_gui_cpp too (via rqt/desktop), so it's
equally exposed once its own cache for that package next evicts.
Pinning back to the last known-good 6.15 line preemptively rather than
waiting to hit the same failure here.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
package.xml's <depend>cartographer</depend> auto-resolves to the
ros2-cartographer dummy package (pkg_additional_info.yaml's
generate_dummy_package_with_run_deps) now that package_name_mode is
both, on top of the existing direct add_host on conda-forge's
cartographer (needed for a matching lua pin). vinca doesn't dedupe
the two, so both landed in host/run simultaneously -- verified via a
real recipe generation. Same fix rolling already applied.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Rolling now has a working emscripten build with more features, so
this repo no longer needs its own copy. Removes:

- vinca.yaml: the wasm32-only package block (rmw_wasm_cpp, test_wasm,
  wasm_cpp), the two "unavailable when targeting WebAssembly"
  packages_skip_by_deps/packages_remove_from_deps blocks, and unwraps
  the (now always-true) "if: not wasm32" / "if: not wasm32 and not
  win" conditions back to unconditional entries / "if: not win".
- pixi.toml: generate-recipes-emscripten, check-patches-emscripten,
  and build-emscripten tasks; the now-stale comment explaining why
  vinca is a pypi- rather than conda-dependency (emscripten-wasm32
  was the only reason cited, and it was never actually in `platforms`
  to begin with).
- testpr.yml: the emscripten-wasm32 matrix entry and its two
  conditional branches (Check patches, Build recipes).
- main.yml: the whole "Build emscripten-wasm32" step sequence.
- patch/dependencies.yaml: the `${{ 'fmt' if emscripten }}`-style
  conditionals, and the rmw_wasm_cpp-only add_host/add_run blocks on
  packages that only needed it there (rclcpp_components and the two
  minimal examples had no other purpose left, so those entries are
  gone entirely; rmw_implementation keeps its other real deps).
- robostack.yaml: the emscripten: [] platform key on google-mock.
- patch/ros-humble-test-wasm.patch: orphaned along with test_wasm.

Left the emscripten/wasm32 platform-selector entries in the three
shared check_*.py tooling scripts alone -- jazzy/rolling carry the
exact same generic completeness entries despite never building for
wasm32 either, so removing them from humble only would make the
shared tooling inconsistent across repos for no benefit.

Verified via real recipe regeneration (linux-64: 1859 recipes,
win-64: 1513, no wasm-related output remaining) and a full non-dry
check_patches_clean_apply.py run (184/184 patches applied cleanly).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Same fix as jazzy (eac4cbd3): sip only comes in transitively via
pyqt-builder here too (humble's qt_gui_cpp/python_qt_binding were
ported to PyQt6, see the ported-to-PyQt6 comments above), so the
conda_build_config.yaml `sip: 6.15` variant pin from 73abc73 never
actually applied -- variant pins only affect a package name that
shows up directly in a recipe's own requirements. Confirmed the fix
mechanism works via an isolated minimal-recipe solve (see jazzy's
commit message for detail); humble hasn't hit this in CI yet only
because its qt_gui_cpp/python_qt_binding builds are presumably still
cached, but it's exposed the same way once that cache evicts.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
packages_skip_by_deps and packages_remove_from_deps each had two
separate "if: win" blocks; packages_select_by_deps had seven separate
"if: not win" blocks and five separate "if: linux" blocks, scattered
across the file from being added incrementally across many sessions.
Merged each condition down to exactly one block per section.

While merging, converted every standalone (own-line) comment within
the merged blocks to a trailing inline comment on its item -- this is
the actual fix a reviewer asked for on jazzy's PR (Timple: "Sorting
will mess this comment up, ideally it fits behind the list item"):
vinca-sort-vinca-lists alphabetically resorts a then: list's items but
doesn't reliably keep a standalone comment attached to the item below
it, so a later resort can silently detach a comment from its intended
package.

That risk turned out not to be theoretical: several comments in the
big "not win" block were already misattached to the wrong item before
this edit (e.g. autoware_ekf_localizer's Windows error text was
sitting on "mavlink", autoware_lanelet2_utils's two Windows errors
were sitting on "mavros_extras", ffmpeg_image_transport's iconv note
was sitting on "autoware_core_localization"). Caught and corrected by
cross-referencing jazzy/rolling's equivalent (still-correct) autoware_*
and ffmpeg_image_transport exclusions, which carry identical technical
content. A handful of comments had no confident correct target left
(no named subject, no cross-distro reference) and were dropped rather
than kept attached to a wrong item.

Verified via real recipe regeneration on both linux-64 (1859 recipes)
and win-64 (1513 recipes) that the selected package set is completely
unchanged from before this refactor -- only the internal if-block
structure and comment placement changed. Also verified with
`pixi run sort --check` and check_orphaned_platform_patches.py.

Note: a few single-occurrence if-blocks elsewhere in the file (e.g.
"if: linux and not aarch64") still have standalone item comments and
would benefit from the same inline treatment; left alone here since
they aren't duplicated and this commit is scoped to the duplicate
consolidation plus the blocks that had to be touched to do it safely.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
A ~51KB cached ros2-moveit-core artifact (missing its installed cmake
config, same signature as the earlier nav2-behavior-tree case) was making
chomp_motion_planner's find_package(moveit_core) fail on win-64. Almost
certainly left behind by an earlier run's cache-save step getting caught
mid-write by a cancellation. Purge it so it rebuilds clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
An exact "sip 6.15.*" pin is fragile: it already conflicted outright with
jazzy's PyQt5-side pyqt5-sip range once, and conda-forge has since published
a pyqt5-sip build whose range newly includes the broken 6.16.1 (so an
unpinned solve there picked the regression right back up). An upper bound
avoids both failure modes -- it's compatible with whatever range pyqt6-sip
actually needs while still excluding the known-bad line. Verified via
dry-run solve: resolves to sip 6.15.3 here, same effective pick as before.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
rtabmap (win-64) failed with "cs.h: No such file or directory" building
OptimizerG2O.cpp. Root cause is upstream: g2o/solvers/csparse/CMakeLists.txt
only adds CSPARSE_INCLUDE_DIR via $<BUILD_INTERFACE:...>, never
$<INSTALL_INTERFACE:...>, so any downstream consumer linking against the
*installed* g2o package (like rtabmap) never learns where suitesparse put
cs.h. This silently worked on Linux/macOS (broader default include search)
but fails hard under MSVC's stricter -external:I isolation -- confirmed via
the actual compile command, which was missing
%PREFIX%\Library\include\suitesparse entirely despite CMake successfully
reporting "Found CSparse" earlier in the same log. Patch adds the missing
INSTALL_INTERFACE entry for both csparse_extension and solver_csparse.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Two separate root causes behind the recurring CI instability today:

1. vinca fetches ~12 additional packages' package.xml concurrently from
   raw.githubusercontent.com, completely unauthenticated. That's subject to
   GitHub's much lower anonymous rate limit, shared across every GH Actions
   runner's IP pool -- manifested as a persistent 404 for the exact same
   URL across three consecutive runs, even though the URL works fine from
   anywhere else and the retry loop's 15s backoff never cleared it. vinca
   already knows to send GITHUB_TOKEN as an Authorization header
   (distro.py's _get_auth_headers) -- it was just never wired up in the
   workflow's env.

2. This PR's build cache persists output/win-64 across every commit, so
   --skip-existing kept reusing the libg2o built before the CSparse
   INSTALL_INTERFACE fix (previous commit) landed -- rtabmap kept failing
   on the identical cs.h error because the actually-patched libg2o was
   never rebuilt. Added it to the existing stale-cache-purge step (same
   pattern already used for moveit-core/nav2-behavior-tree).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
RoboStack/vinca#156 fixes a real, reproducible bug: vinca's package.xml
fetches use raw.githubusercontent.com's short <ref> form for ros2-gbp
release tags like "release/jazzy/foo_pkg/1.2.3-1", which is ambiguous
(where does the slash-containing ref end and the path begin?) and resolves
inconsistently across CDN edges -- the same URL 404s from GitHub Actions
runners while working fine everywhere else, which is what's been causing
CI's persistent "Failed to fetch package.xml" failures. Pin to the fix
commit directly (verified it contains this line's prior HEAD as an
ancestor, so nothing else changes) rather than wait on review/merge.
Revert to the plain RoboStack/vinca.git line once that PR merges.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The previous commit pinned to a fork commit based on current
RoboStack/vinca master, which includes the newer rosdistro-cache-snapshot
feature (PR #146). Our already-generated rosdistro_snapshot.yaml predates
that machinery and isn't compatible with it, causing a new failure.

Re-pin to RoboStack/vinca@1f1dca5 (the last commit before that feature
landed) with the raw.githubusercontent.com tag-URL ambiguity fix
(RoboStack/vinca#156) cherry-picked on top, so we keep the actual fix
without pulling in the incompatible snapshot changes. Per instruction: do
not regenerate rosdistro_snapshot.yaml itself, since that would pull in new
package versions and a fresh round of patches.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
win-64 jobs have repeatedly gone completely silent for 10-20+ minutes at
points that have no legitimate reason to be slow: rattler-build's own
recipe enumeration (a pure local YAML-parse over ~2000 small files, zero
network calls) and library linking (many small .obj/.pdb file
reads/writes). One earlier occurrence ran out the full 6-hour job timeout.
Both are exactly the I/O pattern real-time Defender scanning is known to
silently stall on GH Actions Windows runners, and repeated cancel+retry
cycles kept landing on the identical spot rather than clearing anything up
(ruled out the other known cause of a deterministic win-64-only hang: a
byte-level scan of the whole libg2o source tree found no invalid UTF-8,
unlike the earlier avt_vimba_camera case). Exclude the checkout and
C:\bld build directories from scanning before any heavy I/O begins.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- dependencies.yaml: trim long-prose comments to one line each.
- testpr.yml: drop one-off package cache-purge lines (leave a commented
  template instead), shorten remaining comments.
- rosdistro_additional_recipes.yaml: remove leftover wasm/emscripten
  entries (rmw_wasm_cpp, test_wasm, wasm_cpp) from the emscripten removal.
- vinca_pinning.yaml: drop the channel_sources/channel_targets null
  override; re-render conda_build_config.yaml to match.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Removing this in the last commit broke the build: rattler-build build
commands already pass channels via -c conda-forge -c robostack-staging,
and rattler-build hard-errors if channel_sources is also set ("channel_sources
and channels cannot both be set at the same time"). Reproduced locally with
a minimal recipe and confirmed the fix (render-only succeeds again after
restoring the override). Keep the override, just with a one-line comment
this time instead of the original long-prose version.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…mera-class bug)

Pre-emptive port of the same fix landing on jazzy/rolling: urg_c (Hokuyo
laser rangefinder driver, pulled in transitively via urg_node) ships all of
its source in Shift-JIS encoding, not UTF-8. Compiling urg_sensor.h
triggers -Winvalid-utf8 on its Japanese comments; the compiler echoes the
raw invalid bytes into the diagnostic, and rattler-build's output reader
hangs instead of erroring -- confirmed live on rolling's osx-64, sitting
silently at the exact same source line for 9.5+ minutes, matching the
deterministic hang signature from the earlier avt_vimba_camera fix.

Converts all 35 affected files from Shift-JIS to UTF-8 (comment-only, no
functional change); verified this exact patch applies cleanly against
humble's own (older) urg_c release tag too.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Standardize on humble's post-review layout: a separate sort-check job,
pinned setup-pixi/pixi versions, the 3-attempt recipe-generation retry
loop, short single-line comments, and no per-repo one-off cache-purge
entries (the underlying corrupted/stale artifacts have long since been
superseded by newer cache saves).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
vinca-sort-vinca-lists only treats a whole-line comment as a block
separator; a multi-line comment block gets scrambled across items
once the surrounding lists get re-sorted. Condense every remaining
multi-line comment to one line (or an inline trailing comment where
it's attached to a single item), preserving the handful that exist
specifically to keep adjacent if/then blocks from being pooled
together by the sorter.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
ament_cmake, ros_environment, and ros_workspace were each listed
twice (once in the core-packages list, once in the general
alphabetical list). Harmless but confusing; drop the redundant copy.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Two compounding bugs in vinca-sort-vinca-lists silently defeated
sorting across large parts of this file:

1. Any standalone "  #" comment sitting between plain (unconditional)
   items starts a bogus internal accumulator that never resets. Every
   line after it -- including genuinely unconditional items -- gets
   swept into that accumulator instead of the real simple-items list.
2. Within that accumulator, only 6-space "then:"-indented lines get
   re-sorted (RE_THEN_ITEM requires exact 6-space indent); anything
   at 2-space just gets carried through verbatim and repositioned to
   the end of the file, unsorted.

Together these meant: from the first stray comment or if-block
onward, no later unconditional item was ever actually re-sorted --
verified empirically by deliberately introducing disorder into a
"protected" region and confirming `sort --check` still reported OK.

Fix: removed all standalone comments between plain items (folded the
substantive ones into inline trailing comments on the item they
describe, or the closest still-relevant one; dropped purely
decorative section headers and stale disabled-package notes that no
longer correspond to anything real); merged the two unconditional
blocks (one before the if-blocks, one trailing after) into one,
followed by all if-blocks, matching the fix already applied to
rolling.

Verified zero behavior change: evaluated selectors for linux-64,
win-64, and osx-64 against the prior committed version and confirmed
identical resulting package sets on all three before and after.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Tobias-Fischer

Copy link
Copy Markdown
Contributor Author

@traversaro - human Tobi here. I think this is ready for review. It's a much bigger PR than I had anticipated.

I'm also thinking that for the next round, I'd be keen to bootstrap most of the repositories from a shared CI template, so we can get rid of most duplicated files.

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