From 1f306e1e2966373ca0530aa2936affe6be715ac2 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Fri, 17 Jul 2026 19:55:23 -0700 Subject: [PATCH] Fix Pyodide wheel packaging for emscripten executable name variants (#10158) `build-pyodide` failed because Python packaging assumed the wasm shell artifact is always emitted as `build/z3.wasm`. In the failing run, the expected file was absent, causing wheel build to abort during binary copy. - **Root cause handling in `setup.py`** - In the emscripten path, add executable fallbacks (`z3.js.wasm`, `z3`) alongside the canonical `z3.wasm`. - During packaging, probe known output names in order and copy the first match. - **Stable wheel layout** - Keep packaged artifact name stable as `bin/z3.wasm` regardless of which build output variant exists. - **Failure diagnostics** - If no candidate exists, raise a `FileNotFoundError` listing all attempted paths to make CI failures immediately actionable. ```python executable_names = (EXECUTABLE_FILE,) + tuple(EXECUTABLE_FILE_FALLBACKS) for executable_name in executable_names: candidate = os.path.join(BUILD_DIR, executable_name) if os.path.exists(candidate): shutil.copy(candidate, os.path.join(BINS_DIR, EXECUTABLE_FILE)) break ``` --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> --- src/api/python/setup.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/api/python/setup.py b/src/api/python/setup.py index d02cd3978..28b6929e8 100644 --- a/src/api/python/setup.py +++ b/src/api/python/setup.py @@ -92,9 +92,13 @@ elif BUILD_PLATFORM in ('win32', 'cygwin', 'win'): elif BUILD_PLATFORM in ('emscripten',): LIBRARY_FILE = "libz3.so" EXECUTABLE_FILE = "z3.wasm" + # Depending on emscripten/toolchain details, the shell target can appear + # as z3.js.wasm or z3; package it consistently as z3.wasm. + EXECUTABLE_FILE_FALLBACKS = ["z3.js.wasm", "z3"] else: LIBRARY_FILE = "libz3.so" EXECUTABLE_FILE = "z3" + EXECUTABLE_FILE_FALLBACKS = [] # check if cmake is available, and pull it in via PyPI if necessary SETUP_REQUIRES = [] @@ -225,7 +229,17 @@ def _copy_bins(): os.mkdir(BINS_DIR) os.mkdir(HEADERS_DIR) shutil.copy(os.path.join(BUILD_DIR, LIBRARY_FILE), LIBS_DIR) - shutil.copy(os.path.join(BUILD_DIR, EXECUTABLE_FILE), BINS_DIR) + executable_src = None + executable_names = (EXECUTABLE_FILE,) + tuple(EXECUTABLE_FILE_FALLBACKS) + for executable_name in executable_names: + executable_src_candidate = os.path.join(BUILD_DIR, executable_name) + if os.path.exists(executable_src_candidate): + executable_src = executable_src_candidate + break + if executable_src is None: + attempted_files = "\n- ".join(os.path.join(BUILD_DIR, executable_name) for executable_name in executable_names) + raise FileNotFoundError(f"Could not find any executable in build directory. Tried:\n- {attempted_files}") + shutil.copy(executable_src, os.path.join(BINS_DIR, EXECUTABLE_FILE)) path1 = glob.glob(os.path.join(BUILD_DIR, "msvcp*")) path2 = glob.glob(os.path.join(BUILD_DIR, "vcomp*")) path3 = glob.glob(os.path.join(BUILD_DIR, "vcrun*"))