Skip to content

skia-python: add build-skia-python.yml for riscv64 wheels - #1697

Open
luhenry wants to merge 8 commits into
mainfrom
skia-python
Open

skia-python: add build-skia-python.yml for riscv64 wheels#1697
luhenry wants to merge 8 commits into
mainfrom
skia-python

Conversation

@luhenry

@luhenry luhenry commented Sep 10, 2026

Copy link
Copy Markdown
Member

Compiles Google's Skia 2D graphics library from source (GN/Ninja) and links it into a pybind11 extension. Upstream publishes no riscv64 wheel.

Mirrors upstream's ci.yml build_wheels job, grouping all four interpreters into one CIBW_BUILD so the Skia compile in CIBW_BEFORE_ALL_LINUX runs once, not per interpreter.

Differs from upstream

  • scripts/build_Linux.sh's yum install ninja-build gn reimplemented inline - both packages come from EPEL, which the riscv64 image doesn't carry.
  • ninja comes from its own riscv64 PyPI wheel; gn is bootstrapped from source at a pinned commit (no upstream binary or package exists for riscv64).
  • Drops the xvfb-run wrapper and xorg-x11-server-Xvfb install - Rocky 10 ships no virtual X server at all (Xvfb, Xvnc, weston all absent, every arch).
  • musllinux dropped, per repo convention.

Testing

  • same as upstream, minus moderngl (no riscv64 wheel): deselects test_GrDirectContext_MakeGL_EGL, the one test that imports it.

License: OK

Patches

  • 0001-Skip-GPU-context-tests-when-glfw.init-fails-not-just.patch - Inappropriate [Rocky 10 ships no Xvfb/Xvnc/weston]. Without it, every gpu-parametrized test errors, not skips, with no display. Riscv64-only.

Built on cp312/cp313/cp314/cp314t; pending CI results.

luhenry added a commit that referenced this pull request Sep 10, 2026
…t a display

Rocky 10 (the riscv64 manylinux image's base) carries no virtual X
server at all -- xorg-x11-server-Xvfb, tigervnc-server and weston are
all absent from BaseOS/AppStream/CRB/Extras, on every architecture,
not just riscv64. Drops the dnf install and the xvfb-run wrapper, and
carries a patch so the 'gpu'-parametrized tests skip gracefully
instead of erroring when glfw can't reach a display.
build/gen.py's GenerateLastCommitPosition runs 'git describe HEAD
--match initial-commit' unconditionally whenever .git exists, to
generate a cosmetic version header; a depth-1 clone has none of the
history back to that root tag, so it fails outright with 'No names
found, cannot describe anything.' gn's repo is 42MB full, ~4s to
clone -- shallow isn't worth the fragility here.
build/gen.py's WriteGNNinja defaults cxx to os.environ.get('CXX',
'clang++') on any non-MSVC/AIX/Windows host, unconditionally --
verified against a real clone of gn's own source, and against the
live manylinux_2_39_riscv64 image manifest (quay.io), which has no
layer installing clang anywhere; only GCC is provisioned. The
/opt/clang/bin PATH entry baked into the image's own ENV is a dead
path on this architecture. Skia's own build already assumes GCC
(upstream's gn args set no is_clang), so this just makes gn's
bootstrap use the same toolchain the rest of the build already relies
on.
GCC's -Wcomment fires on src/gn/header_checker.h's ASCII-art
dependency-graph diagram (a // line ending in a backslash, e.g.
'//    / \'), and gen.py sets -Werror unconditionally unless told
otherwise. gn's own gen.py ships an --allow-warnings flag for exactly
this (source only gets -Werror coverage against clang upstream); using
it is cleaner than patching a third-party bootstrap tool's own source
for an ASCII-art comment. gn itself never ships in the wheel, so this
carries no risk to the built extension.
gn links itself with -static-libstdc++ -pthread; the riscv64 manylinux
image doesn't ship libstdc++.a by default (gotcha 77), only via the
CRB libstdc++-static package, already enabled for the other -devel
packages on this same line.
…wnload

tools/git-sync-deps calls bin/fetch-gn unconditionally, with no skip
flag (unlike its --skip-emsdk sibling). fetch-gn's CPU map has no
riscv64 entry and Google's CIPD has no prebuilt gn for riscv64 to add
one for, so it KeyErrors outright. We already built and installed our
own gn to PATH before this step runs; nothing downstream reads
skia/bin/gn or third_party/gn/gn directly, so skipping the download
when a gn is already on PATH is a correct no-op here.
BUILD.gn's 'skia.h' action target hardcodes
args = [rebase_path("//bin/gn")] + ... to invoke gn/find_headers.py,
which runs 'gn desc' to enumerate public include dirs for the
generated skia.h umbrella header -- this is evaluated at ninja build
time (not gn gen time), and reads //bin/gn directly rather than
resolving through $PATH or GN's own GetExePath()-based
self-regeneration mechanism. Confirmed against BUILD.gn and
gn/find_headers.py at the pinned skia commit before pushing, since
this failure only surfaces ~2.5h into the ninja build. Our patched
bin/fetch-gn correctly no-ops (gotcha: no riscv64 CIPD binary) but
never populates this path since it never runs its download logic;
copy our self-built gn there explicitly, same binary already at
/usr/local/bin/gn.
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