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__