Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions recipes/recipes_emscripten/python/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,24 @@ sysconfigdata:

LIBPYTHON_EXTRA_OBJECTS=$$(LIBMPDEC_OBJS) $$(LIBEXPAT_OBJS) $$(LIBHACL_SHA2_OBJS)

$(BUILD)/.patched_makefile:
$(BUILD)/.patched_makefile: $(BUILD)/Makefile
# Clear out libinstall deps (we build what we want explicitly first)
cd $(BUILD) && sed -i -e 's/libinstall:.*/libinstall:/' Makefile;
# Inject extra objects into libpython3.13.a so we don't have to link them
# Disable HACL SIMD (x86-only) for wasm32 so portable Blake2 is used
cd $(BUILD) && sed -i 's/^LIBHACL_BLAKE2_SIMD128_OBJS=.*/LIBHACL_BLAKE2_SIMD128_OBJS=/' Makefile && sed -i 's/^LIBHACL_BLAKE2_SIMD256_OBJS=.*/LIBHACL_BLAKE2_SIMD256_OBJS=/' Makefile
# wasm_assets.py reads PYTHON_SYSCONFIGDATA_PATH in install step (patch 0009)
# Inject extra objects into libpython3.14.a so we don't have to link them
# separately
cd $(BUILD) && sed -i '/MODOBJS=/s/$$/ $(LIBPYTHON_EXTRA_OBJECTS)/' Makefile
touch $(BUILD)/.patched_makefile

$(INSTALL)/lib/$(LIB): $(BUILD)/$(LIB) sysconfigdata $(BUILD)/.patched_makefile
( \
cd $(BUILD); \
sed -i -e 's/^LIBHACL_BLAKE2_SIMD128_OBJS=.*/LIBHACL_BLAKE2_SIMD128_OBJS=/' -e 's/^LIBHACL_BLAKE2_SIMD256_OBJS=.*/LIBHACL_BLAKE2_SIMD256_OBJS=/' Makefile; \
sysconfigpath="$$(pwd)/$$(cat pybuilddir.txt)/$(SYSCONFIG_NAME).py"; \
touch $(BUILD)/$(LIB) ; \
emmake make PYTHON_FOR_BUILD=$(HOSTPYTHON) CROSS_COMPILE=yes inclinstall libinstall $(LIB) -j${CPU_COUNT} && \
_PYTHON_SYSCONFIGDATA_NAME=$(SYSCONFIG_NAME) PYTHON_SYSCONFIGDATA_PATH="$$sysconfigpath" emmake make PYTHON_FOR_BUILD=$(HOSTPYTHON) CROSS_COMPILE=yes inclinstall libinstall $(LIB) -j${CPU_COUNT} && \
cp $(LIB) $(INSTALL)/lib/ \
)
# Generate sysconfigdata. It outputs into a subfolder of build/, and
Expand Down Expand Up @@ -67,43 +72,52 @@ $(BUILD)/.patched:
touch $@


$(BUILD)/Makefile:
$(BUILD)/Makefile: $(BUILD)/Modules/Setup.local
# --enable-big-digits=30 :
# Python integers have "digits" of size 15 by default on systems with 32
# bit pointers and size 30 on systems with 16 bit pointers. Python uses
# "digits" of size 15 by default on systems with 32 bit pointers and size
# 30 on systems with 16 bit pointers. WASM has 32 bit pointers so Python
# will default to the size 15 digits but WASM has native 64 bit arithmetic
# so it is more efficient to use 30 bit digits.
cp Setup.local $(BUILD)/Modules/
( \
cd $(BUILD); \
echo 'ac_cv_lib_uuid_uuid_generate_time_safe=no' >> ./Tools/wasm/config.site-wasm32-emscripten; \
echo 'have_uuid=no' >> ./Tools/wasm/config.site-wasm32-emscripten; \
ac_cv_header_fcntl_h=yes ac_cv_func_fcntl=yes \
ac_cv_func_mbstowcs=yes ac_cv_broken_mbstowcs=yes \
ac_cv_file__dev_ptmx=no ac_cv_file__dev_ptc=no \
ac_cv_func_memfd_create=no \
CONFIG_SITE=./Tools/wasm/config.site-wasm32-emscripten READELF=true emconfigure \
./configure \
CFLAGS="${PYTHON_CFLAGS} -I$(PREFIX)" \
CPPFLAGS="-sUSE_BZIP2=1 -sUSE_ZLIB=1 -I$(PREFIX)" \
LDFLAGS="-L$(PREFIX)/lib" \
PLATFORM_TRIPLET="$(PLATFORM_TRIPLET)" \
--without-pymalloc \
--disable-shared \
--disable-ipv6 \
--enable-big-digits=30 \
--enable-optimizations \
--host=wasm32-unknown-emscripten\
--build=$(shell $(BUILD)/config.guess) \
--prefix=$(INSTALL) \
--with-build-python=$(BUILD_PREFIX)/bin/python \
)
; \
sed -i 's/^LIBHACL_BLAKE2_SIMD128_OBJS=.*/LIBHACL_BLAKE2_SIMD128_OBJS=/' Makefile \
; sed -i 's/^LIBHACL_BLAKE2_SIMD256_OBJS=.*/LIBHACL_BLAKE2_SIMD256_OBJS=/' Makefile \
)


