WASI support is tier 2. Emscripten support is tier 3.
This directory contains configuration and helpers to facilitate cross compilation of CPython to WebAssembly (WASM). Python supports Emscripten (wasm32-emscripten) and WASI (wasm32-wasi) targets. Emscripten builds run in modern browsers and JavaScript runtimes like Node.js. WASI builds use WASM runtimes such as wasmtime.
Users and developers are encouraged to use the script Tools/wasm/wasm_build.py
. The tool automates the build process and provides assistance with installation of SDKs, running tests, etc.
NOTE: If you are looking for information that is not directly related to building CPython for WebAssembly (or the resulting build), please see https://github.com/psf/webassembly for more information.
For now the build system has two target flavors. The Emscripten/browser
target (--with-emscripten-target=browser
) is optimized for browsers. It comes with a reduced and preloaded stdlib without tests and threading support. The Emscripten/node
target has threading enabled and can access the file system directly.
To cross compile to the wasm32-emscripten
platform you need the Emscripten compiler toolchain, a Python interpreter, and an installation of Node version 18 or newer. Emscripten version 3.1.42 or newer is recommended. All commands below are relative to a checkout of the Python repository.
You can install the Emscripten toolchain as follows:
git clone https://github.com/emscripten-core/emsdk.git --depth 1 ./emsdk/emsdk install latest ./emsdk/emsdk activate latest
To add the Emscripten compiler to your path:
source ./emsdk/emsdk_env.sh
This adds emcc
and emconfigure
to your path.
The EM_COMPILER_WRAPPER
must be set after the EMSDK environment is sourced. Otherwise the source script removes the environment variable.
export EM_COMPILER_WRAPPER=ccache
You can use python Tools/wasm/emscripten
to compile and build targetting Emscripten. You can do everything at once with:
python Tools/wasm/emscripten build
or you can break it out into four separate steps:
python Tools/wasm/emscripten configure-build-python python Tools/wasm/emscripten make-build-python python Tools/wasm/emscripten configure-host python Tools/wasm/emscripten make-host
Extra arguments to the configure steps are passed along to configure. For instance, to do a debug build, you can use:
python Tools/wasm/emscripten build --with-py-debug
asyncio
, urllib
, selectors
, etc. are not available.AF_INET
and AF_INET6
with SOCK_STREAM
(TCP) or SOCK_DGRAM
(UDP) are available. AF_UNIX
is not supported.socketpair
does not work.socket.accept
crashes the runtime. gethostbyname
does not resolve to a real IP address. IPv6 is not available.select
module is limited. select.select()
crashes the runtime due to lack of exectfd support.ENOSYS
or ENOSUP
.signal.alarm
, itimer
, sigaction
are not available or do not work correctly. SIGTERM
exits the runtime.os.nice
and most functions of the resource
module are not available.configure
option --enable-wasm-pthreads
adds compiler flag -pthread
and linker flags -sUSE_PTHREADS -sPROXY_TO_PTHREAD
.pwd
module, grp
module, os.setgroups
, os.chown
, and so on. lchown
and lchmod
are not available.umask
is a no-op.os.link
) are not supported.os.pread
, os.preadv
) are not available.os.mknod
and os.mkfifo
don't work and are disabled.mmap
module is unstable. flush (msync
) can crash the runtime.ctypes
, readline
, ssl
, and more.--enable-wasm-dynamic-linking
enables dynamic extensions supports. It's currently known to crash in combination with threading.locales
module is affected by musl libc issues, gh-90548.obmalloc
is disabled by default.ensurepip
is not available.pyc
files.--enable-test-modules
build test modules like _testcapi
.Node builds use NODERAWFS
.
FS.mount()
call.The simple REPL terminal uses SharedArrayBuffer. For security reasons browsers only provide the feature in secure environments with cross-origin isolation. The webserver must send cross-origin headers and correct MIME types for the JavaScript and WASM files. Otherwise the terminal will fail to load with an error message like Browsers disable shared array buffer
.
Place a .htaccess
file in the same directory as python.wasm
.
# .htaccess Header set Cross-Origin-Opener-Policy same-origin Header set Cross-Origin-Embedder-Policy require-corp AddType application/javascript js AddType application/wasm wasm <IfModule mod_deflate.c> AddOutputFilterByType DEFLATE text/html application/javascript application/wasm </IfModule>
See the devguide on how to build and run for WASI.
import os, sys if sys.platform == "emscripten": # Python on Emscripten ... if sys.platform == "wasi": # Python on WASI ... if os.name == "posix": # WASM platforms identify as POSIX-like. # Windows does not provide os.uname(). machine = os.uname().machine if machine.startswith("wasm"): # WebAssembly (wasm32, wasm64 potentially in the future)
>>> import os, sys >>> os.uname() posix.uname_result( sysname='Emscripten', nodename='emscripten', release='3.1.19', version='#1', machine='wasm32' ) >>> os.name 'posix' >>> sys.platform 'emscripten' >>> sys._emscripten_info sys._emscripten_info( emscripten_version=(3, 1, 10), runtime='Mozilla/5.0 (X11; Linux x86_64; rv:104.0) Gecko/20100101 Firefox/104.0', pthreads=False, shared_memory=False )
>>> sys._emscripten_info sys._emscripten_info( emscripten_version=(3, 1, 19), runtime='Node.js v14.18.2', pthreads=True, shared_memory=True )
>>> import os, sys >>> os.uname() posix.uname_result( sysname='wasi', nodename='(none)', release='0.0.0', version='0.0.0', machine='wasm32' ) >>> os.name 'posix' >>> sys.platform 'wasi'
Emscripten SDK and WASI SDK define several built-in macros. You can dump a full list of built-ins with emcc -dM -E - < /dev/null
and /path/to/wasi-sdk/bin/clang -dM -E - < /dev/null
.
__wasm__
(also __wasm
)__wasm32__
(also __wasm32
)__wasm64__
__EMSCRIPTEN__
(also EMSCRIPTEN
)__EMSCRIPTEN_major__
, __EMSCRIPTEN_minor__
, __EMSCRIPTEN_tiny__
__wasi__