EMSCRIPTEN_DIR = Path(__file__).parent
CHECKOUT = EMSCRIPTEN_DIR.parent.parent.parent
+EMSCRIPTEN_VERSION_FILE = EMSCRIPTEN_DIR / "emscripten_version.txt"
CROSS_BUILD_DIR = CHECKOUT / "cross-build"
NATIVE_BUILD_DIR = CROSS_BUILD_DIR / "build"
LOCAL_SETUP_MARKER = b"# Generated by Tools/wasm/emscripten.py\n"
-def updated_env(updates={}):
+@functools.cache
+def get_required_emscripten_version():
+ """Read the required emscripten version from emscripten_version.txt."""
+ return EMSCRIPTEN_VERSION_FILE.read_text().strip()
+
+
+@functools.cache
+def get_emsdk_activate_path(emsdk_cache):
+ required_version = get_required_emscripten_version()
+ return Path(emsdk_cache) / required_version / "emsdk_env.sh"
+
+
+def validate_emsdk_version(emsdk_cache):
+ """Validate that the emsdk cache contains the required emscripten version."""
+ required_version = get_required_emscripten_version()
+ emsdk_env = get_emsdk_activate_path(emsdk_cache)
+ if not emsdk_env.is_file():
+ print(
+ f"Required emscripten version {required_version} not found in {emsdk_cache}",
+ file=sys.stderr,
+ )
+ sys.exit(1)
+ print(f"✅ Emscripten version {required_version} found in {emsdk_cache}")
+
+
+def parse_env(text):
+ result = {}
+ for line in text.splitlines():
+ key, val = line.split("=", 1)
+ result[key] = val
+ return result
+
+
+@functools.cache
+def get_emsdk_environ(emsdk_cache):
+ """Returns os.environ updated by sourcing emsdk_env.sh"""
+ if not emsdk_cache:
+ return os.environ
+ env_text = subprocess.check_output(
+ [
+ "bash",
+ "-c",
+ f"EMSDK_QUIET=1 source {get_emsdk_activate_path(emsdk_cache)} && env",
+ ],
+ text=True,
+ )
+ return parse_env(env_text)
+
+
+def updated_env(updates, emsdk_cache):
"""Create a new dict representing the environment to use.
The changes made to the execution environment are printed out.
except subprocess.CalledProcessError:
pass # Might be building from a tarball.
# This layering lets SOURCE_DATE_EPOCH from os.environ takes precedence.
- environment = env_defaults | os.environ | updates
-
+ environment = env_defaults | get_emsdk_environ(emsdk_cache) | updates
env_diff = {}
for key, value in environment.items():
if os.environ.get(key) != value:
)
call(
[EMSCRIPTEN_DIR / "make_libffi.sh"],
- env=updated_env({"PREFIX": PREFIX_DIR}),
+ env=updated_env({"PREFIX": PREFIX_DIR}, context.emsdk_cache),
cwd=libffi_dir,
quiet=context.quiet,
)
],
cwd=mpdec_dir,
quiet=context.quiet,
+ env=updated_env({}, context.emsdk_cache),
)
call(
["make", "install"],
configure.extend(context.args)
call(
configure,
- env=updated_env(env_additions),
+ env=updated_env(env_additions, context.emsdk_cache),
quiet=context.quiet,
)
"""Run `make` for the emscripten/host build."""
call(
["make", "--jobs", str(cpu_count()), "all"],
- env=updated_env(),
+ env=updated_env({}, context.emsdk_cache),
quiet=context.quiet,
)
dest="quiet",
help="Redirect output from subprocesses to a log file",
)
+ subcommand.add_argument(
+ "--emsdk-cache",
+ action="store",
+ default=None,
+ dest="emsdk_cache",
+ help="Path to emsdk cache directory. If provided, validates that "
+ "the required emscripten version is installed.",
+ )
for subcommand in configure_build, configure_host:
subcommand.add_argument(
"--clean",
context = parser.parse_args()
+ if context.emsdk_cache:
+ validate_emsdk_version(context.emsdk_cache)
+ context.emsdk_cache = Path(context.emsdk_cache).absolute()
+ else:
+ print("Build will use EMSDK from current environment.")
+
dispatch = {
"make-libffi": make_emscripten_libffi,
"make-mpdec": make_mpdec,