$(BUILD)/Modules/Setup.local: Setup.local
cp Setup.local $(BUILD)/Modules/

$(BUILD)/$(LIB): $(BUILD)/Makefile $(BUILD)/pyconfig.h $(BUILD)/Modules/Setup.local
$(BUILD)/$(LIB): $(BUILD)/Makefile $(BUILD)/pyconfig.h $(BUILD)/Modules/Setup.local $(BUILD)/.patched_makefile
cp Setup.local $(BUILD)/Modules/
( \
cd $(BUILD); \
sed -i -e 's/^LIBHACL_BLAKE2_SIMD128_OBJS=.*/LIBHACL_BLAKE2_SIMD128_OBJS=/' -e 's/^LIBHACL_BLAKE2_SIMD256_OBJS=.*/LIBHACL_BLAKE2_SIMD256_OBJS=/' Makefile; \
make regen-frozen; \
emmake make CROSS_COMPILE=yes $(LIB) -j${CPU_COUNT} \
PREFIX=$(PREFIX) emmake make PYTHON_FOR_BUILD=$(HOSTPYTHON) CROSS_COMPILE=yes $(LIB) -j${CPU_COUNT} \
)
touch $(BUILD)/$(LIB)
2 changes: 1 addition & 1 deletion recipes/recipes_emscripten/python/Makefile.envs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export PYVERSION ?= 3.13.1
export PYVERSION ?= 3.14.3

ifdef CPYTHON_DEBUG
export CPYTHON_ABI_FLAGS=d
Expand Down
10 changes: 6 additions & 4 deletions recipes/recipes_emscripten/python/Setup.local
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,24 @@

*static*

CTYPES_FLAGS=-DHAVE_FFI_PREP_CIF_VAR=1 -DHAVE_FFI_PREP_CLOSURE_LOC=1 -DHAVE_FFI_CLOSURE_ALLOC=1 -I $(PREFIX)/include
CTYPES_FLAGS=-DHAVE_FFI_PREP_CIF_VAR=1 -DHAVE_FFI_PREP_CLOSURE_LOC=1 -DHAVE_FFI_CLOSURE_ALLOC=1 -L$(prefix)/lib -I$(prefix)/include -lffi
_ctypes _ctypes/_ctypes.c _ctypes/callbacks.c _ctypes/callproc.c _ctypes/cfield.c _ctypes/stgdict.c $(CTYPES_FLAGS)

_posixsubprocess _posixsubprocess.c

_bz2 _bz2module.c -lbz2
zlib zlibmodule.c

_ssl _ssl.c -lssl -lcrypto -L$(PREFIX)/lib -I$(PREFIX)/include -DOPENSSL_THREADS
_ssl _ssl.c -lssl -lcrypto -L$(prefix)/lib -I$(prefix)/include -DOPENSSL_THREADS

fcntl fcntlmodule.c -L$(PREFIX)/lib -I$(PREFIX)/include
fcntl fcntlmodule.c -L$(prefix)/lib -I$(prefix)/include


#_xxsubinterpreters _xxsubinterpretersmodule.c

_lzma _lzmamodule.c -I $(PREFIX)/include
_lzma _lzmamodule.c -L$(prefix)/lib -I$(prefix)/include -llzma

