avr-toolchain-wasi
The AVR toolchain as WebAssembly. avr-as, avr-ld, avr-objcopy, cc1 and
cc1plus built for wasm32-wasip1 and driven from Python through
wasmtime — one architecture-independent wheel instead
of a native build per platform.
pip install pymcu-avr-toolchain-wasi
Built for PyMCU, which compiles Python to native microcontroller code.
Why
Shipping a native toolchain means building and maintaining it for every platform
a user might have. In practice that is where the time goes, and none of it is
the compiler's fault: Rosetta 2 missing on a new Mac, MSYS2's config.guess
making a native build look like a cross, uname -m saying x86_64 while
file says x86-64, GCC 14 sources refusing to compile against a 2026
libstdc++. Six consecutive failed attempts on Windows alone.
The same modules run everywhere wasmtime does. That class of problem disappears.
| native, per platform | this | |
|---|---|---|
| Artifacts to build | 5 | 0 |
| Wheel | 70.7 MB | 22.9 MB |
| Installed | 226 MB | 105 MB |
| Platforms | 5, each verified separately | anywhere wasmtime runs |
It is also faster in real use — 0.27 s against 0.51 s for 53 builds — because
the module is compiled once and each build is a fresh instance, with no
fork/exec per tool.
Verified, not assumed
Every firmware is compared to the native toolchain's output by sha256, not by whether the build succeeded:
Linux x86_64 plain 53/53 FFI 6/6 TOTAL 59/59
Linux aarch64 plain 53/53 FFI 6/6 TOTAL 59/59
macOS arm64 plain 53/53 FFI 6/6 TOTAL 59/59
Windows AMD64 plain 53/53 FFI 6/6 TOTAL 59/59
Windows ARM64 plain 53/53 FFI 6/6 TOTAL 59/59
The same five modules on all five runners. The FFI cases cover @extern with C
sources and one C++ case (class, method, template, extern "C"). Also verified
across 20 chips and the five library subdirectories, and against binutils 2.45.1
and a libgcc from GCC 9.5.0 — neither changes a byte of firmware.
macOS Intel is not verified. GitHub retired the macos-13 runner, so there
is nowhere to measure it. wasmtime publishes a macosx_10_13_x86_64 wheel, so
there is reason to expect it works, but that is an expectation and not a
measurement.
How it works
WASI has no fork/exec, so the GCC driver cannot be ported — it is replaced.
The exact command line each tool needs is taken from avr-gcc -### rather than
reconstructed by hand, and tabulated per chip:
avr-as -mmcu=<chip> -mno-skip-bug firmware.asm -o firmware.o
avr-ld -m <emulation> -Tdata 0x<800000+RAMSTART> --relax firmware.o
-L<libgcc/libdir> -L<avr/lib/libdir> --start-group -lgcc -lm --end-group
objcopy -O ihex -R .eeprom firmware.elf firmware.hex
Deriving those tables from the compiler instead of from the chip's name is not pedantry. It caught three defects that would have produced broken firmware silently:
atmega1280isavr51, notavr6as the family name suggests.attiny13,13a,24,25and2313areavr25for the linker but must link againstavr25/tiny-stack, the 8-bit stack pointer variant. The wrong one emits code that writesSPHon parts that have noSPH.- A hand-maintained chip list had drifted from the one the product supports. The table is now generated from PyMCU's own chip directory, so it cannot.
Building
The modules are built in a container and the recipe is reproducible:
docker build --output type=local,dest=./dist-docker -f Dockerfile . # as/ld/objcopy
docker build --output type=local,dest=./dist-ffi -f Dockerfile.cc1 . # cc1/cc1plus
What is reproducible is the firmware: modules built on macOS and in the
container differ in size yet produce identical .hex. Bit-identical modules
across build hosts is a separate problem and is not claimed here.
Build products, SDKs and caches are deliberately absent from this repository — CI assembles the wheel from the verified payload attached to each release, so what reaches PyPI is what was measured, not a rebuild nobody checked.
Harnesses
python difftest.py # 53 plain examples, native vs wasi
python ffi_difftest.py # the FFI path
python chip_difftest.py # 20 chips across 5 library subdirectories
python driver_difftest.py # through PyMCU's own driver
Limits
- Programmers stay native.
avrdudetalks to a serial port; WASI does not. - C++ with global constructors does not link, and does not link natively
either: it emits
__do_global_ctorsand__do_clear_bss, which PyMCU's-nostartfileslink and its own linker script do not provide. That is a linker-script matter, not a toolchain one. - Roughly 2× slower than native on inputs of megabytes — far above anything that fits in an AVR.
Licence
GPL-3.0-or-later, as the GNU toolchain it is built from.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pymcu_avr_toolchain_wasi-15.2.0.post1-py3-none-any.whl.
File metadata
- Download URL: pymcu_avr_toolchain_wasi-15.2.0.post1-py3-none-any.whl
- Upload date:
- Size: 24.0 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
59d9bd27e0eaa23770a6392499fd560cf32faf4becc4a0b9dbc24b4b07badb69
|
|
| MD5 |
32928a7593637debcac0d38bfed54637
|
|
| BLAKE2b-256 |
b7b2885f287c6d9a694ec40681e08d0140f603cf0b0831097a00141134ef032a
|
Provenance
The following attestation bundles were made for pymcu_avr_toolchain_wasi-15.2.0.post1-py3-none-any.whl:
Publisher:
publish.yml on PyMCU/avr-toolchain-wasi
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pymcu_avr_toolchain_wasi-15.2.0.post1-py3-none-any.whl -
Subject digest:
59d9bd27e0eaa23770a6392499fd560cf32faf4becc4a0b9dbc24b4b07badb69 - Sigstore transparency entry: 2493852297
- Sigstore integration time:
-
Permalink:
PyMCU/avr-toolchain-wasi@1062b05a6c843fdcfdd607641fb34f1813aa6d8e -
Branch / Tag:
refs/tags/v15.2.0.post1 - Owner: https://github.com/PyMCU
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@1062b05a6c843fdcfdd607641fb34f1813aa6d8e -
Trigger Event:
push
-
Statement type: