1
1
# Python WebAssembly (WASM) build
2
2
3
3
** WASI support is [ tier 2] ( https://peps.python.org/pep-0011/#tier-2 ) .**
4
- ** Emscripten is NOT officially supported as of Python 3.13 .**
4
+ ** Emscripten support is [ tier 3 ] ( https://peps.python.org/pep-0011/#tier-3 ) .**
5
5
6
6
This directory contains configuration and helpers to facilitate cross
7
7
compilation of CPython to WebAssembly (WASM). Python supports Emscripten
@@ -27,154 +27,57 @@ It comes with a reduced and preloaded stdlib without tests and threading
27
27
support. The `` Emscripten/node `` target has threading enabled and can
28
28
access the file system directly.
29
29
30
- Cross compiling to the wasm32-emscripten platform needs the
31
- [ Emscripten] ( https://emscripten.org/ ) SDK and a build Python interpreter.
32
- Emscripten 3.1.19 or newer are recommended. All commands below are relative
33
- to a repository checkout.
30
+ To cross compile to the `` wasm32-emscripten `` platform you need
31
+ [ the Emscripten compiler toolchain] ( https://emscripten.org/ ) ,
32
+ a Python interpreter, and an install of Node version 18 or newer. Emscripten
33
+ 3.1.42 or newer are recommended. All commands below are relative to a checkout
34
+ of the Python repository.
34
35
35
- #### Toolchain
36
+ #### Install [ the Emscripten compiler toolchain ] ( https://emscripten.org/docs/getting_started/downloads.html )
36
37
37
- ##### Container image
38
-
39
- Christian Heimes maintains a container image with Emscripten SDK, Python
40
- build dependencies, WASI-SDK, wasmtime, and several additional tools.
41
-
42
- From within your local CPython repo clone, run one of the following commands:
43
-
44
- ```
45
- # Fedora, RHEL, CentOS
46
- podman run --rm -ti -v $(pwd):/python-wasm/cpython:Z -w /python-wasm/cpython quay.io/tiran/cpythonbuild:emsdk3
47
-
48
- # other
49
- docker run --rm -ti -v $(pwd):/python-wasm/cpython -w /python-wasm/cpython quay.io/tiran/cpythonbuild:emsdk3
38
+ You can install the Emscripten toolchain as follows:
39
+ ``` shell
40
+ git clone https://github.com/emscripten-core/emsdk.git --depth 1
41
+ ./emsdk/emsdk install 3.1.68
42
+ ./emsdk/emsdk activate 3.1.68
50
43
```
51
-
52
- ##### Manually
53
-
54
- ###### Install [ Emscripten SDK] ( https://emscripten.org/docs/getting_started/downloads.html )
55
-
56
- ** NOTE** : Follow the on-screen instructions how to add the SDK to `` PATH `` .
57
-
44
+ To add the Emscripten compiler to your path:
58
45
``` shell
59
- git clone https://github.com/emscripten-core/emsdk.git /opt/emsdk
60
- /opt/emsdk/emsdk install latest
61
- /opt/emsdk/emsdk activate latest
46
+ source ./emsdk/emsdk_env.sh
62
47
```
48
+ This adds ` emcc ` and ` emconfigure ` to your path.
63
49
64
- ###### Optionally: enable ccache for EMSDK
50
+ ##### Optionally: enable ccache for EMSDK
65
51
66
52
The `` EM_COMPILER_WRAPPER `` must be set after the EMSDK environment is
67
53
sourced. Otherwise the source script removes the environment variable.
68
54
69
- ```
70
- . /opt/emsdk/emsdk_env.sh
71
- EM_COMPILER_WRAPPER=ccache
72
- ```
73
-
74
- ###### Optionally: pre-build and cache static libraries
75
-
76
- Emscripten SDK provides static builds of core libraries without PIC
77
- (position-independent code). Python builds with `` dlopen `` support require
78
- PIC. To populate the build cache, run:
79
-
80
55
``` shell
81
- . /opt/emsdk/emsdk_env.sh
82
- embuilder build zlib bzip2 MINIMAL_PIC
83
- embuilder --pic build zlib bzip2 MINIMAL_PIC
56
+ export EM_COMPILER_WRAPPER=ccache
84
57
```
85
58
86
-
87
59
### Compile and build Python interpreter
88
60
89
- From within the container, run the following command:
90
-
91
- ``` shell
92
- ./Tools/wasm/wasm_build.py build
93
- ```
94
-
95
- The command is roughly equivalent to:
96
-
97
- ``` shell
98
- mkdir -p builddir/build
99
- pushd builddir/build
100
- ../../configure -C
101
- make -j$( nproc)
102
- popd
103
- ```
104
-
105
- #### Cross-compile to wasm32-emscripten for browser
106
-
107
- ``` shell
108
- ./Tools/wasm/wasm_build.py emscripten-browser
109
- ```
110
-
111
- The command is roughly equivalent to:
112
-
61
+ You can use ` python Tools/wasm/emscripten ` to compile and build targetting
62
+ Emscripten. You can do everything at once with:
113
63
``` shell
114
- mkdir -p builddir/emscripten-browser
115
- pushd builddir/emscripten-browser
116
-
117
- CONFIG_SITE=../../Tools/wasm/config.site-wasm32-emscripten \
118
- emconfigure ../../configure -C \
119
- --host=wasm32-unknown-emscripten \
120
- --build=$( ../../config.guess) \
121
- --with-emscripten-target=browser \
122
- --with-build-python=$( pwd) /../build/python
123
-
124
- emmake make -j$( nproc)
125
- popd
64
+ python Tools/wasm/emscripten build
126
65
```
127
-
128
- Serve ` python.html ` with a local webserver and open the file in a browser.
129
- Python comes with a minimal web server script that sets necessary HTTP
130
- headers like COOP, COEP, and mimetypes. Run the script outside the container
131
- and from the root of the CPython checkout.
132
-
66
+ or you can break it out into four separate steps:
133
67
``` shell
134
- ./Tools/wasm/wasm_webserver.py
68
+ python Tools/wasm/emscripten configure-build-python
69
+ python Tools/wasm/emscripten make-build-python
70
+ python Tools/wasm/emscripten configure-host
71
+ python Tools/wasm/emscripten make-host
135
72
```
136
-
137
- and open http://localhost:8000/builddir/emscripten-browser/python.html . This
138
- directory structure enables the * C/C++ DevTools Support (DWARF)* to load C
139
- and header files with debug builds.
140
-
141
-
142
- #### Cross compile to wasm32-emscripten for node
143
-
73
+ Extra arguments to the configure steps are passed along to configure. For
74
+ instance, to do a debug build, you can use:
144
75
``` shell
145
- ./ Tools/wasm/wasm_build.py emscripten-node-dl
76
+ python Tools/wasm/emscripten build --with-py-debug
146
77
```
147
78
148
- The command is roughly equivalent to:
149
-
150
- ``` shell
151
- mkdir -p builddir/emscripten-node-dl
152
- pushd builddir/emscripten-node-dl
153
-
154
- CONFIG_SITE=../../Tools/wasm/config.site-wasm32-emscripten \
155
- emconfigure ../../configure -C \
156
- --host=wasm32-unknown-emscripten \
157
- --build=$( ../../config.guess) \
158
- --with-emscripten-target=node \
159
- --enable-wasm-dynamic-linking \
160
- --with-build-python=$( pwd) /../build/python
161
-
162
- emmake make -j$( nproc)
163
- popd
164
- ```
165
-
166
- ``` shell
167
- node --experimental-wasm-threads --experimental-wasm-bulk-memory --experimental-wasm-bigint builddir/emscripten-node-dl/python.js
168
- ```
169
-
170
- (`` --experimental-wasm-bigint `` is not needed with recent NodeJS versions)
171
-
172
79
### Limitations and issues
173
80
174
- Emscripten before 3.1.8 has known bugs that can cause memory corruption and
175
- resource leaks. 3.1.8 contains several fixes for bugs in date and time
176
- functions.
177
-
178
81
#### Network stack
179
82
180
83
- Python's socket module does not work with Emscripten's emulated POSIX
@@ -241,8 +144,6 @@ functions.
241
144
[ gh-90548 ] ( https://github.com/python/cpython/issues/90548 ) .
242
145
- Python's object allocator `` obmalloc `` is disabled by default.
243
146
- `` ensurepip `` is not available.
244
- - Some `` ctypes `` features like `` c_longlong `` and `` c_longdouble `` may need
245
- NodeJS option `` --experimental-wasm-bigint `` .
246
147
247
148
#### In the browser
248
149
@@ -263,15 +164,6 @@ Node builds use ``NODERAWFS``.
263
164
- Node RawFS allows direct access to the host file system without need to
264
165
perform `` FS.mount() `` call.
265
166
266
- ### wasm64-emscripten
267
-
268
- - wasm64 requires recent NodeJS and `` --experimental-wasm-memory64 `` .
269
- - `` EM_JS `` functions must return `` BigInt() `` .
270
- - `` Py_BuildValue() `` format strings must match size of types. Confusing 32
271
- and 64 bits types leads to memory corruption, see
272
- [ gh-95876 ] ( https://github.com/python/cpython/issues/95876 ) and
273
- [ gh-95878 ] ( https://github.com/python/cpython/issues/95878 ) .
274
-
275
167
### Hosting Python WASM builds
276
168
277
169
The simple REPL terminal uses SharedArrayBuffer. For security reasons
0 commit comments