gh-145805: Add python Platforms/emscripten run subcommand (#146051)

Provides a `run` command in the Emscripten build tooling, and adds 
environment variable configuration for EMSDK_CACHE, CROSS_BUILD_DIR
and QUIET.
This commit is contained in:
Hood Chatham 2026-03-19 02:06:17 +01:00 committed by GitHub
parent b9d43188e9
commit abd5246305
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -77,9 +77,11 @@ def get_build_paths(cross_build_dir=None, emsdk_cache=None):
LOCAL_SETUP_MARKER = b"# Generated by Platforms/wasm/emscripten.py\n"
@functools.cache
def validate_emsdk_version(emsdk_cache):
"""Validate that the emsdk cache contains the required emscripten version."""
if emsdk_cache is None:
print("Build will use EMSDK from current environment.")
return
required_version = required_emscripten_version()
emsdk_env = emsdk_activate_path(emsdk_cache)
@ -530,7 +532,6 @@ def configure_emscripten_python(context, working_dir):
@subdir("host_dir")
def make_emscripten_python(context, working_dir):
"""Run `make` for the emscripten/host build."""
validate_emsdk_version(context.emsdk_cache)
call(
["make", "--jobs", str(cpu_count()), "all"],
env=updated_env({}, context.emsdk_cache),
@ -541,6 +542,22 @@ def make_emscripten_python(context, working_dir):
subprocess.check_call([exec_script, "--version"])
def run_emscripten_python(context):
"""Run the built emscripten Python."""
host_dir = context.build_paths["host_dir"]
exec_script = host_dir / "python.sh"
if not exec_script.is_file():
print("Emscripten not built", file=sys.stderr)
sys.exit(1)
args = context.args
# Strip the "--" separator if present
if args and args[0] == "--":
args = args[1:]
os.execv(str(exec_script), [str(exec_script)] + args)
def build_target(context):
"""Build one or more targets."""
steps = []
@ -581,15 +598,31 @@ def clean_contents(context):
print(f"🧹 Deleting generated {LOCAL_SETUP} ...")
def add_cross_build_dir_option(subcommand):
subcommand.add_argument(
"--cross-build-dir",
action="store",
default=os.environ.get("CROSS_BUILD_DIR"),
dest="cross_build_dir",
help=(
"Path to the cross-build directory "
f"(default: {DEFAULT_CROSS_BUILD_DIR}). "
"Can also be set with the CROSS_BUILD_DIR environment variable.",
),
)
def main():
default_host_runner = "node"
parser = argparse.ArgumentParser()
subcommands = parser.add_subparsers(dest="subcommand")
install_emscripten_cmd = subcommands.add_parser(
"install-emscripten",
help="Install the appropriate version of Emscripten",
)
build = subcommands.add_parser("build", help="Build everything")
build.add_argument(
"target",
@ -605,24 +638,46 @@ def main():
configure_build = subcommands.add_parser(
"configure-build-python", help="Run `configure` for the build Python"
)
make_mpdec_cmd = subcommands.add_parser(
"make-mpdec",
help="Clone mpdec repo, configure and build it for emscripten",
)
make_libffi_cmd = subcommands.add_parser(
"make-libffi",
help="Clone libffi repo, configure and build it for emscripten",
)
make_build = subcommands.add_parser(
"make-build-python", help="Run `make` for the build Python"
)
configure_host = subcommands.add_parser(
"configure-host",
help="Run `configure` for the host/emscripten (pydebug builds are inferred from the build Python)",
help=(
"Run `configure` for the host/emscripten "
"(pydebug builds are inferred from the build Python)"
),
)
make_host = subcommands.add_parser(
"make-host", help="Run `make` for the host/emscripten"
)
run = subcommands.add_parser(
"run",
help="Run the built emscripten Python",
)
run.add_argument(
"args",
nargs=argparse.REMAINDER,
help=(
"Arguments to pass to the emscripten Python "
"(use '--' to separate from run options)",
)
)
add_cross_build_dir_option(run)
clean = subcommands.add_parser(
"clean", help="Delete files and directories created by this script"
)
@ -651,26 +706,26 @@ def main():
subcommand.add_argument(
"--quiet",
action="store_true",
default=False,
default="QUIET" in os.environ,
dest="quiet",
help="Redirect output from subprocesses to a log file",
)
subcommand.add_argument(
"--cross-build-dir",
action="store",
default=None,
dest="cross_build_dir",
help="Path to the cross-build directory "
f"(default: {DEFAULT_CROSS_BUILD_DIR})",
help=(
"Redirect output from subprocesses to a log file. "
"Can also be set with the QUIET environment variable."
),
)
add_cross_build_dir_option(subcommand)
subcommand.add_argument(
"--emsdk-cache",
action="store",
default=None,
default=os.environ.get("EMSDK_CACHE"),
dest="emsdk_cache",
help="Path to emsdk cache directory. If provided, validates that "
"the required emscripten version is installed.",
help=(
"Path to emsdk cache directory. If provided, validates that "
"the required emscripten version is installed. "
"Can also be set with the EMSDK_CACHE environment variable."
),
)
for subcommand in configure_build, configure_host:
subcommand.add_argument(
"--clean",
@ -679,10 +734,12 @@ def main():
dest="clean",
help="Delete any relevant directories before building",
)
for subcommand in build, configure_build, configure_host:
subcommand.add_argument(
"args", nargs="*", help="Extra arguments to pass to `configure`"
)
for subcommand in build, configure_host:
subcommand.add_argument(
"--host-runner",
@ -699,8 +756,6 @@ def main():
if context.emsdk_cache:
context.emsdk_cache = Path(context.emsdk_cache).absolute()
else:
print("Build will use EMSDK from current environment.")
context.build_paths = get_build_paths(
context.cross_build_dir, context.emsdk_cache
@ -715,6 +770,7 @@ def main():
"configure-host": configure_emscripten_python,
"make-host": make_emscripten_python,
"build": build_target,
"run": run_emscripten_python,
"clean": clean_contents,
}