# PEP 783: Emscripten Packaging

**URL:** <https://discuss.python.org/t/pep-783-emscripten-packaging/86862>\
**Category:** PEPs\
**Created:** [April 2, 2025, 4:43pm UTC](https://discuss.python.org/t/pep-783-emscripten-packaging/86862 "2025-04-02T16:43:36Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![hoodmane](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/hoodmane/32/4037_2.png) [@hoodmane](https://discuss.python.org/u/hoodmane)\
**Post date:** [April 2, 2025, 4:43pm UTC](https://discuss.python.org/t/pep-783-emscripten-packaging/86862/1 "2025-04-02T16:43:36Z")

</div>

This is a discussion thread on PEP 783. The rendered pep is [here](https://peps.python.org/pep-0783/). Please let me know what you think.

---

<div class="post-metadata">

**Author:** ![hoodmane](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/hoodmane/32/4037_2.png) [@hoodmane](https://discuss.python.org/u/hoodmane)\
**Post date:** [April 7, 2025, 10:40am UTC](https://discuss.python.org/t/pep-783-emscripten-packaging/86862/2 "2025-04-07T10:40:26Z")

</div>

@pf_moore I would appreciate your comments when you have a chance. The main changes are:

- split out from PEP 776
- an exhaustive list of what decisions go into the ABI
- a reference to a new page in Pyodide’s documentation which specifies the ABI:  
[Pyodide Platform ABI](https://pyodide.org/en/stable/development/abi.html)

---

<div class="post-metadata">

**Author:** ![pf\_moore](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pf_moore/32/35_2.png) [@pf\_moore](https://discuss.python.org/u/pf_moore)\
**Post date:** [April 7, 2025, 10:53am UTC](https://discuss.python.org/t/pep-783-emscripten-packaging/86862/3 "2025-04-07T10:53:30Z")

</div>

I don’t really have much to say. The only thing that confuses me is, if pyodide ties the platform tag to the Python version, why have separate tags? For instance, if (as the PEP says) `pyodide_2025_0` is used for Python 3.13, what’s the point of allowing for `pyodide_2025_1`, given that there’s only one Python version released per year? Actually, why is 3.13 using a 2025 tag, given that 3.13 was released in 2024?

I don’t think the above comment actually matters in practice, as the rules for calculating tags are explicit (and easily translated for non-Python implementations like uv). I just found it confusing.

I’ll let tool authors (especially build backend authors) comment on the PEP beyond this.

---

<div class="post-metadata">

**Author:** ![hoodmane](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/hoodmane/32/4037_2.png) [@hoodmane](https://discuss.python.org/u/hoodmane)\
**Post date:** [April 7, 2025, 11:10am UTC](https://discuss.python.org/t/pep-783-emscripten-packaging/86862/4 "2025-04-07T11:10:27Z")

</div>

> if pyodide ties the platform tag to the Python version, why have separate tags?

If you are suggesting to just call them all `pyodide`, it would work for something like `numpy-2.0.2-cp312-cp312-pyodide_wasm32.whl` but not for abi3 wheels where the platform is important e.g., `cryptography-44.0.2-cp37-abi3-pyodide_2025_0_wasm32.whl`. It would be an option to reject abi3 wheels though.

On the flipside, once things settle down upstream, this leaves us the possibility of using the same ABI for more than one year.

> what’s the point of allowing for `pyodide_2025_1` , given that there’s only one Python version released per year?

The thought here is that it provides an emergency escape valve if there is a completely intolerable toolchain issue that makes building prohibitive for downstream users, or a major bug with the runtime implementation of the ABI. Of course we would strongly prioritize fixing the toolchains/runtimes over breaking the ABI. Nothing like this has happened to us _yet_ but the ecosystem is sufficiently immature that we worry about it.

> why is 3.13 using a 2025 tag, given that 3.13 was released in 2024?

Currently we are waiting 6 months after the release of a new Python version to bring it into Pyodide. So the Pyodide stable branch is still using Python 3.12, whereas the main branch is now on 3.13. We do this because we also build and test 265 packages in tree, and even now a couple of them don’t yet build on Python 3.13.

This of course has significant downsides, and we are working on separating our package builds from our runtime so we can switch to releasing them separately. We had just had a discussion about this which I’ve put [here](https://github.com/pyodide/pyodide/issues/5580).

---

<div class="post-metadata">

**Author:** ![hoodmane](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/hoodmane/32/4037_2.png) [@hoodmane](https://discuss.python.org/u/hoodmane)\
**Post date:** [April 7, 2025, 11:23am UTC](https://discuss.python.org/t/pep-783-emscripten-packaging/86862/5 "2025-04-07T11:23:27Z")

</div>

> especially build backend authors

I guess I’ll try summoning some build backend authors directly.

scikit-build-core - @henryiii  
pyo3 - @messense @davidhewitt  
meson-python - @rgommers @FFY00  
setuptools - @jaraco @dstufft

I would very much appreciate any comments any of you have on the pep.

---

<div class="post-metadata">

**Author:** ![pf\_moore](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pf_moore/32/35_2.png) [@pf\_moore](https://discuss.python.org/u/pf_moore)\
**Post date:** [April 7, 2025, 12:03pm UTC](https://discuss.python.org/t/pep-783-emscripten-packaging/86862/6 "2025-04-07T12:03:33Z")

</div>

setuptools also - @abravalheri

---

<div class="post-metadata">

**Author:** ![oscarbenjamin](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/oscarbenjamin/32/1209_2.png) [@oscarbenjamin](https://discuss.python.org/u/oscarbenjamin)\
**Post date:** [April 7, 2025, 1:15pm UTC](https://discuss.python.org/t/pep-783-emscripten-packaging/86862/7 "2025-04-07T13:15:50Z")

</div>

Currently pyodide ties a particular version of each Python library to a particular version of pyodide. If the expectation is that pyodide will use wheels from PyPI then this opens the question of how to select a version of the library and also what libraries should do about multiple pyodide versions. Is the expectation that libraries would upload multiple wheels for pyodide\_2025\_0, pyodide\_2025\_1, pyodide\_2026\_0 etc?

What should an installer do if the latest version of a PyPI package does not have an appropriate wheel for the given pyodide version? The current (often problematic) behaviour of `pip` is that it would try to build from the sdist rather than checking if older versions of the package have wheels (`--prefer-binary`). Building from sdist won’t work in pyodide I think because all extension modules are cross-built which is a bit different from other Python platforms.

The PEP refers generically to “package installers” but it is not clear whether there is any expectation that existing widely used installers such as pip would ever be used in pyodide. I assume that they are not expected to be used there since e.g. pip and uv only have CLI interfaces and pyodide cannot run CLI things (no subprocesses). Otherwise is this just referring to pyodide’s own version of pip, micropip etc?

---

<div class="post-metadata">

**Author:** ![pf\_moore](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pf_moore/32/35_2.png) [@pf\_moore](https://discuss.python.org/u/pf_moore)\
**Post date:** [April 7, 2025, 1:54pm UTC](https://discuss.python.org/t/pep-783-emscripten-packaging/86862/8 "2025-04-07T13:54:38Z")

</div>

> [@oscarbenjamin](#):
>
> Otherwise is this just referring to pyodide’s own version of pip, micropip etc?

If this isn’t impacting pip and uv, or “general installers” in the broader sense, then how is it an interoperability standard? If the bulk of the packaging workflow is handled by custom tools, what’s the advantage of locking everything into a standard? Sorry if this is a dumb question - I have no idea what micropip even is, and maybe my ignorance is showing 🙁

Is this purely about being able to publish wheels on PyPI (and maybe other indexes like Artifactory or devpi)?

---

<div class="post-metadata">

**Author:** ![hoodmane](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/hoodmane/32/4037_2.png) [@hoodmane](https://discuss.python.org/u/hoodmane)\
**Post date:** [April 7, 2025, 1:59pm UTC](https://discuss.python.org/t/pep-783-emscripten-packaging/86862/9 "2025-04-07T13:59:59Z")

</div>

> this opens the question of how to select a version of the library

Well if you use `pip` or `uv` or `micropip` as your installer, they have logic to do this. If you install from one of Pyodide’s lock files, Pyodide will always install the version present in the lock file.

> [@oscarbenjamin](#):
>
> Is the expectation that libraries would upload multiple wheels for pyodide\_2025\_0, pyodide\_2025\_1, pyodide\_2026\_0 etc?

Yes, though to be clear, it is our goal never to create a `2025_1` ABI. Any package that doesn’t do abi3 builds already has to upload one wheel per Python version, so it’s no worse for them. The only packages where this will be annoying is ones that use abi3.

> What should an installer do if the latest version of a PyPI package does not have an appropriate wheel for the given pyodide version?

It should fail. In Pyodide virtual environments we add a `pip.conf` file with:

```python
[install]
only-binary=:all:

```

If you remove this, pip will not be able to successfully build a binary wheel right now anyways. I think it’s unlikely that pip will want to support building for Pyodide in the future either.

> The PEP refers generically to “package installers” but it is not clear whether there is any expectation that existing widely used installers such as pip would ever be used in pyodide.

We are already using pip with Pyodide.

---

<div class="post-metadata">

**Author:** ![hoodmane](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/hoodmane/32/4037_2.png) [@hoodmane](https://discuss.python.org/u/hoodmane)\
**Post date:** [April 7, 2025, 2:01pm UTC](https://discuss.python.org/t/pep-783-emscripten-packaging/86862/10 "2025-04-07T14:01:18Z")

</div>

> [@pf\_moore](#):
>
> Is this purely about being able to publish wheels on PyPI (and maybe other indexes like Artifactory or devpi)?

It’s primarily about that yes. We can patch/configure pip to behave the way we want without much trouble but we have no way to deal with uploads. It appears that some people are just lying about the platform of their wheels to say that they are `py3-none-any`, but of course we would never encourage people to do this.

---

<div class="post-metadata">

**Author:** ![pf\_moore](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pf_moore/32/35_2.png) [@pf\_moore](https://discuss.python.org/u/pf_moore)\
**Post date:** [April 7, 2025, 2:06pm UTC](https://discuss.python.org/t/pep-783-emscripten-packaging/86862/11 "2025-04-07T14:06:40Z")

</div>

> [@hoodmane](#):
>
> If you remove this, pip will not be able to successfully build a binary wheel right now anyways. I think it’s unlikely that pip will want to support building for Pyodide in the future either.

Pip is completely agnostic over the matter of building for any given platform. It simply calls the build backend. Whether the build works is down to the build backend (which may require particular tools, like a C compiler, or an emscripten toolchain, to be present if it’s to succeed). Adding `only-binary=:all:` will prevent (for example) installing of pure Python packages that are shipped in source form only. That may be acceptable to you, but it’s not something that a standard can assume.

Just to be explicit here, I’m not against emscripten support, but I do think that trying to integrate two very different models of operation is probably a lot bigger task than just defining a packaging tag. So if all we are doing is defining a tag, we need to be very clear what that’s intended to achieve, and carefully scope the proposal to exclude problems we’re not expecting to solve.

---

<div class="post-metadata">

**Author:** ![hoodmane](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/hoodmane/32/4037_2.png) [@hoodmane](https://discuss.python.org/u/hoodmane)\
**Post date:** [April 7, 2025, 2:15pm UTC](https://discuss.python.org/t/pep-783-emscripten-packaging/86862/12 "2025-04-07T14:15:50Z")

</div>

> So if all we are doing is defining a tag, we need to be very clear what that’s intended to achieve, and carefully scope the proposal to exclude problems we’re not expecting to solve.

If we successfully define the platform tag and allow PyPI uploads, I would be very happy with that outcome. It is my main goal. In the long term, it might be nice to go further than that. Let’s discuss the other problems a bit and if we think we can’t/shouldn’t try to solve them now I am happy to declare them out of scope.

> Pip is completely agnostic over the matter of building for any given platform.

What’s weird about Pyodide is that we use existing build backends but have a custom build front end that takes care of cross builds. In particular, what needs to be done differently is hacking the sysconfigdata and platform information so that they report information about Emscripten and installation of cross-build dependencies. For example, if the package reports a dependency on numpy, we install a manylinux numpy and then replace the headers and static libraries with the headers and libraries from the numpy-emscripten wheel. We also put custom compiler wrappers on the path.

The build backend then can be completely unaware that it is building for Emscripten. Though some of the newer build backends use build systems like meson, cmake, or cargo that are capable of cross-builds and are choosing to explicitly support Emscripten.

---

<div class="post-metadata">

**Author:** ![hoodmane](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/hoodmane/32/4037_2.png) [@hoodmane](https://discuss.python.org/u/hoodmane)\
**Post date:** [April 7, 2025, 2:22pm UTC](https://discuss.python.org/t/pep-783-emscripten-packaging/86862/13 "2025-04-07T14:22:40Z")

</div>

These questions of “how should build systems approach cross-builds” and “how should installers approach cross-builds” will benefit from a joint effort with Android and iOS. @freakboy3742 and I are hoping to collaborate on this.

---

<div class="post-metadata">

**Author:** ![freakboy3742](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/freakboy3742/32/1273_2.png) [@freakboy3742](https://discuss.python.org/u/freakboy3742)\
**Post date:** [April 7, 2025, 2:38pm UTC](https://discuss.python.org/t/pep-783-emscripten-packaging/86862/14 "2025-04-07T14:38:00Z")

</div>

> [@hoodmane](#):
>
> “how should installers approach cross-builds” will benefit from a joint effort with Android and iOS. @freakboy3742 and I are hoping to collaborate on this.

Just chiming in to confirm that yes - this is a topic that I’m interested in, and I’m hoping to have a coherent proposal (or at least a summary of historical proposals and possible approaches) before PyCon US.

---

<div class="post-metadata">

**Author:** ![hoodmane](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/hoodmane/32/4037_2.png) [@hoodmane](https://discuss.python.org/u/hoodmane)\
**Post date:** [April 7, 2025, 2:44pm UTC](https://discuss.python.org/t/pep-783-emscripten-packaging/86862/15 "2025-04-07T14:44:47Z")

</div>

> [@pf\_moore](#):
>
> So if all we are doing is defining a tag, we need to be very clear what that’s intended to achieve, and carefully scope the proposal to exclude problems we’re not expecting to solve.

Can you clarify what needs to be done to define a tag and which problems you mean to exclude? I think defining a tag entails saying:

- What is the Pyodide platform and how would someone build a wheel compatible with it?
- How should an installer decide if a wheel is compatible with a target Pyodide platform?

I think I answered these things in the current pep text. And you seem to mean we should exclude:

- What should `pip`/some other installer do if someone asks it to install an Emscripten wheel from source?

I will update the PEP should be updated leave this unspecified and explicitly suggest that an acceptable and likely behavior is to fail in some way. We can furthermore recommend but not require that people always use `only-binary=:all:`.

Are there other things I’m missing here?

---

<div class="post-metadata">

**Author:** ![pf\_moore](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/pf_moore/32/35_2.png) [@pf\_moore](https://discuss.python.org/u/pf_moore)\
**Post date:** [April 7, 2025, 3:26pm UTC](https://discuss.python.org/t/pep-783-emscripten-packaging/86862/16 "2025-04-07T15:26:00Z")

</div>

> [@hoodmane](#):
>
> I will update the PEP should be updated leave this unspecified and explicitly suggest that an acceptable and likely behavior is to fail in some way. We can furthermore recommend but not require that people always use `only-binary=:all:`.

A minor technicality, but you don’t install a wheel from source. My point is that you install a sdist, and you do that by asking the build backend to generate a wheel. Whether the backend generates an emscripten-specific wheel or not is entirely down to the backend, and the frontend (pip, or whatever) has to be prepared for that. I just checked PEP 517, and there’s actually not even a requirement that I can see that the wheel generated by `build_wheel` is compatible with the target environment! But I think it’s fair to say that most frontends would expect to either get a compatible wheel or a failure.

I’m a strong -1 on having any suggestion of `only-binary=:all:` in the PEP. Apart from the fact that it’s not a standardised option, there are all sorts of edge cases that make such an approach incredibly fragile. I’ve already mentioned pure-python sdists, and there’s also cases like `--target` where the frontend could be building an environment for a platform other than the current one.

You also need to address @oscarbenjamin’s point - what if the latest version of a PyPI package doesn’t have a wheel for the required pyodide version? Is it OK to backtrack through all older versions looking for one? Are projects expected to ship wheels for _all_ pyodide versions? The manylinux spec avoids this by having systems be compatible with all older manylinux versions, as well as the latest version. That’s not how pyodide tags work, if I understand things correctly.

---

<div class="post-metadata">

**Author:** ![hoodmane](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/hoodmane/32/4037_2.png) [@hoodmane](https://discuss.python.org/u/hoodmane)\
**Post date:** [April 7, 2025, 3:45pm UTC](https://discuss.python.org/t/pep-783-emscripten-packaging/86862/17 "2025-04-07T15:45:10Z")

</div>

> [@pf\_moore](#):
>
> what if the latest version of a PyPI package doesn’t have a wheel for the required pyodide version? Is it OK to backtrack through all older versions looking for one?

Yes, subject of course to the constraints of the request. I think this is all completely normal?

> [@pf\_moore](#):
>
> Are projects expected to ship wheels for _all_ pyodide versions? The manylinux spec avoids this by having systems be compatible with all older manylinux versions, as well as the latest version. That’s not how pyodide tags work, if I understand things correctly.

Yes the ABI tags are not backwards compatible. So far, Pyodide only allows people to use a specific newish version of each binary package. Very few people complain about this.

It is up to the individual project what sort of support they want to offer, but I don’t expect them to support very old Pyodide versions. It would be reasonable for them to only support the most recent one or two Python versions. I think cibuildwheel intends to support all Pyodide ABIs that are not for EOL Python versions.

---

<div class="post-metadata">

**Author:** ![oscarbenjamin](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/oscarbenjamin/32/1209_2.png) [@oscarbenjamin](https://discuss.python.org/u/oscarbenjamin)\
**Post date:** [April 7, 2025, 3:49pm UTC](https://discuss.python.org/t/pep-783-emscripten-packaging/86862/18 "2025-04-07T15:49:09Z")

</div>

> [@hoodmane](#):
>
> > The PEP refers generically to “package installers” but it is not clear whether there is any expectation that existing widely used installers such as pip would ever be used in pyodide.
> 
> We are already using pip with Pyodide.

But is that normal `pip` or some patched version of `pip`? If it is a patched version is there an expectation that the patches would ever be upstreamed?

Let me put the question a slightly different way: if some customisation of pip or of how packages are installed is needed to handle the pyodide case then who is generally expected to implement and maintain that customisation? Is it the pyodide maintainers (e.g. you?) or pip maintainers (e.g. @pf_moore)?

> [@hoodmane](#):
>
> > [@pf\_moore](#):
> >
> > what if the latest version of a PyPI package doesn’t have a wheel for the required pyodide version? Is it OK to backtrack through all older versions looking for one?
> 
> Yes, subject of course to the constraints of the request. I think this is all completely normal?

The current default behaviour of pip is that it would download the sdist for the latest version and try to build it. Various options exist such as `--prefer-binary`, `--only-binary` etc to control this but those options are all off by default. Lengthy discussions have considered changing the default to e.g. `--prefer-binary` but it is known that any change would break some things.

---

<div class="post-metadata">

**Author:** ![hoodmane](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/hoodmane/32/4037_2.png) [@hoodmane](https://discuss.python.org/u/hoodmane)\
**Post date:** [April 7, 2025, 4:04pm UTC](https://discuss.python.org/t/pep-783-emscripten-packaging/86862/19 "2025-04-07T16:04:38Z")

</div>

> But is that normal `pip` or some patched version of `pip` ?

Patched. `venv/bin/pip` is changed to look like [this](https://gist.github.com/hoodmane/79ef1ae77984c791ea3f264e7737df44).

> If it is a patched version is there an expectation that the patches would ever be upstreamed?

Not specified by this PEP. My hope is that @freakboy3742 and I can figure out a solution that handles other cross-build-only platforms as well.

> who is generally expected to implement and maintain that customisation? Is it the pyodide maintainers (e.g. you?) or pip maintainers (e.g. @pf_moore)?

Pyodide maintainers.

> The current default behaviour of pip is that it would download the sdist for the latest version and try to build it.

And this will definitely break.

---

<div class="post-metadata">

**Author:** ![henryiii](https://sea2.discourse-cdn.com/flex002/user_avatar/discuss.python.org/henryiii/32/3493_2.png) [@henryiii](https://discuss.python.org/u/henryiii)\
**Post date:** [April 7, 2025, 4:13pm UTC](https://discuss.python.org/t/pep-783-emscripten-packaging/86862/20 "2025-04-07T16:13:01Z")

</div>

Just want to note that this already is working in practice. You can use scikit-build-core to build wheels for Pyodide; several packages do this, like boost-histogram and awkward-cpp. They build the wheels using cibuildwheel and then set up a documentation site with live versions of the current packages. The only problem is those wheels can’t be uploaded to PyPI, and instead must be manually placed in a folder (which is what the CI does). cibuildwheel has supported Pyodide for quite a while now.

It would be a really bad for package maintainers if there were more than one platform for a single Python version, but I think leaving the possibility in case of an emergency is very reasonable. It’s unfortunate that ABI3 isn’t really useful, but it’s pretty much what almost every package has to deal with today; whenever a new Python version comes out, you need to upload new wheels. (Even ABI3 packages are needing to upload 3.13t wheels now!) It would be _really_ nice if the Pyodide release (the flags + emscripten version) was synchronized to CPython, so that a package could release 3.14 and pyodide 3.14 wheels at the same time. The only reason that’s an issue today (the 6 month delay) is due to the hundreds packages that are also built in every Pyodide build; having a standard wheel tag on PyPI would help reduce that, and I think maybe the model could be changed to have a core Pyodode (just CPython for Emscripten) and then a collection of package builds to cover missing/core PyPI wheels (Raspberry pi’s piwheels is a similar model, I believe).

I’d love to see better cross-compiling support, besides Wasm/iOS/Android, cross-compiling Windows ARM, Linux archs, and even macOS might benefit.

[Next page](https://discuss.python.org/t/pep-783-emscripten-packaging/86862.md?page=2)
