Skip to content

Commit 637186c

Browse files
emmatypingbrettcannontiranpablogsalzware
authored
Initial WASM/Cross build factory code (#322)
* Initial WASM/Cross build code * Changes to use HOSTRUNNER instead of RUNSHARED * Add 3.11 branches (#323) * Add tier labels corresponding to PEP 11 (#326) * Add environment variable to set settings path (#328) * Split WASM build factories * use config.guess directly * Fix pkg-config cross build, add suffix to create unique workers Co-authored-by: Brett Cannon <[email protected]> Co-authored-by: Christian Heimes <[email protected]> Co-authored-by: Ethan Smith <[email protected]> Co-authored-by: Pablo Galindo Salgado <[email protected]> Co-authored-by: Zachary Ware <[email protected]>
1 parent f84d6c1 commit 637186c

File tree

4 files changed

+281
-3
lines changed

4 files changed

+281
-3
lines changed

master/custom/builders.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@
3636
MacOSArmWithBrewBuild,
3737
WindowsARM64Build,
3838
WindowsARM64ReleaseBuild,
39+
Wasm32EmscriptenNodeBuild,
40+
Wasm32EmscriptenBrowserBuild,
41+
Wasm32WASIBuild,
3942
)
4043

4144
STABLE = "stable"
@@ -49,7 +52,7 @@
4952
def get_builders(settings):
5053
# Override with a default simple worker if we are using local workers
5154
if settings.use_local_worker:
52-
return [("Test Builder", "local-worker", UnixBuild, STABLE)]
55+
return [("Test Builder", "local-worker", UnixBuild, STABLE, NO_TIER)]
5356

5457
return [
5558
# -- Stable builders --
@@ -207,6 +210,11 @@ def get_builders(settings):
207210
("ARM64 Windows Non-Debug", "linaro-win-arm64", WindowsARM64ReleaseBuild, STABLE, NO_TIER),
208211
("ARM64 Windows Azure", "linaro2-win-arm64", WindowsARM64Build, UNSTABLE, NO_TIER),
209212
("ARM64 Windows Non-Debug Azure", "linaro2-win-arm64", WindowsARM64ReleaseBuild, UNSTABLE, NO_TIER),
213+
214+
# WebAssembly
215+
("wasm32-emscripten node (threaded)", "bcannon-wasm", Wasm32EmscriptenNodeBuild, UNSTABLE, NO_TIER),
216+
("wasm32-emscripten browser (dynamic linking)", "bcannon-wasm", Wasm32EmscriptenBrowserBuild, UNSTABLE, NO_TIER),
217+
("wasm32-wasi", "bcannon-wasm", Wasm32WASIBuild, UNSTABLE, NO_TIER),
210218
]
211219

212220

master/custom/factories.py

Lines changed: 258 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import os.path
22
from buildbot.process import factory
3-
from buildbot.steps.shell import Configure, Compile, ShellCommand
3+
from buildbot.steps.shell import (
4+
Configure,
5+
Compile,
6+
ShellCommand,
7+
SetPropertyFromCommand,
8+
)
9+
10+
from buildbot.plugins import util
411

512
from .steps import (
613
Test,
@@ -577,3 +584,253 @@ class WindowsARM64ReleaseBuild(WindowsARM64Build):
577584
testFlags = WindowsARM64Build.testFlags + ["+d"]
578585
# keep default cleanFlags, both configurations get cleaned
579586
factory_tags = ["win-arm64", "nondebug"]
587+
588+
##############################################################################
589+
############################## WASM BUILDS #################################
590+
##############################################################################
591+
592+
593+
class UnixCrossBuild(UnixBuild):
594+
configureFlags = [
595+
"--with-pydebug",
596+
"--with-build-python=../build/python"
597+
]
598+
extra_configure_flags = []
599+
host_configure_cmd = ["../../configure"]
600+
host = None
601+
host_make_cmd = ["make"]
602+
can_execute_python = True
603+
604+
def setup(self, parallel, branch, test_with_PTY=False, **kwargs):
605+
assert self.host is not None, "Must set self.host on cross builds"
606+
607+
out_of_tree_dir = "build_oot"
608+
oot_dir_path = os.path.join("build", out_of_tree_dir)
609+
oot_build_path = os.path.join(oot_dir_path, "build")
610+
oot_host_path = os.path.join(oot_dir_path, "host")
611+
612+
self.addStep(
613+
SetPropertyFromCommand(
614+
name="Gather build triple from worker",
615+
description="Get the build triple config.guess",
616+
command="./config.guess",
617+
property="build_triple",
618+
warnOnFailure=True,
619+
)
620+
)
621+
622+
# Create out of tree directory for "build", the platform we are
623+
# currently running on
624+
self.addStep(
625+
ShellCommand(
626+
name="mkdir build out-of-tree directory",
627+
description="Create build out-of-tree directory",
628+
command=["mkdir", "-p", oot_build_path],
629+
warnOnFailure=True,
630+
)
631+
)
632+
# Create directory for "host", the platform we want to compile *for*
633+
self.addStep(
634+
ShellCommand(
635+
name="mkdir host out-of-tree directory",
636+
description="Create host out-of-tree directory",
637+
command=["mkdir", "-p", oot_host_path],
638+
warnOnFailure=True,
639+
)
640+
)
641+
642+
# First, we build the "build" Python, which we need to cross compile
643+
# the "host" Python
644+
self.addStep(
645+
Configure(
646+
name="Configure build Python",
647+
command=["../../configure"],
648+
workdir=oot_build_path
649+
)
650+
)
651+
if parallel:
652+
compile = ["make", parallel]
653+
else:
654+
compile = ["make"]
655+
656+
self.addStep(
657+
Compile(
658+
name="Compile build Python",
659+
command=compile,
660+
workdir=oot_build_path
661+
)
662+
)
663+
664+
# Now that we have a "build" architecture Python, we can use that
665+
# to build a "host" (also known as the target we are cross compiling)
666+
# to
667+
configure_cmd = self.host_configure_cmd + ["--prefix", "$(PWD)/target/host"]
668+
configure_cmd += self.configureFlags + self.extra_configure_flags
669+
configure_cmd += [util.Interpolate("--build=%(prop:build_triple)s")]
670+
configure_cmd += [f"--host={self.host}"]
671+
self.addStep(
672+
Configure(
673+
name="Configure host Python",
674+
command=configure_cmd,
675+
env=self.compile_environ,
676+
workdir=oot_host_path
677+
)
678+
)
679+
680+
testopts = self.testFlags
681+
if "-R" not in self.testFlags:
682+
testopts += " --junit-xml test-results.xml"
683+
if parallel:
684+
testopts = testopts + " " + parallel
685+
if "-j" not in testopts:
686+
testopts = "-j2 " + testopts
687+
688+
# Timeout for the buildworker process
689+
self.test_timeout = self.test_timeout or TEST_TIMEOUT
690+
# Timeout for faulthandler
691+
faulthandler_timeout = self.test_timeout - 5 * 60
692+
693+
test = [
694+
"make",
695+
"buildbottest",
696+
"TESTOPTS=" + testopts + " ${BUILDBOT_TESTOPTS}",
697+
"TESTPYTHONOPTS=" + self.interpreterFlags,
698+
"TESTTIMEOUT=" + str(faulthandler_timeout),
699+
]
700+
701+
if parallel:
702+
compile = self.host_make_cmd + [parallel, self.makeTarget]
703+
else:
704+
compile = self.host_make_cmd + [self.makeTarget]
705+
self.addStep(
706+
Compile(
707+
name="Compile host Python",
708+
command=compile,
709+
env=self.compile_environ,
710+
workdir=oot_host_path,
711+
)
712+
)
713+
if self.can_execute_python:
714+
self.addStep(
715+
ShellCommand(
716+
name="pythoninfo",
717+
description="pythoninfo",
718+
command=["make", "pythoninfo"],
719+
warnOnFailure=True,
720+
env=self.test_environ,
721+
workdir=oot_host_path,
722+
)
723+
)
724+
self.addStep(
725+
Test(
726+
command=test,
727+
timeout=self.test_timeout,
728+
usePTY=test_with_PTY,
729+
env=self.test_environ,
730+
workdir=oot_host_path,
731+
)
732+
)
733+
if branch not in ("3",) and "-R" not in self.testFlags:
734+
filename = os.path.join(oot_host_path, "test-results.xml")
735+
self.addStep(UploadTestResults(branch, filename=filename))
736+
self.addStep(
737+
Clean(
738+
name="Clean build Python",
739+
workdir=oot_build_path,
740+
)
741+
)
742+
self.addStep(
743+
Clean(
744+
name="Clean host Python",
745+
workdir=oot_host_path,
746+
)
747+
)
748+
749+
750+
class Wasm32EmscriptenBuild(UnixCrossBuild):
751+
"""wasm32-emscripten builder
752+
753+
* Emscripten SDK >= 3.1.12 must be installed
754+
* ccache must be installed
755+
* Emscripten PATHs must be pre-pended to PATH
756+
* ``which node`` must be equal $EMSDK_NODE
757+
"""
758+
factory_tags = ["wasm", "emscripten"]
759+
compile_environ = {
760+
"CONFIG_SITE": "../../Tools/wasm/config.site-wasm32-emscripten",
761+
"EM_COMPILER_WRAPPER": "ccache",
762+
}
763+
764+
host = "wasm32-unknown-emscripten"
765+
host_configure_cmd = ["emconfigure", "../../configure"]
766+
host_make_cmd = ["emmake", "make"]
767+
768+
769+
class Wasm32EmscriptenNodeBuild(Wasm32EmscriptenBuild):
770+
buildersuffix = ".emscripten-node"
771+
extra_configure_flags = [
772+
"--with-emscripten-target=node",
773+
"--disable-wasm-dynamic-linking",
774+
"--enable-wasm-pthreads",
775+
]
776+
777+
778+
class Wasm32EmscriptenBrowserBuild(Wasm32EmscriptenBuild):
779+
buildersuffix = ".emscripten-browser"
780+
extra_configure_flags = [
781+
"--with-emscripten-target=browser",
782+
"--enable-wasm-dynamic-linking",
783+
"--disable-wasm-pthreads",
784+
]
785+
# browser builds do not accept argv from CLI
786+
can_execute_python = False
787+
788+
789+
class Wasm32WASIBuild(UnixCrossBuild):
790+
"""wasm32-wasi builder
791+
792+
* WASI SDK >= 16 must be installed to default path /opt/wasi-sdk
793+
* WASIX must be installed to /opt/wasix
794+
* ccache must be installed
795+
* wasmtime must be installed and on PATH
796+
"""
797+
buildersuffix = ".wasi"
798+
factory_tags = ["wasm", "wasi"]
799+
extra_configure_flags = [
800+
# debug builds exhaust the limited call stack on WASI
801+
"--without-pydebug",
802+
# ipv6 is not supported on WASI
803+
"--disable-ipv6",
804+
]
805+
wasi_sdk = "/opt/wasi-sdk"
806+
wasi_sysroot = f"{wasi_sdk}/share/wasi-sysroot"
807+
wasix = "/opt/wasix"
808+
compile_environ = {
809+
"CONFIG_SITE": "../../Tools/wasm/config.site-wasm32-wasi",
810+
# use Clang from WASI-SDK
811+
"CC": f"ccache {wasi_sdk}/bin/clang",
812+
"LDSHARED": f"{wasi_sdk}/bin/wasm-ld",
813+
"AR": f"{wasi_sdk}/bin/llvm-ar",
814+
# use WASIX library with POSIX stubs
815+
"CFLAGS": f"-isystem {wasix}/include",
816+
"LDFLAGS": f"-L{wasix}/lib -lwasix",
817+
# WASI-SDK does not have a 'wasm32-unknown-wasi-pkg-config' script
818+
# force pkg-config into cross-compiling mode
819+
"PKG_CONFIG_PATH": "",
820+
"PKG_CONFIG_SYSROOT_DIR": wasi_sysroot,
821+
"PKG_CONFIG_LIBDIR": f"{wasi_sysroot}/lib/pkgconfig:{wasi_sysroot}/share/pkgconfig",
822+
}
823+
host = "wasm32-unknown-wasi"
824+
825+
def setup(self, parallel, branch, test_with_PTY=False, **kwargs):
826+
self.addStep(
827+
ShellCommand(
828+
name="Touch srcdir Modules/Setup.local",
829+
description="Hack to work around wasmtime mapdir issue",
830+
command=["touch", "Modules/Setup.local"],
831+
haltOnFailure=True,
832+
)
833+
)
834+
super().setup(
835+
parallel, branch, test_with_PTY=test_with_PTY, **kwargs
836+
)

master/custom/workers.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -289,5 +289,10 @@ def get_workers(settings):
289289
tags=['windows', 'arm64'],
290290
parallel_tests=2,
291291
),
292-
292+
cpw(
293+
name="bcannon-wasm",
294+
tags=['wasm', 'emscripten', 'wasi'],
295+
branches=['3.11', '3.x'],
296+
parallel_tests=4,
297+
),
293298
]

master/master.cfg

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,14 @@ for branch_num, (git_url, branchname, git_branch) in enumerate(git_branches):
236236
branch=branchname,
237237
**extra_factory_args.get(worker, {}),
238238
)
239+
tags = [branchname, stability,] + getattr(f, "tags", [])
240+
if tier:
241+
tags.append(tier)
242+
243+
# Only 3.11+ for WebAssembly builds
244+
if "wasm" in tags and branchname in {"3.8", "3.9", "3.10"}:
245+
continue
246+
239247
if name in DAILYBUILDERS:
240248
dailybuildernames.append(buildername)
241249
else:

0 commit comments

Comments
 (0)