# _uuid requires libuuid link; uuid stdlib works without it (ImportError fallback). Disable for wasm to avoid link issues.
*disabled*
pwd
_hashlib
Expand Down
6 changes: 4 additions & 2 deletions recipes/recipes_emscripten/python/build.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/bash

PY_VERSION=3.13
PY_VERSION=3.14

set -euxo pipefail

Expand All @@ -18,11 +18,13 @@ mv Doc Grammar Include LICENSE Lib Mac Misc Modules Objects PC PCbuild Parser Pr
# copy the LICENSE file back for the recipe
cp ${BUILD}/LICENSE .

# create a symlink from $BUILD_PREFIX/bin/python3.11 to $BUILD_PREFIX/bin/python.js
# create a symlink from $BUILD_PREFIX/bin/python3.XY to $BUILD_PREFIX/bin/python.js
# since the python build script overwrites the env variable PYTHON to python.js
# as it assumes this is the correct name for the python binary when building for emscripten.
# But emscripten itself (emcc/emar/...) relies on the env variable PYTHON to be set to python<version_major>.<version_minor>
ln -s $BUILD_PREFIX/bin/python${PY_VERSION} $BUILD_PREFIX/bin/python.js
# Newer Emscripten SDK invokes "python.mjs"; ensure it resolves to host Python so emcc works.
ln -sf $BUILD_PREFIX/bin/python${PY_VERSION} $BUILD_PREFIX/bin/python.mjs

# create an empty emsdk_env.sh in CONDA_EMSDK_DIR
echo "" > $EMSCRIPTEN_FORGE_EMSDK_DIR/emsdk_env.sh
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Julien Jerphanion <git@jjerphan.xyz>
Date: Mon, 1 Jan 2024 00:00:00 +0000
Subject: [PATCH] Build trampoline with standalone clang without -mgc

The source no longer uses __builtin_wasm_test_function_pointer_signature
(see 0007 compat patch), so -mgc is not needed. Use standalone clang with
-nostdlib to produce minimal wasm without pulling in emscripten runtime.
---
Makefile.pre.in | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Makefile.pre.in b/Makefile.pre.in
index 0000000..1111111 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -3111,5 +3111,5 @@
Python/emscripten_trampoline_inner.wasm: $(srcdir)/Python/emscripten_trampoline_inner.c
# emcc has a path that ends with emsdk/upstream/emscripten/emcc, we're looking for emsdk/upstream/bin/clang.
- $$(dirname $$(dirname $(CC)))/bin/clang -o $@ $< -mgc -O2 -Wl,--no-entry -Wl,--import-table -Wl,--import-memory -target wasm32-unknown-unknown -nostdlib
+ $$(dirname $$(dirname $(CC)))/bin/clang -o $@ $< -O2 -Wl,--no-entry -Wl,--import-table -Wl,--import-memory -target wasm32-unknown-unknown -nostdlib

Python/emscripten_trampoline_wasm.c: Python/emscripten_trampoline_inner.wasm
$(PYTHON_FOR_REGEN) $(srcdir)/Tools/wasm/emscripten/prepare_external_wasm.py $< $@ getWasmTrampolineModule
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Julien Jerphanion <git@jjerphan.xyz>
Date: Mon, 1 Jan 2024 00:00:00 +0000
Subject: [PATCH] Compat for missing __builtin_wasm_test_function_pointer_signature

