Skip to content

Add emscripten-wasm32 as an opt-in target platform - #425

Open
Tobias-Fischer wants to merge 1 commit into
RoboStack:codex/cross-distro-syncfrom
Tobias-Fischer:feature/emscripten-wasm32-support
Open

Add emscripten-wasm32 as an opt-in target platform#425
Tobias-Fischer wants to merge 1 commit into
RoboStack:codex/cross-distro-syncfrom
Tobias-Fischer:feature/emscripten-wasm32-support

Conversation

@Tobias-Fischer

Copy link
Copy Markdown
Contributor

Summary

Adds emscripten-wasm32 support to the vinca-driven recipe pipeline, enabling ROS 2 Humble to build for WebAssembly (via the Emscripten toolchain) alongside the existing native platforms. All changes are gated by wasm32/emscripten selectors in vinca.yaml/robostack.yaml/conda_build_config.yaml — no effect on existing platform builds.

Validated end-to-end: a full ~104-package build targeting emscripten-wasm32, running a real rclcpp talker continuously in the browser via a COOP/COEP-isolated page with genuine SharedArrayBuffer-backed threads (real pthreads, not a JS shim).

Depends on RoboStack/vinca#154 (pthreads support for emscripten-wasm32) — pixi.toml currently pins the Tobias-Fischer/vinca fork branch; re-point to the merged upstream commit once that PR lands.

Key pieces

  • vinca.yaml: packages_select_by_deps/skip_by_deps/remove_from_deps selectors adding a wasm32-appropriate package subset (dropping packages with no viable wasm32 host deps: fastrtps/cyclonedds RMWs, google-benchmark, gtest/gmock-heavy test infra, etc.)
  • robostack.yaml: per-platform rosdep-key overrides for eigen/yaml/yaml-cpp/spdlog, since emscripten-forge doesn't publish conda packages for several of these and the vendored from-source fallback needs to be used instead
  • patch/dependencies.yaml: genuinely-missing host deps added per package.xml audits (e.g. rmw_wasm_cpp needing libffi), gated to emscripten where the dep is actually missing
  • patch/ros-humble-{yaml-cpp-vendor,spdlog-vendor}.emscripten.patch: fix CMAKE_PROJECT_INCLUDE propagation into each vendor's own nested ExternalProject_Add build (without it, the nested build silently loses vinca's global side-module/pthread flags)
  • patch/ros-humble-rosidl-generator-py.patch: numpy 2.x header path fix (numpy/core/includenumpy/_core/include)
  • patch/ros-humble-{wasm-cpp,rmw-wasm-cpp,test-wasm}.patch: patches against github.com/ros2wasm/rmw_wasm's wasm_cpp/rmw_wasm_cpp/test_wasm packages — fix a genuine embind duplicate-registration bug, drop dead SQLite3/ZLIB/BZip2 deps that broke once pthreads were enabled (emscripten-forge's prebuilt static libs for these aren't pthread-compatible, and nothing in rmw_wasm_cpp's own sources ever calls into them), and remove stale hardcoded USE_PTHREADS=0 overrides now that vinca sets it globally
  • patch/ros-humble-rcutils.emscripten.patch: the actual root-cause fix for the demo running only once and then hanging forever — rcutils_steady_time_now() (which rclcpp::WallTimer actually uses) called clock_gettime(CLOCK_MONOTONIC_RAW, ...), which is silently broken in this emscripten/pthread build (the nanosecond field gets misread as the seconds field), even though plain CLOCK_MONOTONIC on the same build works correctly. Switched both rcutils_system_time_now and rcutils_steady_time_now to CLOCK_MONOTONIC under emscripten.
  • vinca_pinning.yaml/conda_build_config.yaml: emscripten-forge/recipes-specific version overrides (emscripten SDK 4.0.9, python 3.13, libffi 3.4.6, graphviz 15.1.0) layered on top of the existing conda-forge-pinning-derived config, for the packages where emscripten-forge's published set doesn't match conda-forge-pinning's regular versions
  • .github/workflows/testpr.yml: point the emscripten-wasm32 CI job at repo.prefix.dev/emscripten-forge-4x (repo.mamba.pm/emscripten-forge is stale/legacy, ~1/3 the package count as of 2026-09-07)

