Skip to content

Commit b194688

Browse files
miss-islingtonhoodmanefreakboy3742
authored
[3.14] gh-145219: Add Emscripten cross-build and clean configurability (GH-145581) (#145654)
Modifies the Emscripten build script to allow for custom cross-build directory names, and to only clean Emscripten-specific paths (optionally including the build python). (cherry picked from commit 0156133) Co-authored-by: Hood Chatham <roberthoodchatham@gmail.com> Co-authored-by: Russell Keith-Magee <russell@keith-magee.com>
1 parent d910638 commit b194688

File tree

2 files changed

+77
-28
lines changed

2 files changed

+77
-28
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ Tools/unicode/data/
135135
/config.status
136136
/config.status.lineno
137137
/.ccache
138-
/cross-build/
138+
/cross-build*/
139139
/jit_stencils*.h
140140
/platform
141141
/profile-clean-stamp

Tools/wasm/emscripten/__main__.py

Lines changed: 76 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,25 @@
2424
CHECKOUT = EMSCRIPTEN_DIR.parent.parent.parent
2525
EMSCRIPTEN_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"
2928
HOST_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

3647
LOCAL_SETUP = CHECKOUT / "Modules" / "Setup.local"
3748
LOCAL_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)
194211
def 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")
210227
def 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)
245262
def 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)
263282
def 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)
293312
def 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")
407427
def 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

433453
def 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

Comments
 (0)