Toolchains before Emscripten 4.0.12 (LLVM without llvm#150201) do not
provide this builtin. Use a stub that always assumes signature matches
so the trampoline compiles; may trap for 0/1/2-arg callables.
---
Python/emscripten_trampoline_inner.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/Python/emscripten_trampoline_inner.c b/Python/emscripten_trampoline_inner.c
index 0000000..1111111 100644
--- a/Python/emscripten_trampoline_inner.c
+++ b/Python/emscripten_trampoline_inner.c
@@ -18,6 +18,13 @@ typedef PyObject* (*zero_arg)(void);

-#define TRY_RETURN_CALL(ty, args...) \
- if (__builtin_wasm_test_function_pointer_signature((ty)func)) { \
+
+/* Compat for toolchains without __builtin_wasm_test_function_pointer_signature
+ (e.g. Emscripten < 4.0.12, llvm/llvm-project#150201). Always assume match. */
+static inline int compat_wasm_test_function_pointer_signature(void *f) { (void)f; return 1; }
+
+#define TRY_RETURN_CALL(ty, args...) \
+ if (compat_wasm_test_function_pointer_signature((ty)func)) { \
return ((ty)func)(args); \
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Julien Jerphanion <git@jjerphan.xyz>
Date: Mon, 1 Jan 2024 00:00:00 +0000
Subject: [PATCH] Disable HACL SIMD for Emscripten

The *mmintrin.h headers are x86-specific; disable SIMD128/SIMD256 on
Emscripten (wasm32) so we use the portable Blake2 implementation.
---
configure.ac | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/configure.ac b/configure.ac
index 0000000..1111111 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7993,8 +7993,8 @@
# The SIMD files use aligned_alloc, which is not available on older versions of
# Android.
# The *mmintrin.h headers are x86-family-specific, so can't be used on WASI.
-if test "$ac_sys_system" != "Linux-android" -a "$ac_sys_system" != "WASI" || \
+if test "$ac_sys_system" != "Linux-android" -a "$ac_sys_system" != "WASI" -a "$ac_sys_system" != "Emscripten" || \
{ test -n "$ANDROID_API_LEVEL" && test "$ANDROID_API_LEVEL" -ge 28; }
then
dnl This can be extended here to detect e.g. Power8, which HACL* should also support.
@@ -8028,8 +8028,8 @@
# Although AVX support is not guaranteed on Android
# (https://developer.android.com/ndk/guides/abis#86-64), this is safe because we do a
# runtime CPUID check.
-if test "$ac_sys_system" != "Linux-android" -a "$ac_sys_system" != "WASI" || \
+if test "$ac_sys_system" != "Linux-android" -a "$ac_sys_system" != "WASI" -a "$ac_sys_system" != "Emscripten" || \
{ test -n "$ANDROID_API_LEVEL" && test "$ANDROID_API_LEVEL" -ge 28; }
then
AX_CHECK_COMPILE_FLAG([-mavx2],[
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Julien Jerphanion <git@jjerphan.xyz>
Date: Mon, 1 Jan 2024 00:00:00 +0000
Subject: [PATCH] wasm_assets: allow sysconfig data path via env (cross-build)

When building with host Python for wasm target, sysconfig uses host name.
Allow overriding via PYTHON_SYSCONFIGDATA_PATH so the Makefile does not
need to be patched.
---
Tools/wasm/emscripten/wasm_assets.py | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)

diff --git a/Tools/wasm/emscripten/wasm_assets.py b/Tools/wasm/emscripten/wasm_assets.py
index 0000000..1111111 100644
--- a/Tools/wasm/emscripten/wasm_assets.py
+++ b/Tools/wasm/emscripten/wasm_assets.py
@@ -15,6 +15,7 @@ The WASM asset bundles are pre-loaded by the final WASM build. The bundle
"""

import argparse
+import os
import pathlib
import sys
import sysconfig
@@ -102,6 +103,13 @@ def get_builddir(args: argparse.Namespace) -> pathlib.Path:


def get_sysconfigdata(args: argparse.Namespace) -> pathlib.Path:
+ """Get path to sysconfigdata; overridable via PYTHON_SYSCONFIGDATA_PATH for cross-build."""
+ env_path = os.environ.get("PYTHON_SYSCONFIGDATA_PATH")
+ if env_path:
+ return pathlib.Path(env_path).resolve()
"""Get path to sysconfigdata relative to build root"""
assert isinstance(args.builddir, pathlib.Path)
data_name: str = sysconfig._get_sysconfigdata_name() # type: ignore[attr-defined]
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Julien Jerphanion <git@jjerphan.xyz>
Date: Mon, 1 Jan 2024 00:00:00 +0000
Subject: [PATCH] blake2: undef HACL SIMD macros for wasm32

HACL SIMD128/SIMD256 objects are not built for Emscripten (x86-only).
Undef the macros so blake2module uses the portable Blake2 path.
---
Modules/blake2module.c | 6 ++++++
1 file changed, 6 insertions(+), 0 deletions(-)

diff --git a/Modules/blake2module.c b/Modules/blake2module.c
index 0000000..1111111 100644
--- a/Modules/blake2module.c
+++ b/Modules/blake2module.c
@@ -49,6 +49,12 @@
#if defined(__APPLE__) && defined(__arm64__)
# undef _Py_HACL_CAN_COMPILE_VEC128
# undef _Py_HACL_CAN_COMPILE_VEC256
#endif
+
+/* Emscripten/wasm32: HACL SIMD objects are not built (x86-only), use portable Blake2. */
+#if defined(__wasm32__)
+# undef _Py_HACL_CAN_COMPILE_VEC128
+# undef _Py_HACL_CAN_COMPILE_VEC256
+#endif

// ECX
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Julien Jerphanion <git@jjerphan.xyz>
Date: Mon, 1 Jan 2024 00:00:00 +0000
Subject: [PATCH] Avoid uuid_generate_time_safe reference on Emscripten

Emscripten builds fail to link _uuid because the object references
uuid_generate_time_safe but libuuid is not linked into the final binary.
Stub the call on __EMSCRIPTEN__ so the symbol is not referenced.
---
Modules/_uuidmodule.c | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/Modules/_uuidmodule.c b/Modules/_uuidmodule.c
--- a/Modules/_uuidmodule.c
+++ b/Modules/_uuidmodule.c
@@ -29,6 +29,11 @@
PyObject *Py_UNUSED(ignored))
{
uuid_t uuid;
+#ifdef __EMSCRIPTEN__
+ PyErr_SetString(PyExc_NotImplementedError,
+ "uuid_generate_time_safe is not available on Emscripten");
+ return NULL;
+#else
#ifdef HAVE_UUID_GENERATE_TIME_SAFE
int res;

@@ -48,6 +53,7 @@
uuid_generate_time(uuid);
return Py_BuildValue("y#O", (const char *) uuid, sizeof(uuid), Py_None);
#endif /* HAVE_UUID_GENERATE_TIME_SAFE */
+#endif /* !__EMSCRIPTEN__ */
}

#else /* MS_WINDOWS */
17 changes: 12 additions & 5 deletions recipes/recipes_emscripten/python/recipe.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
context:
version: 3.13.1
version: 3.14.3
name: python
ver2: '3.13'
ver2: '3.14'
ver2nd: ${{ version | version_to_buildstring}}
build_number: 11
build_number: 1
abi_tag: cp${{ ver2nd }}

package:
Expand All @@ -12,9 +12,14 @@ package:

source:
- url: https://www.python.org/ftp/python/${{ version }}/Python-${{ version }}.tar.xz
sha256: 9cf9427bee9e2242e3877dd0f6b641c1853ca461f39d6503ce260a59c80bf0d9
sha256: a97d5549e9ad81fe17159ed02c68774ad5d266c72f8d9a0b5a9c371fe85d902b
patches:
- patches/0005-Fix-LONG_BIT-constant-to-be-always-32bit.patch
- patches/0006-Use-emcc-for-emscripten_trampoline_inner.wasm.patch
- patches/0007-Compat-for-missing-builtin_wasm_test_function_pointer_signature.patch
- patches/0009-wasm_assets-allow-sysconfig-data-path-for-cross.patch
- patches/0010-blake2-undef-HACL-SIMD-macros-for-wasm.patch
- patches/0011-disable-uuid-generate-time-safe-on-emscripten.patch
build:
number: ${{ build_number }}
string: h_${{ hash }}_${{build_number}}_${{ abi_tag }}
Expand Down Expand Up @@ -50,11 +55,13 @@ requirements:
- patch # only needed on MacOS
- sed # only needed on MacOS
- wget
- python=3.13
- python=3.14
host:
- openssl
- libffi
- liblzma
- zstd
- libuuid
run:
- python_abi ${{ ver2 }}.* *_${{ abi_tag }}
run_exports:
Expand Down
2 changes: 1 addition & 1 deletion recipes/recipes_emscripten/python_abi/recipe.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
context:
name: python_abi
version: "3.13.1" # keep sync with python
version: "3.14.3" # keep sync with python
ver2nd: ${{ version | version_to_buildstring}}
python_abi_tag: "cp${{ ver2nd }}"
build_num: 1
Expand Down
Loading