Skip to content

GH-103065, GH-106704, GH-105253: Provide a Tools/wasm/wasi.py script to simplify doing a WASI build #112473

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 51 commits into from
Nov 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
a4e6f9b
Set up minimal arg parsing
brettcannon Sep 27, 2023
f1be30a
Get the WASI build working
brettcannon Sep 28, 2023
7031bce
Create a `python.sh` command
brettcannon Oct 3, 2023
3db2388
Switch to `os.process_cpu_count()`
brettcannon Oct 3, 2023
238eed1
Tweak some formatting
brettcannon Oct 4, 2023
01319de
Add a `--skip-build-python` flag
brettcannon Oct 4, 2023
0120446
Add a `--quiet` flag
brettcannon Oct 4, 2023
4642afe
Add `SOURCE_DATE_EPOCH`
brettcannon Oct 5, 2023
705f746
Add `--debug`
brettcannon Oct 5, 2023
134e6b4
Fix a bug related to passing a `pathlib.Path` to `section()`
brettcannon Oct 6, 2023
7851a4d
Merge branch 'main' of https://github.com/python/cpython into wasi.py
brettcannon Oct 6, 2023
95029ee
Rename `--debug` to `--with-pydebug`
brettcannon Oct 6, 2023
8717974
Get everything working with a pydebug build
brettcannon Oct 6, 2023
d66fd8b
Support macOS
brettcannon Oct 17, 2023
b21d59a
Add a verification check for the `python.sh` file
brettcannon Oct 18, 2023
a14348e
Allow for `HOST_RUNNER` to be specified as a CLI option
brettcannon Oct 27, 2023
57f56fa
Turn on thread support for the default host runner
brettcannon Nov 3, 2023
94851f6
Add threaded build support
brettcannon Nov 3, 2023
0eb8435
Merge branch 'main' into wasi.py
brettcannon Nov 7, 2023
7060516
Check if the expected sysconfig directory was created
brettcannon Nov 7, 2023
347d5c0
Do a better job of deleting build directories when run with `--clean`
brettcannon Nov 7, 2023
0aa5599
Make the check for the sysconfig build directory use an absolute path
brettcannon Nov 8, 2023
97ff44a
Merge branch 'main' of https://github.com/python/cpython into wasi.py
brettcannon Nov 16, 2023
082e976
Merge branch 'main' of https://github.com/python/cpython into wasi.py
brettcannon Nov 16, 2023
cfefcf0
Merge branch 'main' of https://github.com/python/cpython into wasi.py
brettcannon Nov 16, 2023
b1268ce
Switch to `--platform` from `--skip-build-python`
brettcannon Nov 16, 2023
31cc023
Merge branch 'main' of https://github.com/python/cpython into wasi.py
brettcannon Nov 16, 2023
c3539c1
Add the `configure-build-python` and `make-build-python` subcommands
brettcannon Nov 22, 2023
2a6c541
Create a decorator to handle some boilerplate
brettcannon Nov 22, 2023
c7dcc95
Don't accidentally delete the checkout
brettcannon Nov 22, 2023
19cbc6e
Add back in the `section()` call to `prep_checkout()`
brettcannon Nov 22, 2023
12a7886
Make automatic cleaning an opt-in experience
brettcannon Nov 22, 2023
57b1ea0
Merge remote-tracking branch 'upstream/main' into wasi.py
brettcannon Nov 22, 2023
eb90cbc
Merge branch 'main' of https://github.com/python/cpython into wasi.py
brettcannon Nov 22, 2023
0f7494c
Merge branch 'main' of https://github.com/python/cpython into wasi.py
brettcannon Nov 22, 2023
62b2da8
Clobber `cross-build`
brettcannon Nov 22, 2023
7893385
Add `configure-host`
brettcannon Nov 23, 2023
9994841
Re-implement `build` in terms of all the other subcommands
brettcannon Nov 23, 2023
d975c47
Touch up formatting
brettcannon Nov 24, 2023
27702ca
Update README
brettcannon Nov 24, 2023
c8cbd7a
Set `SOURCE_DATE_EPOCH` based on `git log -1 --pretty=%ct`
brettcannon Nov 27, 2023
e6d947a
Flesh out the README
brettcannon Nov 27, 2023
e160baf
Some more README flourishes
brettcannon Nov 27, 2023
37619db
Add a news entry
brettcannon Nov 27, 2023
3505077
Merge branch 'main' into wasi.py
brettcannon Nov 27, 2023
5b01cbe
Skip mypy checks
brettcannon Nov 27, 2023
ad0a83c
Merge branch 'wasi.py' of https://github.com/brettcannon/cpython into…
brettcannon Nov 27, 2023
71946e7
Fix an over-indentation
brettcannon Nov 27, 2023
bd488b2
Only set `SOURCE_DATE_EPOCH` if it has not already been set
brettcannon Nov 27, 2023
547ba0f
Simplify some code
brettcannon Nov 28, 2023
dea525e
Bump the version of wasmtime installed into the dev container
brettcannon Nov 28, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ ENV WASI_SDK_VERSION=20
ENV WASI_SDK_PATH=/opt/wasi-sdk

ENV WASMTIME_HOME=/opt/wasmtime
ENV WASMTIME_VERSION=9.0.1
ENV WASMTIME_VERSION=14.0.4
ENV WASMTIME_CPU_ARCH=x86_64

