Skip to content

mujoco: add build-mujoco.yml for riscv64 wheels - #1728

Open
luhenry wants to merge 5 commits into
mainfrom
mujoco
Open

mujoco: add build-mujoco.yml for riscv64 wheels#1728
luhenry wants to merge 5 commits into
mainfrom
mujoco

Conversation

@luhenry

@luhenry luhenry commented Sep 10, 2026

Copy link
Copy Markdown
Member

Compiles the MuJoCo physics engine plus its pybind11 Python bindings, using upstream's own two-stage CMake flow (core library, then bindings against it) rather than cibuildwheel. Upstream publishes no riscv64 wheel.

Mirrors upstream's .github/workflows/build.yml/build_steps.sh (configure_mujoco/build_mujoco/install_mujoco, then build_python_bindings against MUJOCO_PATH).

Differs from upstream

  • Studio (Filament GUI, dear_imgui/implot) and OpenUSD dropped - Filament needs Vulkan/Metal tooling with no riscv64 story, USD is a separate heavy build.
  • Classic GLFW viewer (mujoco.viewer) kept, mirroring the already-published glfw riscv64 port's X11/Wayland dnf packages.
  • All native deps (ccd, qhull, tinyxml2, tinyobjloader, lodepng, miniz, pybind11, glfw) build from source via CMake FetchContent.

Testing

  • same as upstream (pytest --pyargs mujoco), plus an mj_step smoke test.

License: OK - Apache-2.0, wheel carries upstream's LICENSE and LICENSES_THIRD_PARTY.md.

CI running; will update with pass/skip counts once the first build completes.

luhenry added a commit that referenced this pull request Sep 10, 2026
cp312/cp313/cp314t all hung at the exact same point (render_test.py's
setUp creating a second mujoco.GLContext via GLFW) and were killed only
by the 360-minute job timeout - not a slow build, a genuine hang, as
each build had already reached the test phase within ~70 minutes.

Upstream's own CI sets MUJOCO_GL: disable for its "Test Python bindings"
step precisely to skip GLContext-dependent tests on headless runners;
mirroring that here removes the hang instead of masking it with a
bigger timeout.
auditwheel was mangling libmujoco.so.<ver> into mujoco.libs/ only for the
mujoco/plugin/*.so files (their RPATH didn't already resolve it the way
$ORIGIN does for the main extension modules in mujoco/), producing two
independent loaded copies of libmujoco.so in the same process. Since
MuJoCo's plugin registry is a global inside libmujoco.so, the plugin .so's
registered elasticity/pid/etc. into a copy the main bindings never see,
so any XML referencing a plugin failed with "plugin ... not found" -
reproduced identically across all four interpreters.

The real published PyPI wheel never grafts libmujoco.so at all (verified
by inspecting mujoco-3.12.0-cp313-cp313-manylinux_2_27_x86_64...whl): all
consumers keep the same unmangled libmujoco.so.<ver> SONAME, so the
dynamic loader reuses the one already loaded by the first extension
module imported. --exclude reproduces that here.
python/mujoco/__init__.py extends its __path__ via pkgutil.extend_path
(so mujoco-mjx can contribute to the same namespace package), and
`python -m pytest` prepends cwd to sys.path. Running pytest from
/mujoco/python made it resolve `mujoco` to the checkout's package dir
(found on sys.path ahead of site-packages) instead of the installed
wheel: the compiled extension submodules still resolved fine through
the merged __path__, so almost the whole suite passed, but
PLUGINS_DIR - derived from that shadowing __file__ - pointed at a
python/mujoco/plugin/ that doesn't exist in the checkout, so zero
bundled plugins loaded and every plugin XML test failed with
"XML Error: plugin ... not found". Confirmed via a temporary in-CI
diagnostic (since removed): mjp_pluginCount() and mjs_activatePlugin()
are both thin wrappers around the exact same GlobalTable<mjpPlugin>
singleton compiled into the one libmujoco.so, so a real per-process
registry bug was never plausible once the checkout-shadowing mechanism
was found. Upstream's own CI (build_steps.sh:test_python_bindings) runs
pytest with no working-directory override at all (i.e. from the repo
root, which has no top-level mujoco/ to shadow) - mirror that here.
luhenry added a commit that referenced this pull request Sep 11, 2026
Root-caused and fixed the 5 plugin-test failures blocking CI: pytest was
run from a cd-ed /mujoco/python, and python -m pytest's cwd-prepended
sys.path let mujoco's pkgutil.extend_path-based __init__.py resolve to
the checkout's python/mujoco/ package (no plugin/ subdirectory there)
instead of the installed wheel, so no bundled plugins loaded. Fixed by
running pytest from the repo root, matching upstream's own CI.
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