Skip to content

Commit 32ac98e

Browse files
tiranbrettcannon
andauthored
gh-95853: Add script to automate WASM build (GH-95828)
Automate WASM build with a new Python script. The script provides several build profiles with configure flags for Emscripten flavors and WASI. The script can detect and use Emscripten SDK and WASI SDK from default locations or env vars. ``configure`` now detects Node arguments and creates HOSTRUNNER arguments for Node 16. It also sets correct arguments for ``wasm64-emscripten``. Co-authored-by: Brett Cannon <[email protected]>
1 parent 0b329f4 commit 32ac98e

File tree

9 files changed

+827
-21
lines changed

9 files changed

+827
-21
lines changed

Lib/test/test_unicode_file_functions.py

+5
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import warnings
77
from unicodedata import normalize
88
from test.support import os_helper
9+
from test import support
910

1011

1112
filenames = [
@@ -123,6 +124,10 @@ def test_open(self):
123124
# NFKD in Python is useless, because darwin will normalize it later and so
124125
# open(), os.stat(), etc. don't raise any exception.
125126
@unittest.skipIf(sys.platform == 'darwin', 'irrelevant test on Mac OS X')
127+
@unittest.skipIf(
128+
support.is_emscripten or support.is_wasi,
129+
"test fails on Emscripten/WASI when host platform is macOS."
130+
)
126131
def test_normalize(self):
127132
files = set(self.files)
128133
others = set()

Lib/test/test_warnings/__init__.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,14 @@ def test_warn_explicit_non_ascii_filename(self):
487487
module=self.module) as w:
488488
self.module.resetwarnings()
489489
self.module.filterwarnings("always", category=UserWarning)
490-
for filename in ("nonascii\xe9\u20ac", "surrogate\udc80"):
490+
filenames = ["nonascii\xe9\u20ac"]
491+
if not support.is_emscripten:
492+
# JavaScript does not like surrogates.
493+
# Invalid UTF-8 leading byte 0x80 encountered when
494+
# deserializing a UTF-8 string in wasm memory to a JS
495+
# string!
496+
filenames.append("surrogate\udc80")
497+
for filename in filenames:
491498
try:
492499
os.fsencode(filename)
493500
except UnicodeEncodeError:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
The new tool ``Tools/wasm/wasm_builder.py`` automates configure, compile, and
2+
test steps for building CPython on WebAssembly platforms.

Python/sysmodule.c

+7-3
Original file line numberDiff line numberDiff line change
@@ -2789,14 +2789,18 @@ EM_JS(char *, _Py_emscripten_runtime, (void), {
27892789
if (typeof navigator == 'object') {
27902790
info = navigator.userAgent;
27912791
} else if (typeof process == 'object') {
2792-
info = "Node.js ".concat(process.version)
2792+
info = "Node.js ".concat(process.version);
27932793
} else {
2794-
info = "UNKNOWN"
2794+
info = "UNKNOWN";
27952795
}
27962796
var len = lengthBytesUTF8(info) + 1;
27972797
var res = _malloc(len);
2798-
stringToUTF8(info, res, len);
2798+
if (res) stringToUTF8(info, res, len);
2799+
#if __wasm64__
2800+
return BigInt(res);
2801+
#else
27992802
return res;
2803+
#endif
28002804
});
28012805

28022806
static PyObject *

Tools/wasm/README.md

+35-7
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,13 @@ docker run --rm -ti -v $(pwd):/python-wasm/cpython -w /python-wasm/cpython quay.
3535

3636
### Compile a build Python interpreter
3737

38-
From within the container, run the following commands:
38+
From within the container, run the following command:
39+
40+
```shell
41+
./Tools/wasm/wasm_build.py build
42+
```
43+
44+
The command is roughly equivalent to:
3945

4046
```shell
4147
mkdir -p builddir/build
@@ -45,13 +51,13 @@ make -j$(nproc)
4551
popd
4652
```
4753

48-
### Fetch and build additional emscripten ports
54+
### Cross-compile to wasm32-emscripten for browser
4955

5056
```shell
51-
embuilder build zlib bzip2
57+
./Tools/wasm/wasm_build.py emscripten-browser
5258
```
5359

54-
### Cross compile to wasm32-emscripten for browser
60+
The command is roughly equivalent to:
5561

5662
```shell
5763
mkdir -p builddir/emscripten-browser
@@ -85,22 +91,29 @@ and header files with debug builds.
8591
### Cross compile to wasm32-emscripten for node
8692

8793
```shell
88-
mkdir -p builddir/emscripten-node
89-
pushd builddir/emscripten-node
94+
./Tools/wasm/wasm_build.py emscripten-browser-dl
95+
```
96+
97+
The command is roughly equivalent to:
98+
99+
```shell
100+
mkdir -p builddir/emscripten-node-dl
101+
pushd builddir/emscripten-node-dl
90102

91103
CONFIG_SITE=../../Tools/wasm/config.site-wasm32-emscripten \
92104
emconfigure ../../configure -C \
93105
--host=wasm32-unknown-emscripten \
94106
--build=$(../../config.guess) \
95107
--with-emscripten-target=node \
108+
--enable-wasm-dynamic-linking \
96109
--with-build-python=$(pwd)/../build/python
97110

98111
emmake make -j$(nproc)
99112
popd
100113
```
101114

102115
```shell
103-
node --experimental-wasm-threads --experimental-wasm-bulk-memory --experimental-wasm-bigint builddir/emscripten-node/python.js
116+
node --experimental-wasm-threads --experimental-wasm-bulk-memory --experimental-wasm-bigint builddir/emscripten-node-dl/python.js
104117
```
105118

106119
(``--experimental-wasm-bigint`` is not needed with recent NodeJS versions)
@@ -199,6 +212,15 @@ Node builds use ``NODERAWFS``.
199212
- Node RawFS allows direct access to the host file system without need to
200213
perform ``FS.mount()`` call.
201214

215+
## wasm64-emscripten
216+
217+
- wasm64 requires recent NodeJS and ``--experimental-wasm-memory64``.
218+
- ``EM_JS`` functions must return ``BigInt()``.
219+
- ``Py_BuildValue()`` format strings must match size of types. Confusing 32
220+
and 64 bits types leads to memory corruption, see
221+
[gh-95876](https://github.com/python/cpython/issues/95876) and
222+
[gh-95878](https://github.com/python/cpython/issues/95878).
223+
202224
# Hosting Python WASM builds
203225

204226
The simple REPL terminal uses SharedArrayBuffer. For security reasons
@@ -234,6 +256,12 @@ The script ``wasi-env`` sets necessary compiler and linker flags as well as
234256
``pkg-config`` overrides. The script assumes that WASI-SDK is installed in
235257
``/opt/wasi-sdk`` or ``$WASI_SDK_PATH``.
236258

259+
```shell
260+
./Tools/wasm/wasm_build.py wasi
261+
```
262+
263+
The command is roughly equivalent to:
264+
237265
```shell
238266
mkdir -p builddir/wasi
239267
pushd builddir/wasi

Tools/wasm/wasi-env

+2-1
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,5 @@ export CFLAGS LDFLAGS
7272
export PKG_CONFIG_PATH PKG_CONFIG_LIBDIR PKG_CONFIG_SYSROOT_DIR
7373
export PATH
7474

75-
exec "$@"
75+
# no exec, it makes arvg[0] path absolute.
76+
"$@"

0 commit comments

Comments
 (0)