Skip to content

Commit 37589d7

Browse files
authored
GH-103065, GH-106704, GH-105253: Provide a Tools/wasm/wasi.py script to simplify doing a WASI build (GH-112473)
1 parent d4a6229 commit 37589d7

File tree

7 files changed

+373
-77
lines changed

7 files changed

+373
-77
lines changed

.devcontainer/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ ENV WASI_SDK_VERSION=20
66
ENV WASI_SDK_PATH=/opt/wasi-sdk
77

88
ENV WASMTIME_HOME=/opt/wasmtime
9-
ENV WASMTIME_VERSION=9.0.1
9+
ENV WASMTIME_VERSION=14.0.4
1010
ENV WASMTIME_CPU_ARCH=x86_64
1111

1212
RUN dnf -y --nodocs --setopt=install_weak_deps=False install /usr/bin/{blurb,clang,curl,git,ln,tar,xz} 'dnf-command(builddep)' && \

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ Tools/unicode/data/
125125
/config.status.lineno
126126
# hendrikmuhs/ccache-action@v1
127127
/.ccache
128+
/cross-build/
128129
/platform
129130
/profile-clean-stamp
130131
/profile-run-stamp

Makefile.pre.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2732,6 +2732,7 @@ clobber: clean
27322732
-rm -rf build platform
27332733
-rm -rf $(PYTHONFRAMEWORKDIR)
27342734
-rm -f python-config.py python-config
2735+
-rm -rf cross-build
27352736

27362737
# Make things extra clean, before making a distribution:
27372738
# remove all generated files, even Makefile[.pre]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Introduce ``Tools/wasm/wasi.py`` to simplify doing a WASI build.

Tools/wasm/README.md

Lines changed: 40 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -298,100 +298,66 @@ AddType application/wasm wasm
298298

299299
## WASI (wasm32-wasi)
300300

