- name: Build and test
run: python3 Apple ci iOS --fast-ci --simulator 'iPhone SE (3rd generation),OS=17.5'
+ build-emscripten:
+ name: 'Emscripten'
+ needs: build-context
+ if: needs.build-context.outputs.run-emscripten == 'true'
+ uses: ./.github/workflows/reusable-emscripten.yml
+
build-wasi:
name: 'WASI'
needs: build-context
- build-ubuntu
- build-ubuntu-ssltests
- build-ios
+ - build-emscripten
- build-wasi
- test-hypothesis
- build-asan
with:
allowed-failures: >-
build-android,
+ build-emscripten,
build-windows-msi,
build-ubuntu-ssltests,
test-hypothesis,
}}
${{ !fromJSON(needs.build-context.outputs.run-android) && 'build-android,' || '' }}
${{ !fromJSON(needs.build-context.outputs.run-ios) && 'build-ios,' || '' }}
+ ${{ !fromJSON(needs.build-context.outputs.run-emscripten) && 'build-emscripten,' || '' }}
${{ !fromJSON(needs.build-context.outputs.run-wasi) && 'build-wasi,' || '' }}
jobs: ${{ toJSON(needs) }}
run-ubuntu:
description: Whether to run the Ubuntu tests
value: ${{ jobs.compute-changes.outputs.run-ubuntu }} # bool
+ run-emscripten:
+ description: Whether to run the Emscripten tests
+ value: ${{ jobs.compute-changes.outputs.run-emscripten }} # bool
run-wasi:
description: Whether to run the WASI tests
value: ${{ jobs.compute-changes.outputs.run-wasi }} # bool
run-macos: ${{ steps.changes.outputs.run-macos }}
run-tests: ${{ steps.changes.outputs.run-tests }}
run-ubuntu: ${{ steps.changes.outputs.run-ubuntu }}
+ run-emscripten: ${{ steps.changes.outputs.run-emscripten }}
run-wasi: ${{ steps.changes.outputs.run-wasi }}
run-windows-msi: ${{ steps.changes.outputs.run-windows-msi }}
run-windows-tests: ${{ steps.changes.outputs.run-windows-tests }}
--- /dev/null
+name: Reusable Emscripten
+
+on:
+ workflow_call:
+
+env:
+ FORCE_COLOR: 1
+
+jobs:
+ build-emscripten-reusable:
+ name: 'build and test'
+ runs-on: ubuntu-24.04
+ timeout-minutes: 60
+ steps:
+ - uses: actions/checkout@v6
+ with:
+ persist-credentials: false
+ - name: "Read Emscripten config"
+ id: emscripten-config
+ shell: python
+ run: |
+ import hashlib
+ import json
+ import os
+ import tomllib
+ from pathlib import Path
+
+ config = tomllib.loads(Path("Platforms/emscripten/config.toml").read_text())
+ h = hashlib.sha256()
+ h.update(json.dumps(config["dependencies"], sort_keys=True).encode())
+ h.update(Path("Platforms/emscripten/make_libffi.sh").read_bytes())
+ h.update(b'1') # Update to explicitly bust cache
+ emsdk_cache = Path(os.environ["RUNNER_TEMP"]) / "emsdk-cache"
+ with open(os.environ["GITHUB_OUTPUT"], "a") as f:
+ f.write(f"emscripten-version={config['emscripten-version']}\n")
+ f.write(f"node-version={config['node-version']}\n")
+ f.write(f"deps-hash={h.hexdigest()}\n")
+ with open(os.environ["GITHUB_ENV"], "a") as f:
+ f.write(f"EMSDK_CACHE={emsdk_cache}\n")
+ - name: "Install Node.js"
+ uses: actions/setup-node@v6
+ with:
+ node-version: ${{ steps.emscripten-config.outputs.node-version }}
+ - name: "Cache Emscripten SDK"
+ id: emsdk-cache
+ uses: actions/cache@v5
+ with:
+ path: ${{ env.EMSDK_CACHE }}
+ key: emsdk-${{ steps.emscripten-config.outputs.emscripten-version }}-${{ steps.emscripten-config.outputs.deps-hash }}
+ restore-keys: emsdk-${{ steps.emscripten-config.outputs.emscripten-version }}
+ - name: "Install Python"
+ uses: actions/setup-python@v6
+ with:
+ python-version: '3.x'
+ - name: "Runner image version"
+ run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
+ - name: "Install Emscripten"
+ run: python3 Platforms/emscripten install-emscripten
+ - name: "Configure build Python"
+ run: python3 Platforms/emscripten configure-build-python -- --config-cache --with-pydebug
+ - name: "Make build Python"
+ run: python3 Platforms/emscripten make-build-python
+ - name: "Make dependencies"
+ run: >-
+ python3 Platforms/emscripten make-dependencies
+ ${{ steps.emsdk-cache.outputs.cache-hit == 'true' && '--check-up-to-date' || '' }}
+ - name: "Configure host Python"
+ run: python3 Platforms/emscripten configure-host --host-runner node -- --config-cache
+ - name: "Make host Python"
+ run: python3 Platforms/emscripten make-host
+ - name: "Test"
+ run: python3 Platforms/emscripten run --test
def make_emscripten_libffi(context, working_dir):
validate_emsdk_version(context.emsdk_cache)
prefix = context.build_paths["prefix_dir"]
- libffi_config = load_config_toml()["libffi"]
+ libffi_config = load_config_toml()["dependencies"]["libffi"]
+ with open(EMSCRIPTEN_DIR / "make_libffi.sh", "rb") as f:
+ libffi_config["make_libffi_shasum"] = hashlib.file_digest(f, "sha256").hexdigest()
if not should_build_library(
prefix, "libffi", libffi_config, context.quiet
):
return
+
+ if context.check_up_to_date:
+ print("libffi out of date, expected to be up to date", file=sys.stderr)
+ sys.exit(1)
+
url = libffi_config["url"]
version = libffi_config["version"]
shasum = libffi_config["shasum"]
def make_mpdec(context, working_dir):
validate_emsdk_version(context.emsdk_cache)
prefix = context.build_paths["prefix_dir"]
- mpdec_config = load_config_toml()["mpdec"]
+ mpdec_config = load_config_toml()["dependencies"]["mpdec"]
if not should_build_library(prefix, "mpdec", mpdec_config, context.quiet):
return
+ if context.check_up_to_date:
+ print("libmpdec out of date, expected to be up to date", file=sys.stderr)
+ sys.exit(1)
+
url = mpdec_config["url"]
version = mpdec_config["version"]
shasum = mpdec_config["shasum"]
help="Build all static library dependencies",
)
+ for cmd in [make_mpdec_cmd, make_libffi_cmd, make_dependencies_cmd]:
+ cmd.add_argument(
+ "--check-up-to-date",
+ action="store_true",
+ default=False,
+ help=("If passed, will fail if dependency is out of date"),
+ )
+
make_build = subcommands.add_parser(
"make-build-python", help="Run `make` for the build Python"
)
help=(
"If passed, will add the default test arguments to the beginning of the command. "
"Default arguments loaded from Platforms/emscripten/config.toml"
- )
+ ),
)
run.add_argument(
"args",
help=(
"Arguments to pass to the emscripten Python "
"(use '--' to separate from run options)",
- )
+ ),
)
add_cross_build_dir_option(run)
"-W",
]
-[libffi]
+[dependencies.libffi]
url = "https://github.com/libffi/libffi/releases/download/v{version}/libffi-{version}.tar.gz"
version = "3.4.6"
shasum = "b0dea9df23c863a7a50e825440f3ebffabd65df1497108e5d437747843895a4e"
-[mpdec]
+[dependencies.mpdec]
url = "https://www.bytereef.org/software/mpdecimal/releases/mpdecimal-{version}.tar.gz"
version = "4.0.1"
shasum = "96d33abb4bb0070c7be0fed4246cd38416188325f820468214471938545b1ac8"
SUFFIXES_DOCUMENTATION = frozenset({".rst", ".md"})
ANDROID_DIRS = frozenset({"Android"})
+EMSCRIPTEN_DIRS = frozenset({Path("Platforms", "emscripten")})
IOS_DIRS = frozenset({"Apple", "iOS"})
MACOS_DIRS = frozenset({"Mac"})
WASI_DIRS = frozenset({Path("Platforms", "WASI")})
run_ci_fuzz: bool = False
run_ci_fuzz_stdlib: bool = False
run_docs: bool = False
+ run_emscripten: bool = False
run_ios: bool = False
run_macos: bool = False
run_tests: bool = False
# Otherwise, just run the tests
outputs = Outputs(
run_android=True,
+ run_emscripten=True,
run_ios=True,
run_macos=True,
run_tests=True,
return "ios"
if first_part in ANDROID_DIRS:
return "android"
+ if len(file.parts) >= 2 and Path(*file.parts[:2]) in EMSCRIPTEN_DIRS:
+ return "emscripten"
if len(file.parts) >= 2 and Path(*file.parts[:2]) in WASI_DIRS:
return "wasi"
return None
run_tests = True
platforms_changed.add("macos")
continue
+ if file.name == "reusable-emscripten.yml":
+ run_tests = True
+ platforms_changed.add("emscripten")
+ continue
if file.name == "reusable-wasi.yml":
run_tests = True
platforms_changed.add("wasi")
if run_tests:
if not has_platform_specific_change or not platforms_changed:
run_android = True
+ run_emscripten = True
run_ios = True
run_macos = True
run_ubuntu = True
run_wasi = True
else:
run_android = "android" in platforms_changed
+ run_emscripten = "emscripten" in platforms_changed
run_ios = "ios" in platforms_changed
run_macos = "macos" in platforms_changed
run_ubuntu = False
run_wasi = "wasi" in platforms_changed
else:
run_android = False
+ run_emscripten = False
run_ios = False
run_macos = False
run_ubuntu = False
run_ci_fuzz=run_ci_fuzz,
run_ci_fuzz_stdlib=run_ci_fuzz_stdlib,
run_docs=run_docs,
+ run_emscripten=run_emscripten,
run_ios=run_ios,
run_macos=run_macos,
run_tests=run_tests,