2424CHECKOUT = EMSCRIPTEN_DIR .parent .parent .parent
2525EMSCRIPTEN_VERSION_FILE = EMSCRIPTEN_DIR / "emscripten_version.txt"
2626
27- CROSS_BUILD_DIR = CHECKOUT / "cross-build"
28- NATIVE_BUILD_DIR = CROSS_BUILD_DIR / "build"
27+ DEFAULT_CROSS_BUILD_DIR = CHECKOUT / "cross-build"
2928HOST_TRIPLE = "wasm32-emscripten"
3029
31- DOWNLOAD_DIR = CROSS_BUILD_DIR / HOST_TRIPLE / "build"
32- HOST_BUILD_DIR = CROSS_BUILD_DIR / HOST_TRIPLE / "build"
33- HOST_DIR = HOST_BUILD_DIR / "python"
34- PREFIX_DIR = CROSS_BUILD_DIR / HOST_TRIPLE / "prefix"
30+
31+ def get_build_paths (cross_build_dir = None ):
32+ """Compute all build paths from the given cross-build directory."""
33+ if cross_build_dir is None :
34+ cross_build_dir = DEFAULT_CROSS_BUILD_DIR
35+ cross_build_dir = Path (cross_build_dir ).absolute ()
36+ host_triple_dir = cross_build_dir / HOST_TRIPLE
37+ return {
38+ "cross_build_dir" : cross_build_dir ,
39+ "native_build_dir" : cross_build_dir / "build" ,
40+ "host_triple_dir" : host_triple_dir ,
41+ "host_build_dir" : host_triple_dir / "build" ,
42+ "host_dir" : host_triple_dir / "build" / "python" ,
43+ "prefix_dir" : host_triple_dir / "prefix" ,
44+ }
45+
3546
3647LOCAL_SETUP = CHECKOUT / "Modules" / "Setup.local"
3748LOCAL_SETUP_MARKER = b"# Generated by Tools/wasm/emscripten.py\n "
@@ -115,12 +126,17 @@ def updated_env(updates, emsdk_cache):
115126 return environment
116127
117128
118- def subdir (working_dir , * , clean_ok = False ):
119- """Decorator to change to a working directory."""
129+ def subdir (path_key , * , clean_ok = False ):
130+ """Decorator to change to a working directory.
131+
132+ path_key is a key into context.build_paths, used to resolve the working
133+ directory at call time.
134+ """
120135
121136 def decorator (func ):
122137 @functools .wraps (func )
123138 def wrapper (context ):
139+ working_dir = context .build_paths [path_key ]
124140 try :
125141 tput_output = subprocess .check_output (
126142 ["tput" , "cols" ], encoding = "utf-8"
@@ -177,20 +193,21 @@ def build_platform():
177193 return sysconfig .get_config_var ("BUILD_GNU_TYPE" )
178194
179195
180- def build_python_path ():
196+ def build_python_path (context ):
181197 """The path to the build Python binary."""
182- binary = NATIVE_BUILD_DIR / "python"
198+ native_build_dir = context .build_paths ["native_build_dir" ]
199+ binary = native_build_dir / "python"
183200 if not binary .is_file ():
184201 binary = binary .with_suffix (".exe" )
185202 if not binary .is_file ():
186203 raise FileNotFoundError (
187- f"Unable to find `python(.exe)` in { NATIVE_BUILD_DIR } "
204+ f"Unable to find `python(.exe)` in { native_build_dir } "
188205 )
189206
190207 return binary
191208
192209
193- @subdir (NATIVE_BUILD_DIR , clean_ok = True )
210+ @subdir ("native_build_dir" , clean_ok = True )
194211def configure_build_python (context , working_dir ):
195212 """Configure the build/host Python."""
196213 if LOCAL_SETUP .exists ():
@@ -206,12 +223,12 @@ def configure_build_python(context, working_dir):
206223 call (configure , quiet = context .quiet )
207224
208225
209- @subdir (NATIVE_BUILD_DIR )
226+ @subdir ("native_build_dir" )
210227def make_build_python (context , working_dir ):
211228 """Make/build the build Python."""
212229 call (["make" , "--jobs" , str (cpu_count ()), "all" ], quiet = context .quiet )
213230
214- binary = build_python_path ()
231+ binary = build_python_path (context )
215232 cmd = [
216233 binary ,
217234 "-c" ,
@@ -241,7 +258,7 @@ def download_and_unpack(working_dir: Path, url: str, expected_shasum: str):
241258 shutil .unpack_archive (tmp_file .name , working_dir )
242259
243260
244- @subdir (HOST_BUILD_DIR , clean_ok = True )
261+ @subdir ("host_build_dir" , clean_ok = True )
245262def make_emscripten_libffi (context , working_dir ):
246263 ver = "3.4.6"
247264 libffi_dir = working_dir / f"libffi-{ ver } "
@@ -253,13 +270,15 @@ def make_emscripten_libffi(context, working_dir):
253270 )
254271 call (
255272 [EMSCRIPTEN_DIR / "make_libffi.sh" ],
256- env = updated_env ({"PREFIX" : PREFIX_DIR }, context .emsdk_cache ),
273+ env = updated_env (
274+ {"PREFIX" : context .build_paths ["prefix_dir" ]}, context .emsdk_cache
275+ ),
257276 cwd = libffi_dir ,
258277 quiet = context .quiet ,
259278 )
260279
261280
262- @subdir (HOST_BUILD_DIR , clean_ok = True )
281+ @subdir ("host_build_dir" , clean_ok = True )
263282def make_mpdec (context , working_dir ):
264283 ver = "4.0.1"
265284 mpdec_dir = working_dir / f"mpdecimal-{ ver } "
@@ -275,7 +294,7 @@ def make_mpdec(context, working_dir):
275294 mpdec_dir / "configure" ,
276295 "CFLAGS=-fPIC" ,
277296 "--prefix" ,
278- PREFIX_DIR ,
297+ context . build_paths [ "prefix_dir" ] ,
279298 "--disable-shared" ,
280299 ],
281300 cwd = mpdec_dir ,
@@ -289,14 +308,15 @@ def make_mpdec(context, working_dir):
289308 )
290309
291310
292- @subdir (HOST_DIR , clean_ok = True )
311+ @subdir ("host_dir" , clean_ok = True )
293312def configure_emscripten_python (context , working_dir ):
294313 """Configure the emscripten/host build."""
314+ paths = context .build_paths
295315 config_site = os .fsdecode (EMSCRIPTEN_DIR / "config.site-wasm32-emscripten" )
296316
297317 emscripten_build_dir = working_dir .relative_to (CHECKOUT )
298318
299- python_build_dir = NATIVE_BUILD_DIR / "build"
319+ python_build_dir = paths [ "native_build_dir" ] / "build"
300320 lib_dirs = list (python_build_dir .glob ("lib.*" ))
301321 assert len (lib_dirs ) == 1 , (
302322 f"Expected a single lib.* directory in { python_build_dir } "
@@ -322,13 +342,13 @@ def configure_emscripten_python(context, working_dir):
322342 capture_output = True ,
323343 )
324344 host_runner = res .stdout .strip ()
325- pkg_config_path_dir = (PREFIX_DIR / "lib/pkgconfig/" ).resolve ()
345+ pkg_config_path_dir = (paths [ "prefix_dir" ] / "lib/pkgconfig/" ).resolve ()
326346 env_additions = {
327347 "CONFIG_SITE" : config_site ,
328348 "HOSTRUNNER" : host_runner ,
329349 "EM_PKG_CONFIG_PATH" : str (pkg_config_path_dir ),
330350 }
331- build_python = os .fsdecode (build_python_path ())
351+ build_python = os .fsdecode (build_python_path (context ))
332352 configure = [
333353 "emconfigure" ,
334354 os .path .relpath (CHECKOUT / "configure" , working_dir ),
@@ -342,7 +362,7 @@ def configure_emscripten_python(context, working_dir):
342362 "--disable-ipv6" ,
343363 "--enable-big-digits=30" ,
344364 "--enable-wasm-dynamic-linking" ,
345- f"--prefix={ PREFIX_DIR } " ,
365+ f"--prefix={ paths [ 'prefix_dir' ] } " ,
346366 ]
347367 if pydebug :
348368 configure .append ("--with-pydebug" )
@@ -403,7 +423,7 @@ def configure_emscripten_python(context, working_dir):
403423 sys .stdout .flush ()
404424
405425
406- @subdir (HOST_DIR )
426+ @subdir ("host_dir" )
407427def make_emscripten_python (context , working_dir ):
408428 """Run `make` for the emscripten/host build."""
409429 call (
@@ -432,9 +452,17 @@ def build_all(context):
432452
433453def clean_contents (context ):
434454 """Delete all files created by this script."""
435- if CROSS_BUILD_DIR .exists ():
436- print (f"🧹 Deleting { CROSS_BUILD_DIR } ..." )
437- shutil .rmtree (CROSS_BUILD_DIR )
455+ if context .target in {"all" , "build" }:
456+ build_dir = context .build_paths ["native_build_dir" ]
457+ if build_dir .exists ():
458+ print (f"🧹 Deleting { build_dir } ..." )
459+ shutil .rmtree (build_dir )
460+
461+ if context .target in {"all" , "host" }:
462+ host_triple_dir = context .build_paths ["host_triple_dir" ]
463+ if host_triple_dir .exists ():
464+ print (f"🧹 Deleting { host_triple_dir } ..." )
465+ shutil .rmtree (host_triple_dir )
438466
439467 if LOCAL_SETUP .exists ():
440468 with LOCAL_SETUP .open ("rb" ) as file :
@@ -472,6 +500,17 @@ def main():
472500 clean = subcommands .add_parser (
473501 "clean" , help = "Delete files and directories created by this script"
474502 )
503+ clean .add_argument (
504+ "target" ,
505+ nargs = "?" ,
506+ default = "host" ,
507+ choices = ["all" , "host" , "build" ],
508+ help = (
509+ "What should be cleaned. 'build' for just the build platform, or "
510+ "'host' for the host platform, or 'all' for both. Defaults to 'host'."
511+ ),
512+ )
513+
475514 for subcommand in (
476515 build ,
477516 configure_build ,
@@ -489,6 +528,14 @@ def main():
489528 dest = "quiet" ,
490529 help = "Redirect output from subprocesses to a log file" ,
491530 )
531+ subcommand .add_argument (
532+ "--cross-build-dir" ,
533+ action = "store" ,
534+ default = None ,
535+ dest = "cross_build_dir" ,
536+ help = "Path to the cross-build directory "
537+ f"(default: { DEFAULT_CROSS_BUILD_DIR } )" ,
538+ )
492539 subcommand .add_argument (
493540 "--emsdk-cache" ,
494541 action = "store" ,
@@ -521,6 +568,8 @@ def main():
521568
522569 context = parser .parse_args ()
523570
571+ context .build_paths = get_build_paths (context .cross_build_dir )
572+
524573 if context .emsdk_cache :
525574 validate_emsdk_version (context .emsdk_cache )
526575 context .emsdk_cache = Path (context .emsdk_cache ).absolute ()
0 commit comments