2222
2323EMSCRIPTEN_DIR = Path (__file__ ).parent
2424CHECKOUT = EMSCRIPTEN_DIR .parent .parent .parent
25+ EMSCRIPTEN_VERSION_FILE = EMSCRIPTEN_DIR / "emscripten_version.txt"
2526
2627CROSS_BUILD_DIR = CHECKOUT / "cross-build"
2728NATIVE_BUILD_DIR = CROSS_BUILD_DIR / "build"
3637LOCAL_SETUP_MARKER = b"# Generated by Tools/wasm/emscripten.py\n "
3738
3839
39- def updated_env (updates = {}):
40+ @functools .cache
41+ def get_required_emscripten_version ():
42+ """Read the required emscripten version from emscripten_version.txt."""
43+ return EMSCRIPTEN_VERSION_FILE .read_text ().strip ()
44+
45+
46+ @functools .cache
47+ def get_emsdk_activate_path (emsdk_cache ):
48+ required_version = get_required_emscripten_version ()
49+ return Path (emsdk_cache ) / required_version / "emsdk_env.sh"
50+
51+
52+ def validate_emsdk_version (emsdk_cache ):
53+ """Validate that the emsdk cache contains the required emscripten version."""
54+ required_version = get_required_emscripten_version ()
55+ emsdk_env = get_emsdk_activate_path (emsdk_cache )
56+ if not emsdk_env .is_file ():
57+ print (
58+ f"Required emscripten version { required_version } not found in { emsdk_cache } " ,
59+ file = sys .stderr ,
60+ )
61+ sys .exit (1 )
62+ print (f"✅ Emscripten version { required_version } found in { emsdk_cache } " )
63+
64+
65+ def parse_env (text ):
66+ result = {}
67+ for line in text .splitlines ():
68+ key , val = line .split ("=" , 1 )
69+ result [key ] = val
70+ return result
71+
72+
73+ @functools .cache
74+ def get_emsdk_environ (emsdk_cache ):
75+ """Returns os.environ updated by sourcing emsdk_env.sh"""
76+ if not emsdk_cache :
77+ return os .environ
78+ env_text = subprocess .check_output (
79+ [
80+ "bash" ,
81+ "-c" ,
82+ f"EMSDK_QUIET=1 source { get_emsdk_activate_path (emsdk_cache )} && env" ,
83+ ],
84+ text = True ,
85+ )
86+ return parse_env (env_text )
87+
88+
89+ def updated_env (updates , emsdk_cache ):
4090 """Create a new dict representing the environment to use.
4191
4292 The changes made to the execution environment are printed out.
@@ -52,8 +102,7 @@ def updated_env(updates={}):
52102 except subprocess .CalledProcessError :
53103 pass # Might be building from a tarball.
54104 # This layering lets SOURCE_DATE_EPOCH from os.environ takes precedence.
55- environment = env_defaults | os .environ | updates
56-
105+ environment = env_defaults | get_emsdk_environ (emsdk_cache ) | updates
57106 env_diff = {}
58107 for key , value in environment .items ():
59108 if os .environ .get (key ) != value :
@@ -204,7 +253,7 @@ def make_emscripten_libffi(context, working_dir):
204253 )
205254 call (
206255 [EMSCRIPTEN_DIR / "make_libffi.sh" ],
207- env = updated_env ({"PREFIX" : PREFIX_DIR }),
256+ env = updated_env ({"PREFIX" : PREFIX_DIR }, context . emsdk_cache ),
208257 cwd = libffi_dir ,
209258 quiet = context .quiet ,
210259 )
@@ -231,6 +280,7 @@ def make_mpdec(context, working_dir):
231280 ],
232281 cwd = mpdec_dir ,
233282 quiet = context .quiet ,
283+ env = updated_env ({}, context .emsdk_cache ),
234284 )
235285 call (
236286 ["make" , "install" ],
@@ -300,7 +350,7 @@ def configure_emscripten_python(context, working_dir):
300350 configure .extend (context .args )
301351 call (
302352 configure ,
303- env = updated_env (env_additions ),
353+ env = updated_env (env_additions , context . emsdk_cache ),
304354 quiet = context .quiet ,
305355 )
306356
@@ -358,7 +408,7 @@ def make_emscripten_python(context, working_dir):
358408 """Run `make` for the emscripten/host build."""
359409 call (
360410 ["make" , "--jobs" , str (cpu_count ()), "all" ],
361- env = updated_env (),
411+ env = updated_env ({}, context . emsdk_cache ),
362412 quiet = context .quiet ,
363413 )
364414
@@ -439,6 +489,14 @@ def main():
439489 dest = "quiet" ,
440490 help = "Redirect output from subprocesses to a log file" ,
441491 )
492+ subcommand .add_argument (
493+ "--emsdk-cache" ,
494+ action = "store" ,
495+ default = None ,
496+ dest = "emsdk_cache" ,
497+ help = "Path to emsdk cache directory. If provided, validates that "
498+ "the required emscripten version is installed." ,
499+ )
442500 for subcommand in configure_build , configure_host :
443501 subcommand .add_argument (
444502 "--clean" ,
@@ -463,6 +521,12 @@ def main():
463521
464522 context = parser .parse_args ()
465523
524+ if context .emsdk_cache :
525+ validate_emsdk_version (context .emsdk_cache )
526+ context .emsdk_cache = Path (context .emsdk_cache ).absolute ()
527+ else :
528+ print ("Build will use EMSDK from current environment." )
529+
466530 dispatch = {
467531 "make-libffi" : make_emscripten_libffi ,
468532 "make-mpdec" : make_mpdec ,
0 commit comments