Skip to content

mini-racer: Add version 0.14.1 - #1875

Open
luhenry wants to merge 12 commits into
mainfrom
mini-racer
Open

luhenry wants to merge 12 commits into
mainfrom
mini-racer

Conversation

@luhenry

@luhenry luhenry commented Sep 13, 2026

Copy link
Copy Markdown
Member

Important

Needs a maintainer decision on runner cost before merge — do not merge silently. build_dll carries timeout-minutes: 2880 (48h). That is a ceiling, not an allocation: the measured build is ~27h wall on a 4-core riscv64 runner (23h30m of ninja reached 1970/2176 targets, still progressing normally when the old 1440 ceiling killed it). The previous 24h ceiling was below the build's real cost, so it destroyed a full day of runner time and would have had it repeated — raising it lowers total runner consumption rather than raising it. The build is already parallel (measured: 21% of ninja completions land sub-second apart) and -g0/is_debug=false; the only ways to go materially faster are dropping WebAssembly, Intl/ICU or the optimizing tiers from the engine, which would make this wheel functionally different from mini-racer on every other platform. Same reasoning and same value as build-nodejs-wheel-binaries.yml (the other V8-from-source port: "a prior run needed ~23h16m and the next one was still compiling V8 objects when killed at the 24h mark") and build-vtk.yml. If ~27h per release is judged too expensive for the shared pool, this port should be parked rather than trimmed.

Builds V8 (branch-heads/14.4) from source and embeds it as a minimal Python JS engine. Upstream publishes no riscv64 wheel.

Mirrors upstream's build.yml build-dll/build-wheel jobs, narrowed to Linux glibc riscv64.

Differs from upstream

  • Builds with V8's own riscv64-linux-gnu- gcc_toolchain - Chromium's prebuilt clang has no riscv64 host build.
  • Tests the single wheel against every interpreter the image ships - uv fetches no riscv64 pythons.

Matrix: one riscv64 build, not one per interpreter; the wheel is py3-none-<platform>, so one V8 build serves all four.

Testing

  • same as upstream (pytest tests), run once per bundled interpreter (cp312/cp313/cp314/cp314t).

License: OK

Patches (all Upstream-Status: To upstream, all riscv64-only, all against builder/v8_build.py)

  • 0001-0003 - recognise riscv64 as a native v8_target_cpu, give it its own manylinux tag, select the gcc_toolchain; without them the build fetches an unusable x86_64 clang and mislabels the wheel as x86_64.
  • 0004-0006 - serialize gclient sync and patch out the reclient/siso CIPD packages, which are not published for linux-riscv64.
  • 0007-0008 - drop the cross sysroot, V8's custom libc++ and Rust/Temporal; none of them works on a native riscv64 GCC host.
  • 0009, 0011 - the two V8 sources GCC cannot compile (an explicit specialization inside a class body, and third_party/highway falling back to HWY_SCALAR, which has no FixedTag<T, 16> for the JSON stringifier), plus treat_warnings_as_errors=false for the GCC-only warnings V8 gates on clang.

Pending CI.

Builds v8 (branch-heads/14.4) from source for riscv64, the shape
upstream already uses for x64/arm64: a build-dll job runs v8_build.py
to produce libmini_racer.so, then build-wheel packages it into a
single py3-none-manylinux_riscv64 wheel (the .so is not linked against
libpython, so one wheel serves every interpreter). v8's own riscv64
codegen backend (src/codegen/riscv) is mature and actively developed;
the gap is entirely in tooling: PyMiniRacer's build script does not
recognize riscv64 as a host arch, its wheel tagging mislabels
non-aarch64 riscv builds as x86_64, and Chromium's prebuilt clang is
only published for amd64/arm64/mac hosts, so the build must use v8's
existing riscv64-linux-gnu- gcc_toolchain instead. All three are
patched in patches/mini-racer/0.14.1/.
luhenry added a commit that referenced this pull request Sep 13, 2026
CI hit gclient sync's 'gsutil' bootstrap lockfile.LockError:
[Errno 11] Resource temporarily unavailable, from concurrent sync
workers racing to fetch the shared gsutil binary. depot_tools already
serializes sync (--jobs=1) for 32-bit arm boards for the same reason;
do the same for riscv64.

