Add Emscripten libmpdec build step
Goes together with: https://github.com/python/cpython/pull/136997
Can these not be made already present on the host?
Do you mean that we should build them once and then install in some prefix directory which we reuse between jobs?
Building libmpdec is pretty fast, and it's nice for it to be reproducible. OTOH libssl takes several minutes to build...
Do you mean that we should build them once and then install in some prefix directory which we reuse between jobs?
Right.
Building libmpdec is pretty fast, and it's nice for it to be reproducible. OTOH libssl takes several minutes to build...
Windows builds use pre-built libssl binaries, partly for this reason. They also build some libraries (statically) on every build, so I'm OK with whichever direction you want to go for Emscripten :)
Do you mean that we should build them once and then install in some prefix directory which we reuse between jobs?
Right
FWIW - this is the approach that iOS and Android use as well - we've got standalone repos (iOS, Android) to manage binary releases; the CPython CI builds then download/cache those releases.
The complication for Emscripten is that we can't just add "bzip-1.0.8" and re-use it - we need to add "bzip-1.0.8, compiled for Emscripten 4.0.10". That's certainly possible, but it's definitely more complicated than the iOS/Android/macOS situation where the only real restriction is the minimum OS compatibility version.
@hoodmane One thought - we could cache these builds as part of the whole "Emscripten version cache" thing we discussed at EuroPython.
For the benefit of others - Emscripten doesn't provide any ABI compatibility guarantees between versions. We're effectively going to have to say "Python 3.14 uses Emscripten 4.0.11", and everything that is for Python3.14 will need to use that version of Emscripten.
This means the buildbot will need to maintain multiple versions of Emscripten; the idea @hoodmane and I discussed at EuroPython was to add an --emscripten-dir argument to the build script, and set the required Emscripten version number in the script; if -emscripten-dir is provided, that is used to find the appropriate EMSDK version on disk.
We could then expand that to also include cached builds of libffi, mpdecimal, or whatever else is a dependency. We'd end up with a directory structure that looks something like:
- emscripten-versions
- 4.0.11
- emsdk
- prefix
- include
- lib
- 4.0.20
- emsdk
- prefix
- include
- lib
The idea would be that if you specify an --emscripten-versions directory, it treats the content as a cache; the build target would assume cached builds exist and use the version specific prefix directory; targets for the build dependencies would install into the version-specific prefix.
Thoughts?
Makes sense to me. libmpdec only takes about 8 seconds to build though, so could we merge it first like this and then do the rearrangement with two libraries? I feel better about having two libs before making this change. Though I'm also okay with adding --emscripten-versions first.
Makes sense to me. libmpdec only takes about 8 seconds to build though, so could we merge it first like this and then do the rearrangement with two libraries? I feel better about having two libs before making this change.
I'd be fine with merging this as is, and then re-arranging as part of the larger refactor of the build script.
The complication is that the 3.14 branch is now locked until 3.14.0 final, so we can't merge this change to the buildbot without breaking 3.14 builds.
It may be possible for the step to be made optional depending on the branch? Similar things have been done before I think: https://github.com/python/buildmaster-config/blob/847d2edfc6913945c21279cc0d709b86f1e6f926/master/custom/factories.py#L309-L314
patch
Subject: [PATCH] Make compile step not run on 3.14
---
Index: master/custom/factories.py
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/master/custom/factories.py b/master/custom/factories.py
--- a/master/custom/factories.py (revision cacc9671eed1382c2b5cbdbde4e71a47a5c2164d)
+++ b/master/custom/factories.py (date 1753342781896)
@@ -1339,7 +1339,7 @@
buildersuffix = ".emscripten"
factory_tags = ["emscripten"]
- def setup(self, **kwargs):
+ def setup(self, branch, **kwargs):
compile_environ = {
"PATH": os.pathsep.join([
"/home/emscripten/emsdk",
@@ -1368,12 +1368,19 @@
name="Compile host libFFI",
command=["python3", "Tools/wasm/emscripten", "make-libffi"],
env=compile_environ,
- ),
- Compile(
- name="Compile host libmpdec",
- command=["python3", "Tools/wasm/emscripten", "make-mpdec"],
- env=compile_environ,
- ),
+ )
+ ])
+
+ # This is done because ...
+ if branch != '3.14':
+ self.addStep(
+ Compile(
+ name="Compile host libmpdec",
+ command=["python3", "Tools/wasm/emscripten", "make-mpdec"],
+ env=compile_environ,
+ ))
+
+ self.addSteps([
Configure(
name="Configure host Python",
command=["python3", "Tools/wasm/emscripten", "configure-host"],
Thanks for the suggestion @StanFromIreland! I did that.
@freakboy3742 does it look okay to merge now with the check that @StanFromIreland suggested?
The complication with this approach is that PR builds (i.e., everything fired by the !buildbot comment trigger) all come through as "branch = 3", regardless of whether it's a PR on main, or a backport PR.
So, this change would mean we wouldn't have the ability to run CI builds on PRs against the 3.14 branch. That seems like fairly significant collateral damage, especially in the 3.14 RC window.
The mpdec changes have been merged into 3.14, so we can roll back to the "non-gated version" and merge.
The complication for Emscripten is that we can't just add "bzip-1.0.8" and re-use it - we need to add "bzip-1.0.8, compiled for Emscripten 4.0.10". That's certainly possible, but it's definitely more complicated than the iOS/Android/macOS situation where the only real restriction is the minimum OS compatibility version.
My two cents about this is that, indeed, Emscripten does not support ABI compatibility between versions, but I think it is mainly related to shared libraries, not static ones.
Static WASM libraries are standard WASM modules without any custom sections, so I think it would be quite safe to link the library built with old Emscripten versions to the runtime built with a newer Emscripten.
Maybe we can experiment this in Pyodide first and see if it works, wdyt @hoodmane?