Testing

Full 104-recipe build succeeded; extracted the resulting test_wasm package into a micromamba-created emscripten-wasm32 environment, served it locally with COOP/COEP headers, and confirmed the talker demo runs continuously (55+ consecutive correctly-timed publishes) and the listener demo initializes and spins cleanly on the subscriber code path.

🤖 Generated with Claude Code

Adds emscripten-wasm32 support to the vinca-driven recipe pipeline,
enabling ROS 2 Humble to build for WebAssembly (via the Emscripten
toolchain) alongside the existing native platforms. All changes are
gated by wasm32/emscripten selectors in vinca.yaml/robostack.yaml/
conda_build_config.yaml -- no effect on existing platform builds.

Validated end-to-end: a full ~104-package build targeting
emscripten-wasm32 (using the pthreads-enabled vinca fork from the
companion PR at RoboStack/vinca), running a real rclcpp talker
continuously in the browser via a COOP/COEP-isolated page with genuine
SharedArrayBuffer-backed threads.

Key pieces:
- vinca.yaml: packages_select_by_deps/skip_by_deps/remove_from_deps
  selectors adding a wasm32-appropriate package subset (dropping
  packages with no viable wasm32 host deps: fastrtps/cyclonedds RMWs,
  google-benchmark, gtest/gmock-heavy test infra, etc.)
- robostack.yaml: per-platform rosdep-key overrides for eigen/yaml/
  yaml-cpp/spdlog, since emscripten-forge doesn't publish conda
  packages for several of these and the vendored from-source fallback
  needs to be used instead
- patch/dependencies.yaml: genuinely-missing host deps added per
  package.xml audits (e.g. rmw_wasm_cpp needing libffi), gated to
  emscripten where the dep is actually missing
- patch/ros-humble-{yaml-cpp-vendor,spdlog-vendor}.emscripten.patch:
  fix CMAKE_PROJECT_INCLUDE propagation into each vendor's own nested
  ExternalProject_Add build (without it, the nested build silently
  loses vinca's global side-module/pthread flags)
- patch/ros-humble-rosidl-generator-py.patch: numpy 2.x header path
  fix (numpy/core/include -> numpy/_core/include)
- patch/ros-humble-{wasm-cpp,rmw-wasm-cpp,test-wasm}.patch: patches
  against github.com/ros2wasm/rmw_wasm's wasm_cpp/rmw_wasm_cpp/
  test_wasm packages -- fix a genuine embind duplicate-registration
  bug, drop dead SQLite3/ZLIB/BZip2 deps that broke once pthreads
  were enabled (emscripten-forge's prebuilt static libs for these
  aren't pthread-compatible, and nothing in rmw_wasm_cpp's own
  sources ever calls into them), and remove the stale hardcoded
  USE_PTHREADS=0 overrides now that vinca sets it globally
- patch/ros-humble-rcutils.emscripten.patch: the actual root-cause
  fix for the demo running only once and then hanging forever --
  rcutils_steady_time_now() (which rclcpp::WallTimer actually uses)
  called clock_gettime(CLOCK_MONOTONIC_RAW, ...), which is silently
  broken in this emscripten/pthread build (the nanosecond field gets
  misread as the seconds field), even though plain CLOCK_MONOTONIC on
  the same build works correctly. Switched both rcutils_system_time_now
  and rcutils_steady_time_now to CLOCK_MONOTONIC under emscripten.
- conda_build_config.yaml/vinca_pinning.yaml: emscripten-forge/
  recipes-specific version pins (emscripten SDK 4.0.9, python 3.13,
  libffi 3.4.6, graphviz 15.1.0) where their published package set
  doesn't match conda-forge-pinning's regular versions
- .github/workflows/testpr.yml: point the emscripten-wasm32 CI job at
  repo.prefix.dev/emscripten-forge-4x (repo.mamba.pm/emscripten-forge
  is stale/legacy, ~1/3 the package count as of 2026-09-07)

Depends on RoboStack/vinca#154 (pthreads support) -- pixi.toml
currently pins the Tobias-Fischer/vinca fork branch; re-point to the
merged upstream commit once that PR lands.

Co-Authored-By: Claude Sonnet 5 <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