https://github.com/riseproject-dev/python-wheels/actions/runs/34731759983/job/103655726279
CI's gclient sync got past the gsutil lockfile race and then failed
resolving two CIPD packages neither published for linux-riscv64:
infra/rbe/client (remote build execution) and build/siso (the siso
build tool). Both are optional accelerators the plain gn+ninja build
never needs; skip them via custom_deps.

https://github.com/riseproject-dev/python-wheels/actions/runs/34732817721/job/103658674867
CI proved the previous approach wrong: gclient still tried (and
failed) to resolve infra/rbe/client/linux-riscv64 and
build/siso/linux-riscv64 with the custom_deps override in place.
CipdDependency.run() never consults the Dependency.url a custom_deps
override changes, only should_process, which is derived straight from
the DEPS-declared condition -- so nulling out a custom_deps entry can
never skip a CIPD package. A global host_cpu var override doesn't work
either: gn and ninja share the exact same guard clause and do have
riscv64 packages, so spoofing host_cpu would stop them being fetched
too. Patch the two conditions in the checked-out v8/DEPS directly
instead, after letting the first sync attempt run to completion (it
always finishes cloning v8 before it gets to CIPD resolution).

https://github.com/riseproject-dev/python-wheels/actions/runs/34734236315/job/103662627780
CI proved the retry itself wrong: gclient still re-resolved and
re-checked-out the v8 solution as normal (branch-heads/14.4 is a
branch name, not a pinned hash, so the current_revision fast path
never applied), refusing to proceed over our uncommitted DEPS edit
("You have uncommitted changes"). Drop --revision from the retry so
the .gclient's "managed: False" takes effect (only happens when there
is no revision override), skipping v8's git step entirely rather than
touching the working tree.

https://github.com/riseproject-dev/python-wheels/actions/runs/34735996717/job/103669201128
…alse on riscv64

CI got past the DEPS/CIPD fixes into an actual ninja build for the
first time, surfacing three independent problems: the bundled
debian_trixie_riscv64-sysroot is missing a multiarch header our
riscv64-linux-gnu- toolprefix trick expects, v8's custom libc++ needs
GCC 15+ (ours is older), and the prebuilt Rust toolchain segfaults on
riscv64 (published for amd64/arm64/mac hosts only, same as clang).