RUN dnf -y --nodocs --setopt=install_weak_deps=False install /usr/bin/{blurb,clang,curl,git,ln,tar,xz} 'dnf-command(builddep)' && \
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ Tools/unicode/data/
/config.status.lineno
# hendrikmuhs/ccache-action@v1
/.ccache
/cross-build/
/platform
/profile-clean-stamp
/profile-run-stamp
Expand Down
1 change: 1 addition & 0 deletions Makefile.pre.in
Original file line number Diff line number Diff line change
Expand Up @@ -2732,6 +2732,7 @@ clobber: clean
-rm -rf build platform
-rm -rf $(PYTHONFRAMEWORKDIR)
-rm -f python-config.py python-config
-rm -rf cross-build

# Make things extra clean, before making a distribution:
# remove all generated files, even Makefile[.pre]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Introduce ``Tools/wasm/wasi.py`` to simplify doing a WASI build.
112 changes: 40 additions & 72 deletions Tools/wasm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,100 +298,66 @@ AddType application/wasm wasm

## WASI (wasm32-wasi)

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

### Build
### Prerequisites

Developing for WASI requires two things to be installed:

1. The [WASI SDK](https://github.com/WebAssembly/wasi-sdk) 16.0+
(see `.devcontainer/Dockerfile` for an example of how to download and install the WASI SDK)
2. A WASI host/runtime ([wasmtime](https://wasmtime.dev) 14+ is recommended and what the instructions below assume)

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

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

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`.

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).

The discrete steps are:
```shell
./Tools/wasm/wasm_build.py wasi build
python Tools/wasm/wasi.py configure-build-python
python Tools/wasm/wasi.py make-build-python
python Tools/wasm/wasi.py configure-host
python Tools/wasm/wasi.py make-host
```

or:
To do it in a single command, run:
```shell
./Tools/wasm/build_wasi.sh
python Tools/wasm/wasi.py build
```

The commands are equivalent to the following steps:

- Make sure `Modules/Setup.local` exists
- Make sure the necessary build tools are installed:
- [WASI SDK](https://github.com/WebAssembly/wasi-sdk) (which ships with `clang`)
- `make`
- `pkg-config` (on Linux)
- Create the build Python
- `mkdir -p builddir/build`
- `pushd builddir/build`
- Get the build platform
- Python: `sysconfig.get_config_var("BUILD_GNU_TYPE")`
- Shell: `../../config.guess`
- `../../configure -C`
- `make all`
- ```PYTHON_VERSION=`./python -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")'` ```
- `popd`
- Create the host/WASI Python
- `mkdir builddir/wasi`
- `pushd builddir/wasi`
- `../../Tools/wasm/wasi-env ../../configure -C --host=wasm32-unknown-wasi --build=$(../../config.guess) --with-build-python=../build/python`
- `CONFIG_SITE=../../Tools/wasm/config.site-wasm32-wasi`
- `HOSTRUNNER="wasmtime run --mapdir /::$(dirname $(dirname $(pwd))) --env PYTHONPATH=/builddir/wasi/build/lib.wasi-wasm32-$PYTHON_VERSION $(pwd)/python.wasm --"`
- Maps the source checkout to `/` in the WASI runtime
- Stdlib gets loaded from `/Lib`
- Gets `_sysconfigdata__wasi_wasm32-wasi.py` on to `sys.path` via `PYTHONPATH`
- Set by `wasi-env`
- `WASI_SDK_PATH`
- `WASI_SYSROOT`
- `CC`
- `CPP`
- `CXX`
- `LDSHARED`
- `AR`
- `RANLIB`
- `CFLAGS`
- `LDFLAGS`
- `PKG_CONFIG_PATH`
- `PKG_CONFIG_LIBDIR`
- `PKG_CONFIG_SYSROOT_DIR`
- `PATH`
- `make all`

That will:

### Running

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):
1. Run `configure` for the build Python (same as `wasi.py configure-build-python`)
2. Run `make` for the build Python (`wasi.py make-build-python`)
3. Run `configure` for the WASI build (`wasi.py configure-host`)
4. Run `make` for the WASI build (`wasi.py make-host`)

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:
```shell
wasmtime run --mapdir /::../.. --env PYTHONPATH=/builddir/wasi/build/lib.wasi-wasm32-$PYTHON_VERSION python.wasm -- <args>
python Tools/wasm/wasi.py build -- -C --with-pydebug
```

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).

#### REPL

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:
```shell
./Tools/wasm/wasm_build.py wasi repl
python Tools/wasm/wasi.py configure-build-python -- -C --with-pydebug
python Tools/wasm/wasi.py make-build-python
python Tools/wasm/wasi.py configure-host -- -C
python Tools/wasm/wasi.py make-host
```

#### Tests

### Running

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):
```shell
./Tools/wasm/wasm_build.py wasi test
cross-build/wasm32-wasi/python.sh --version
```

### Debugging
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.

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

## Detect WebAssembly builds

Expand All @@ -402,15 +368,17 @@ 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 in the future)
# WebAssembly (wasm32, wasm64 potentially in the future)
```

```python
Expand Down
5 changes: 1 addition & 4 deletions Tools/wasm/mypy.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[mypy]
files = Tools/wasm
files = Tools/wasm/wasm_*.py
pretty = True
show_traceback = True

Expand All @@ -9,6 +9,3 @@ python_version = 3.8
# Be strict...
strict = True
enable_error_code = truthy-bool,ignore-without-code

# except for incomplete defs, which are useful for module authors:
disallow_incomplete_defs = False
Loading