Files
velzieandClaude Opus 5.5 e73ddff770 GL backend on wink + numpy for Python add-ons
GL backend (build-blender-gl, BLENDER_GPU=gl): wink/epoxy build scripts,
cmake cache, Blender/Mesa patches, WGSL seed cache, demo wiring, and the
compat/latency/GPU bench + profiling harnesses.

numpy: scripts/build_numpy.sh cross-compiles numpy 2.3.4 and links its
extension modules into blender.wasm as builtins (fixes glTF/FBX import,
'No module named numpy'). CPython: undo mimalloc's __wasi__ leak in
timemodule.c so time.process_time() works (FBX export). Bump BLENDER_REF
for the glTF/FBX add-on fixes. scripts/numpy_io_test.mjs covers numpy and
glTF/FBX/OBJ/PLY/STL import/export in the browser.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_25da9696629446c4ae08c8603ff6ea2f
2026-10-20 13:43:36 -04:00

93 lines
4.3 KiB
Bash

#!/usr/bin/env bash
# CPython 3.13.13 → wasm-sysroot (static libpython, embedded into Blender).
# Two-step emscripten cross-build per CPython's Tools/wasm/README.md:
# 1) a native build-python of the SAME version (freezes stdlib during cross-build)
# 2) the wasm cross-build with --enable-wasm-pthreads (matches our -pthread ABI)
set -euo pipefail
source "$(dirname "$0")/dep_common.sh"
PYSRC=$(fetch_extract \
"https://www.python.org/ftp/python/3.13.13/Python-3.13.13.tar.xz" \
"Python-3.13.13.tar.xz" "Python-3.13.13")
# The bundled mimalloc's internal.h does `#define __wasi__` on Emscripten, and it
# leaks into every core module through pycore_*.h. timemodule.c then takes its
# WASI-only (gh-115714) fallbacks, leaving time.process_time()/times() on clock(),
# which Emscripten doesn't implement -> RuntimeError (breaks e.g. the FBX
# exporter). Emscripten's CPU-time clocks work, so undo the leak in that file.
if ! grep -q "blender-wasm: mimalloc __wasi__ leak" "$PYSRC/Modules/timemodule.c"; then
python3 - "$PYSRC/Modules/timemodule.c" <<'PYEOF'
import sys
p = sys.argv[1]; s = open(p).read()
anchor = '#include <time.h> // clock()\n'
assert anchor in s
s = s.replace(anchor, anchor + (
'/* blender-wasm: mimalloc __wasi__ leak (see scripts/build_python.sh). */\n'
'#if defined(__EMSCRIPTEN__) && defined(__wasi__)\n'
'# undef __wasi__\n'
'#endif\n'), 1)
open(p, 'w').write(s)
PYEOF
log "patched timemodule.c (emscripten CPU-time clocks)"
fi
# 1) Native build-python (host interpreter used by the cross-build).
NATIVE="$BLD/python-native"
# Must be a COMPLETE build (incl. extension modules like binascii) — the wasm
# cross-build runs this interpreter for its freeze/codegen steps.
if [ ! -x "$NATIVE/python" ] || ! "$NATIVE/python" -c "import binascii, zlib" 2>/dev/null; then
log "building native build-python 3.13.13 (full)"
rm -rf "$NATIVE"; mkdir -p "$NATIVE"; ( cd "$NATIVE"
"$PYSRC/configure" -C >/dev/null
make -j"$NPROC" >/dev/null 2>&1 )
fi
BUILD_PY="$NATIVE/python"
"$BUILD_PY" --version
# 2) WASM cross-build → $SYSROOT.
WB="$BLD/python-wasm"; rm -rf "$WB"; mkdir -p "$WB"
( cd "$WB"
# -DPY_CALL_TRAMPOLINE: enable CPython's Emscripten C-function call trampoline.
# WASM call_indirect enforces exact signature match; CPython calls METH_NOARGS/
# METH_O C functions through a generic PyCFunctionWithKeywords pointer, which is
# a bad fpcast that traps ("null function or function signature mismatch") on
# wasm. The trampoline routes those calls through JS (wasmTable.get + arity
# reflection) so the real arity is honored. Not auto-defined by 3.13 configure.
CONFIG_SITE="$PYSRC/Tools/wasm/config.site-wasm32-emscripten" \
CFLAGS="-fexceptions -DPY_CALL_TRAMPOLINE" \
emconfigure "$PYSRC/configure" -C \
--host=wasm32-unknown-emscripten \
--build=x86_64-pc-linux-gnu \
--enable-wasm-pthreads \
--with-build-python="$BUILD_PY" \
--prefix="$SYSROOT" \
--disable-shared \
--disable-test-modules \
--with-ensurepip=no
emmake make -j"$NPROC"
emmake make install )
# The _decimal module's bundled libmpdec objects compile but are NOT archived
# into libpython3.13.a by CPython's static-wasm build, so _decimal.o is left with
# undefined mpd_* symbols at the final Blender link. Fold them into the archive.
# Several bundled modules compile their support sources but CPython's static-wasm
# build does NOT archive them into libpython3.13.a, leaving undefined symbols at
# the final Blender link: _decimal's libmpdec (mpd_*), pyexpat/_elementtree's
# vendored expat (PyExpat_XML_*), and hashlib's HACL SHA2 (python_hashlib_*).
# Fold them in. Prefix member names: libmpdec has context.o/io.o whose BASENAMES
# collide with core CPython objects in the flat-namespaced archive (`ar r` keys
# by basename and would silently overwrite Python's own context.o).
_mz=$(mktemp -d)
for _o in "$WB"/Modules/_decimal/libmpdec/*.o \
"$WB"/Modules/expat/xmlparse.o "$WB"/Modules/expat/xmltok.o "$WB"/Modules/expat/xmlrole.o \
"$WB"/Modules/_hacl/Hacl_Hash_SHA2.o; do
[ -f "$_o" ] && cp "$_o" "$_mz/pymod_$(basename "$_o")"
done
if ls "$_mz"/*.o >/dev/null 2>&1; then
emar r "$SYSROOT/lib/libpython3.13.a" "$_mz"/*.o
log "archived bundled libmpdec/expat/hacl objects into libpython3.13.a"
fi
rm -rf "$_mz"
log "installed python into $SYSROOT"
ls -la "$SYSROOT"/lib/libpython3.13*.a 2>&1