https://github.com/riseproject-dev/python-wheels/actions/runs/34738407307/job/103678169855
luhenry added a commit that referenced this pull request Sep 13, 2026
sqreen/PyMiniRacer's own README deprecates it in favor of the
bpcreech/PyMiniRacer fork, which continues under the PyPI name
mini-racer (already being ported in PR #1875). py-mini-racer's last
PyPI release stayed at 0.6.0 (2021-04-22).
enable_rust=false alone doesn't work: gn gen failed with
'assert(enable_rust)' in build/rust/gni_impl/rust_target.gni, reached
via v8_maybe_temporal -> third_party/rust/temporal_capi.
v8_enable_temporal_support's own default already excludes ppc64 and
s390x by name ('some architectures don't have Rust toolchains in
Chromium') -- riscv64 is simply missing from that list. Temporal is
runtime-flag-gated even when built in, so disabling it drops no
default-on behavior.

https://github.com/riseproject-dev/python-wheels/actions/runs/34742097041/job/103685126595
…stall patch(1)

CI got past gn gen and almost an hour into the actual ninja build,
then failed compiling with GCC (is_clang=false):

  ../../src/strings/unicode.h:218:13: error: explicit specialization
    in non-namespace scope 'class unibrow::Utf8'

unibrow::Utf8::WriteLeadingAscii's two explicit specializations are
declared a second time inside the class body; clang accepts this as
an extension, GCC correctly rejects it (explicit specializations of a
member template must be at namespace scope). The out-of-line
definitions in unicode.cc are already namespace-scope and
standard-conformant on their own, so the in-class declarations are
both redundant and non-portable. Wire up the previously-unused
apply_patch() to drop them for a riscv64 build, and install the
patch(1) utility it shells out to.

https://github.com/riseproject-dev/python-wheels/actions/runs/34744357842/job/103689419698
CI got past the unicode.h fix and ~46% (1011/2176) into the ninja
build before hitting another GCC-only warning-as-error in
bigint/mul-karatsuba.cc ('1 << (shift - 2)' is int, compared against a
uint32_t; clang doesn't flag it, GCC does under -Wsign-compare). Cast
it explicitly. Renamed the accumulating patch to reflect that this is
evidently a class of issue, and pass ninja -k 1000 on riscv64 so one
build surfaces as many of these as it can find, instead of one
discovery per multi-hour CI cycle.

https://github.com/riseproject-dev/python-wheels/actions/runs/34748309593/job/103700194955
The -k 1000 run paid off: instead of one failure per cycle it collected
all six that were left, and the job died at exactly timeout-minutes:
1440 with the build at 1970/2176 and still progressing normally -- so
the cancellation was the timeout, not an infra flake or a hold.

Five of the six are -Werror diagnostics GCC emits and clang does not
(-Wuninitialized x53 in liftoff-compiler.cc, -Wdangling-reference in
js-call-reducer.cc and js-typed-lowering.cc, -Wsign-compare in
maglev-graph-builder.cc, -Wparentheses in collection-barrier.cc), all
benign or false positives. V8 only gates -Werror on clang for
third_party code precisely because "GCC may emit unsuppressible
warnings", so set treat_warnings_as_errors=false rather than keep
casting one line per 24h cycle, and drop the one cast already added
for that reason.

The sixth is a genuine error in third_party/highway: json-stringifier.cc
wants a 16-lane FixedTag, highway resolved to HWY_SCALAR because its
EMU128 opt-out disables EMU128 for any GCC below 16.0 at the revision
v8 pins. On RISC-V without the V extension EMU128 is the only fallback
that has fixed-width tags at all; highway has since fixed this upstream
and names V8's JSON stringifier as the breakage, so backport the
carve-out.

Drop ninja -k 1000 now that the class it was hunting is gone -- past
this point it only turns a fast failure into a 24h timeout -- and raise
timeout-minutes to 2880, the value build-nodejs-wheel-binaries.yml and
build-vtk.yml already use for full-V8-from-source work on these 4-core
runners. 23h30m only reached 90% of ninja, so 24h was never enough.

https://github.com/riseproject-dev/python-wheels/actions/runs/34755707688/job/103719604859
The branch sat open for six days and the repo moved: _setup.yml now
takes a required package: input and hands back a JSON list of the
versions to build, and pr-checks.yml grew a check_packages_yaml job
that enforces it. Calling _setup.yml with no inputs is a startup
failure, so the last push produced a run with no jobs at all rather
than a build -- nothing to do with the v8 fixes it carried.

Bring the workflow to the shape every recently-merged sibling uses
(build-nodejs-wheel-binaries.yml is the closest, being the other
V8-from-source port):

* add docs/packages/mini-racer.yaml with one pending 0.14.1 entry.
  This was missing outright, which is also why check_packages_yaml
  failed; the version belongs there, never in the workflow.
* call _setup.yml with package: mini-racer, and iterate
  matrix.version over its versions output in all three jobs, gated on
  needs.setup.outputs.versions != '[]', instead of hardcoding 0.14.1
  in nine places.
* turn the workflow_dispatch input into the standard optional version
  glob rather than a required tag.
* add the push: trigger that was missing, restrict both path triggers
  to main, and list docs/packages/mini-racer.yaml in them.
* pass secrets.RISEPROJECT_APP_PRIVATE_KEY to _publish-wheel.yml, as
  708 of the 711 workflows on main do; without it the documentation PR
  gets no checks.
@luhenry luhenry changed the title mini-racer: add build-mini-racer.yml for riscv64 wheels mini-racer: Add version 0.14.1 Sep 19, 2026
build_wheel installs the wheel and runs pytest under four interpreters
on a 4-core riscv64 runner, and it only starts after build_dll has
spent a day compiling V8. Hitting the implicit 360-minute default
there would cost that whole day again to find out, so state the
timeout with margin instead of inheriting one sized for a normal job.
luhenry added a commit that referenced this pull request Sep 19, 2026
Record what PR #1875's stalled run actually was and what unblocked it,
so nobody re-reads that cancellation as a maintainer stop signal: the
build_dll job ran exactly its 1440-minute timeout with ninja still
progressing at 1970/2176, the six remaining compile failures are now
fixed, and the branch has been caught up with main's _setup.yml
contract after six days of drift. Still ci-running; the V8 compile
needs over a day, so the branch must be left alone until it lands.
@github-actions

github-actions Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://riseproject-dev.github.io/python-wheels/pr-preview/pr-1875/

Built to branch gh-pages at 2026-09-19 11:14 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

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