301-
WASI builds require the [WASI SDK](https://github.com/WebAssembly/wasi-sdk) 16.0+.
302-
See `.devcontainer/Dockerfile` for an example of how to download and
303-
install the WASI SDK.
301+
**NOTE**: The instructions below assume a Unix-based OS due to cross-compilation for CPython being set up for `./configure`.
304302

305-
### Build
303+
### Prerequisites
304+
305+
Developing for WASI requires two things to be installed:
306+
307+
1. The [WASI SDK](https://github.com/WebAssembly/wasi-sdk) 16.0+
308+
(see `.devcontainer/Dockerfile` for an example of how to download and install the WASI SDK)
309+
2. A WASI host/runtime ([wasmtime](https://wasmtime.dev) 14+ is recommended and what the instructions below assume)
306310

307-
The script ``wasi-env`` sets necessary compiler and linker flags as well as
308-
``pkg-config`` overrides. The script assumes that WASI-SDK is installed in
309-
``/opt/wasi-sdk`` or ``$WASI_SDK_PATH``.
310311

311-
There are two scripts you can use to do a WASI build from a source checkout. You can either use:
312+
### Building
312313

314+
Building for WASI requires doing a cross-build where you have a "build" Python to help produce a WASI build of CPython (technically it's a "host x host" cross-build because the build Python is also the target Python while the host build is the WASI build; yes, it's confusing terminology). In the end you should have a build Python in `cross-build/build` and a WASI build in `cross-build/wasm32-wasi`.
315+
316+
The easiest way to do a build is to use the `wasi.py` script. You can either have it perform the entire build process from start to finish in one step, or you can do it in discrete steps that mirror running `configure` and `make` for each of the two builds of Python you end up producing (which are beneficial when you only need to do a specific step after getting a complete build, e.g. editing some code and you just need to run `make` for the WASI build).
317+
318+
The discrete steps are:
313319
```shell
314-
./Tools/wasm/wasm_build.py wasi build
320+
python Tools/wasm/wasi.py configure-build-python
321+
python Tools/wasm/wasi.py make-build-python
322+
python Tools/wasm/wasi.py configure-host
323+
python Tools/wasm/wasi.py make-host
315324
```
316325

317-
or:
326+
To do it in a single command, run:
318327
```shell
319-
./Tools/wasm/build_wasi.sh
328+
python Tools/wasm/wasi.py build
320329
```
321330

322-
The commands are equivalent to the following steps:
323-
324-
- Make sure `Modules/Setup.local` exists
325-
- Make sure the necessary build tools are installed:
326-
- [WASI SDK](https://github.com/WebAssembly/wasi-sdk) (which ships with `clang`)
327-
- `make`
328-
- `pkg-config` (on Linux)
329-
- Create the build Python
330-
- `mkdir -p builddir/build`
331-
- `pushd builddir/build`
332-
- Get the build platform
333-
- Python: `sysconfig.get_config_var("BUILD_GNU_TYPE")`
334-
- Shell: `../../config.guess`
335-
- `../../configure -C`
336-
- `make all`
337-
- ```PYTHON_VERSION=`./python -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")'` ```
338-
- `popd`
339-
- Create the host/WASI Python
340-
- `mkdir builddir/wasi`
341-
- `pushd builddir/wasi`
342-
- `../../Tools/wasm/wasi-env ../../configure -C --host=wasm32-unknown-wasi --build=$(../../config.guess) --with-build-python=../build/python`
343-
- `CONFIG_SITE=../../Tools/wasm/config.site-wasm32-wasi`
344-
- `HOSTRUNNER="wasmtime run --mapdir /::$(dirname $(dirname $(pwd))) --env PYTHONPATH=/builddir/wasi/build/lib.wasi-wasm32-$PYTHON_VERSION $(pwd)/python.wasm --"`
345-
- Maps the source checkout to `/` in the WASI runtime
346-
- Stdlib gets loaded from `/Lib`
347-
- Gets `_sysconfigdata__wasi_wasm32-wasi.py` on to `sys.path` via `PYTHONPATH`
348-
- Set by `wasi-env`
349-
- `WASI_SDK_PATH`
350-
- `WASI_SYSROOT`
351-
- `CC`
352-
- `CPP`
353-
- `CXX`
354-
- `LDSHARED`
355-
- `AR`
356-
- `RANLIB`
357-
- `CFLAGS`
358-
- `LDFLAGS`
359-
- `PKG_CONFIG_PATH`
360-
- `PKG_CONFIG_LIBDIR`
361-
- `PKG_CONFIG_SYSROOT_DIR`
362-
- `PATH`
363-
- `make all`
364-
331+
That will:
365332

366-
### Running
367-
368-
If you followed the instructions above, you can run the interpreter via e.g., `wasmtime` from within the `Tools/wasi` directory (make sure to set/change `$PYTHON_VERSION` and do note the paths are relative to running in`builddir/wasi` for simplicity only):
333+
1. Run `configure` for the build Python (same as `wasi.py configure-build-python`)
334+
2. Run `make` for the build Python (`wasi.py make-build-python`)
335+
3. Run `configure` for the WASI build (`wasi.py configure-host`)
336+
4. Run `make` for the WASI build (`wasi.py make-host`)
369337

338+
See the `--help` for the various options available for each of the subcommands which controls things like the location of the WASI SDK, the command to use with the WASI host/runtime, etc. Also note that you can use `--` as a separtor for any of the `configure`-related commands -- including `build` -- to pass arguments to `configure` itself. For example, if you want a pydebug build that also caches the results from `configure`, you can do:
370339
```shell
371-
wasmtime run --mapdir /::../.. --env PYTHONPATH=/builddir/wasi/build/lib.wasi-wasm32-$PYTHON_VERSION python.wasm -- <args>
340+
python Tools/wasm/wasi.py build -- -C --with-pydebug
372341
```
373342

374-
There are also helpers provided by `Tools/wasm/wasm_build.py` as listed below. Also, if you used `Tools/wasm/build_wasi.sh`, a `run_wasi.sh` file will be created in `builddir/wasi` which will run the above command for you (it also uses absolute paths, so it can be executed from anywhere).
375-
376-
#### REPL
377-
343+
The `wasi.py` script is able to infer details from the build Python, and so you only technically need to specify `--with-pydebug` once for `configure-build-python` and `configure-host` will detect its use if you use the discrete steps:
378344
```shell
379-
./Tools/wasm/wasm_build.py wasi repl
345+
python Tools/wasm/wasi.py configure-build-python -- -C --with-pydebug
346+
python Tools/wasm/wasi.py make-build-python
347+
python Tools/wasm/wasi.py configure-host -- -C
348+
python Tools/wasm/wasi.py make-host
380349
```
381350

382-
#### Tests
383351

352+
### Running
353+
354+
If you used `wasi.py` to do your build then there will be a `cross-build/wasm32-wasi/python.sh` file which you can use to run the `python.wasm` file (see the output from the `configure-host` subcommand):
384355
```shell
385-
./Tools/wasm/wasm_build.py wasi test
356+
cross-build/wasm32-wasi/python.sh --version
386357
```
387358

388-
### Debugging
359+
While you _can_ run `python.wasm` directly, Python will fail to start up without certain things being set (e.g. `PYTHONPATH` for `sysconfig` data). As such, the `python.sh` file records these details for you.
389360

390-
* ``wasmtime run -g`` generates debugging symbols for gdb and lldb. The
391-
feature is currently broken, see
392-
https://github.com/bytecodealliance/wasmtime/issues/4669 .
393-
* The environment variable ``RUST_LOG=wasi_common`` enables debug and
394-
trace logging.
395361

396362
## Detect WebAssembly builds
397363

@@ -402,15 +368,17 @@ import os, sys
402368

403369
if sys.platform == "emscripten":
404370
# Python on Emscripten
371+
...
405372
if sys.platform == "wasi":
406373
# Python on WASI
374+
...
407375

408376
if os.name == "posix":
409377
# WASM platforms identify as POSIX-like.
410378
# Windows does not provide os.uname().
411379
machine = os.uname().machine
412380
if machine.startswith("wasm"):
413-
# WebAssembly (wasm32, wasm64 in the future)
381+
# WebAssembly (wasm32, wasm64 potentially in the future)
414382
```
415383

416384
```python

Tools/wasm/mypy.ini

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[mypy]
2-
files = Tools/wasm
2+
files = Tools/wasm/wasm_*.py
33
pretty = True
44
show_traceback = True
55

@@ -9,6 +9,3 @@ python_version = 3.8
99
# Be strict...
1010
strict = True
1111
enable_error_code = truthy-bool,ignore-without-code
12-
13-
# except for incomplete defs, which are useful for module authors:
14-
disallow_incomplete_defs = False

0 commit comments

Comments
 (0)