Skip to content

Commit fa78f51

Browse files
committed
PEP tbd: Emscripten packaging
1 parent 993df23 commit fa78f51

File tree

1 file changed

+190
-0
lines changed

1 file changed

+190
-0
lines changed

peps/pep-tbd.rst

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
PEP: tbd
2+
Title: Emscripten Packaging
3+
Author: Hood Chatham <roberthoodchatham at gmail.com>
4+
Sponsor: Łukasz Langa <lukasz at python.org>
5+
Discussions-To:
6+
Status: Draft
7+
Type: Standards Track
8+
Topic: Packaging
9+
Created: 28-Mar-2025
10+
Python-Version: 3.14
11+
Post-History:
12+
13+
Abstract
14+
========
15+
16+
This PEP proposes a new platform tag series `pyodide` for binary Python package
17+
distributions for the Pyodide Python runtime.
18+
19+
`Emscripten <https://emscripten.org/>`__ is a complete open source compiler
20+
toolchain. It compiles C/C++ code into WebAssembly/JavaScript executables, for
21+
use in JavaScript runtimes, including browsers and Node.js. The Rust language
22+
also maintains an Emscripten target.
23+
24+
The goals of this PEP are:
25+
26+
1. To describe Pyodide's packaging tooling
27+
2. To describe Pyodide's wheel abi to a similar level of detail as the manylinux
28+
PEPs
29+
3. For Pyodide wheels to be allowed for upload to PyPI
30+
31+
32+
33+
Motivation
34+
==========
35+
36+
Pyodide is a CPython distribution for use in the browser. A web browser is a
37+
universal computing platform, available on Windows, macOS, Linux, and every
38+
smartphone. Hundreds of thousands of students have learned Python through
39+
Pyodide via projects like `Capytale
40+
<https://web.archive.org/web/20241211090946/https://cfp.jupytercon.com/2023/talk/TJ9YEV/>`__
41+
and `PyodideU <https://stanford.edu/~cpiech/bio/papers/pyodideU.pdf>`__. Pyodide
42+
is also increasingly being used by Python packages to provide interactive
43+
documentation.
44+
45+
Pyodide currently maintains ports of 255 different packages at the time of this
46+
writing, including major scientific Python packages like NumPy, SciPy, pandas,
47+
Polars, scikit-learn, OpenCV, PyArrow, and Pillow as well as general purpose
48+
packages like aiohttp, Requests, Pydantic, cryptography, and orjson.
49+
50+
About 60 packages are also testing against Pyodide in their CI, including NumPy,
51+
pandas, awkward-cpp, scikit-image, statsmodels, PyArrow, Hypothesis, and PyO3.
52+
53+
Python package projects cannot deploy binary distributions for Pyodide on PyPI.
54+
Instead they must use other options like ``anaconda.org`` or ``jsdelivr.com``.
55+
This creates friction both for package maintainers and for users.
56+
57+
58+
Rationale
59+
=========
60+
61+
Emscripten uses a variant of musl libc. The Emscripten compiler makes no ABI
62+
stability guarantees between versions. Many Emscripten updates are ABI
63+
compatible by chance, and the Rust Emscripten target behaves as if the ABI were
64+
stable with only `occasional negative consequences
65+
<https://github.com/rust-lang/rust/issues/131467>`__.
66+
67+
There are several linker flags that adjust the Emscripten ABI, so Python
68+
packages built to run with Emscripten must make sure to match the ABI-sensitive
69+
linker flags used to compile the interpreter to avoid load-time or run-time
70+
errors. The Emscripten compiler continuously fixes bugs and adds support for new
71+
web platform features. Thus, there is significant benefit to being able to
72+
update the ABI.
73+
74+
In order to balance the ABI stability needs of package maintainers with the ABI
75+
flexibility to allow the platform to move forward, Pyodide plans to adopt a new
76+
ABI for each feature release of Python.
77+
78+
The Pyodide team also coordinates the ABI flags that Pyodide uses with the
79+
Emscripten ABI that Rust supports in order to ensure that we have support for
80+
the many popular Rust packages. Historically, most of the work for this has
81+
been related to unwinding ABIs. See for instance `this Rust Major Change
82+
Proposal <https://github.com/rust-lang/compiler-team/issues/801>`__.
83+
84+
The ``pyodide`` platform tags only apply to Python interpreters compiled and
85+
linked with the same version of Emscripten as Pyodide, with the same
86+
ABI-sensitive flags.
87+
88+
89+
Specification
90+
=============
91+
92+
The platform tags will take the form::
93+
94+
pyodide_${YEAR}_${PATCH}_wasm32
95+
96+
Each one of these will be used with a specified Python version. For example, the
97+
platform tag `pyodide_2025_0` will be used with Python 3.13.
98+
99+
Emscripten Wheel ABI
100+
--------------------
101+
102+
The specification of the ``pyodide_<abi>`` platform includes:
103+
104+
* Which version of the Emscripten compiler is used
105+
* What libraries are statically linked with the interpreter
106+
* What stack unwinding ABI is to be used
107+
* Which runtime platform features are required to be present
108+
109+
and a handful of other similar details that affect the ABI.
110+
111+
The ABI is selected by choosing the appropriate version of the Emscripten
112+
compiler and passing appropriate compiler and linker flags. It is possible for
113+
other people to build their own Python interpreter that is compatible with the
114+
Pyodide ABI, it is not necessary to use the Pyodide distribution itself.
115+
116+
The ``pyodide build`` tool knows how to create wheels that match our ABI. Unlike
117+
with manylinux wheels, there is no need for a Docker container to build the
118+
``pyodide_<abi>`` wheels. All that is needed is a Linux machine and appropriate
119+
versions of Python, Node.js, and Emscripten.
120+
121+
It is possible to validate a wheel by installing and importing it into the
122+
Pyodide runtime. Because Pyodide can run in an environment with strong
123+
sandboxing guarantees, doing this produces no security risks.
124+
125+
Determining the ABI version
126+
---------------------------
127+
128+
The Pyodide ABI version is stored in the `PYODIDE_ABI_VERSION` config variable
129+
and can be determined via::
130+
131+
pyodide_abi_version = sysconfig.get_config_var("PYODIDE_ABI_VERSION")
132+
133+
134+
To generate the list of compatible tags, one can use the following code::
135+
136+
from packaging.tags import cpython_tags, _generic_platforms
137+
138+
def _emscripten_platforms() -> Iterator[str]:
139+
pyodide_abi_version = sysconfig.get_config_var("PYODIDE_ABI_VERSION")
140+
if pyodide_abi_version:
141+
yield f"pyodide_{pyodide_abi_version}_wasm32"
142+
yield from _generic_platforms()
143+
144+
emscripten_tags = cpython_tags(platforms=_emscripten_platforms())
145+
146+
This code will be added to `pypa/packaging
147+
<https://github.com/pypa/packaging/pull/804>`__.
148+
149+
150+
Package Installers
151+
------------------
152+
153+
Installers should use the ``_emscripten_platforms()`` function shown above to
154+
determine which platforms are compatible with an Emscripten build of CPython. In
155+
particular, the Pyodide ABI version is exposed via
156+
``sysconfig.get_config_var("PYODIDE_ABI_VERSION")``.
157+
158+
Package indexes
159+
---------------
160+
161+
We recommend that package indexes accept any wheel whose platform tag matches
162+
``pyodide_[0-9]+_[0-9]+_wasm32``.
163+
164+
165+
Dependency Specifier Markers
166+
----------------------------
167+
168+
To check for the Emscripten platform in a dependency specifier, one can use
169+
``sys_platform == 'emscripten'`` (or its negation).
170+
171+
172+
Trove Classifier
173+
----------------
174+
175+
Packages that build and test Emscripten wheels can declare this by adding the
176+
``Environment :: WebAssembly :: Emscripten``. PyPI already accepts uploads of
177+
packages with this classifier.
178+
179+
180+
Backwards Compatibility
181+
=======================
182+
183+
There are no backwards compatibility concerns in this PEP.
184+
185+
186+
Copyright
187+
=========
188+
189+
This document is placed in the public domain or under the
190+
CC0-1.0-Universal license, whichever is more permissive.

0 commit comments

Comments
 (0)