diff --git a/README.md b/README.md index c98222e..1eb3182 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ https://emscripten.org/docs/building_from_source/toolchain_what_is_needed.html. ### Linux -- `python`: Version 3.9.2 or above. +- `python`: Version 3.8 or above. - `java`: For running closure compiler (optional) The emsdk pre-compiled binaries are built against Ubuntu/Focal 20.04 LTS and diff --git a/bazel/MODULE.bazel b/bazel/MODULE.bazel index 5240178..4e3291d 100644 --- a/bazel/MODULE.bazel +++ b/bazel/MODULE.bazel @@ -1,6 +1,6 @@ module( name = "emsdk", - version = "4.0.9", + version = "4.0.11", ) bazel_dep(name = "platforms", version = "0.0.11") diff --git a/bazel/emscripten_toolchain/toolchain.bzl b/bazel/emscripten_toolchain/toolchain.bzl index ae2939f..070e3e0 100644 --- a/bazel/emscripten_toolchain/toolchain.bzl +++ b/bazel/emscripten_toolchain/toolchain.bzl @@ -363,6 +363,9 @@ def _impl(ctx): # Set if enabling exceptions. feature(name = "exceptions"), + # Set if enabling wasm_exceptions. + feature(name = "wasm_exceptions"), + # This feature overrides the default optimization to prefer execution speed # over binary size (like clang -O3). feature( @@ -515,7 +518,7 @@ def _impl(ctx): flags = [ "-fno-exceptions", ], - not_features = ["exceptions"], + not_features = ["exceptions", "wasm_exceptions"], ), flag_set( actions = all_cpp_compile_actions, @@ -524,6 +527,14 @@ def _impl(ctx): ], features = ["exceptions"], ), + flag_set( + actions = all_cpp_compile_actions + + all_link_actions, + flags = [ + "-fwasm-exceptions", + ], + features = ["wasm_exceptions"], + ), # All compiles (and implicitly link) flag_set( actions = all_compile_actions + diff --git a/bazel/revisions.bzl b/bazel/revisions.bzl index e954235..3fdd54c 100644 --- a/bazel/revisions.bzl +++ b/bazel/revisions.bzl @@ -2,6 +2,22 @@ # DO NOT MODIFY EMSCRIPTEN_TAGS = { + "4.0.11": struct( + hash = "7033fec38817ec01909b044ea0193ddd5057255c", + sha_linux = "f38e70b53be587e7c757f375b3452e259c70130d4b40db3213c95b7ae321f5d7", + sha_linux_arm64 = "42020e4db200ac366a3e91ac2fccc04ee0ffc090cd2d5986c892b27f39172bb9", + sha_mac = "4169811f9682f54ae5c9d0662d0a4dd4318abab5d3d0473fa54007f515a8cdea", + sha_mac_arm64 = "09554371e3941306d047d67618532e5366ba6c9b5bda1a504a917bfbabc5d414", + sha_win = "bd2094ca9bde5df25020a46ece7f56b622d1d22214fbd12950b01b952dd40084", + ), + "4.0.10": struct( + hash = "8103ffedfb0c42d231c6af6859a5a1a832260b43", + sha_linux = "0183f887b56c3f8d4b45826cb49856a3324afb66236ad3c13944c0fd2550cbbc", + sha_linux_arm64 = "0679f459118d80163d0712b0abda00cbc97a90cddf1dcefa9efb1bf89f67baed", + sha_mac = "02f3179f703b4d196a679897b430c1eeeb1d5f9aeba9b435b04ba3f526f7e8e0", + sha_mac_arm64 = "c744ffe06ffed55cd8dae42862b7646f15550c7decd47a48d09a474af83732b0", + sha_win = "1a66825e85fda039f57d39c98ae2bdb96a18e53745159e9599f69679be18439f", + ), "4.0.9": struct( hash = "cb2a69bce627bd2247624c71fc12907cb8785d2f", sha_linux = "c6fd245138e6bbdd8349963cb4045c557d657e4be0ea44155375633c689c8be9", diff --git a/bazel/test_secondary_lto_cache/MODULE.bazel b/bazel/test_secondary_lto_cache/MODULE.bazel index 0fabdc8..0f5d9dc 100644 --- a/bazel/test_secondary_lto_cache/MODULE.bazel +++ b/bazel/test_secondary_lto_cache/MODULE.bazel @@ -19,6 +19,7 @@ emscripten_cache.targets(targets = [ "libdlmalloc", "libcompiler_rt", "libc++-noexcept", + "libc++-debug-noexcept", "libc++abi-debug-noexcept", "libsockets", "libdlmalloc-debug", diff --git a/docker/Dockerfile b/docker/Dockerfile index 4e4667e..2c63a4a 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -63,7 +63,7 @@ COPY --from=stage_build /emsdk /emsdk # using `--entrypoint /bin/bash` in CLI). # This corresponds to the env variables set during: `source ./emsdk_env.sh` ENV EMSDK=/emsdk \ - PATH="/emsdk:/emsdk/upstream/emscripten:/emsdk/node/20.18.0_64bit/bin:${PATH}" + PATH="/emsdk:/emsdk/upstream/emscripten:/emsdk/node/22.16.0_64bit/bin:${PATH}" # ------------------------------------------------------------------------------ # Create a 'standard` 1000:1000 user diff --git a/emscripten-releases-tags.json b/emscripten-releases-tags.json index 012fe41..f5f2942 100644 --- a/emscripten-releases-tags.json +++ b/emscripten-releases-tags.json @@ -1,6 +1,6 @@ { "aliases": { - "latest": "4.0.9", + "latest": "4.0.11", "latest-sdk": "latest", "latest-arm64-linux": "latest", "latest-64bit": "latest", @@ -10,6 +10,10 @@ "latest-releases-upstream": "latest" }, "releases": { + "4.0.11": "7033fec38817ec01909b044ea0193ddd5057255c", + "4.0.11-asserts": "0eacb0d6", + "4.0.10": "8103ffedfb0c42d231c6af6859a5a1a832260b43", + "4.0.10-asserts": "ccf48a673362f11ddb6c3656405bb6a03b344052", "4.0.9": "cb2a69bce627bd2247624c71fc12907cb8785d2f", "4.0.9-asserts": "27f1e0801c6ec5ea4d9a9e1d573eb1fead3525f1", "4.0.8": "56f86607aeb458086e72f23188789be2ee0e971a", diff --git a/emsdk b/emsdk index 78c0288..7bf84c7 100755 --- a/emsdk +++ b/emsdk @@ -8,7 +8,10 @@ # First look for python bundled in Emsdk if [ -z "$EMSDK_PYTHON" ]; then - PYTHON3="$(dirname "$0")/python/3.9.2-1_64bit/bin/python3" + PYTHON3="$(dirname "$0")/python/3.13.3_64bit/bin/python3" + if [ ! -f "$PYTHON3" ]; then + PYTHON3="$(dirname "$0")/python/3.9.2_64bit/bin/python3" + fi if [ -f "$PYTHON3" ]; then EMSDK_PYTHON="$PYTHON3" diff --git a/emsdk.bat b/emsdk.bat index d0c599d..6f5b33a 100644 --- a/emsdk.bat +++ b/emsdk.bat @@ -7,8 +7,16 @@ setlocal :: When using our bundled python we never want the users :: PYTHONHOME or PYTHONPATH :: https://github.com/emscripten-core/emsdk/issues/598 -if exist "%~dp0python\3.9.2-1_64bit\python.exe" ( - set EMSDK_PY="%~dp0python\3.9.2-1_64bit\python.exe" + +if exist "%~dp0python\3.13.3_64bit\python.exe" ( + set EMSDK_PY="%~dp0python\3.13.3_64bit\python.exe" + set PYTHONHOME= + set PYTHONPATH= + goto end +) + +if exist "%~dp0python\3.9.2_64bit\python.exe" ( + set EMSDK_PY="%~dp0python\3.9.2_64bit\python.exe" set PYTHONHOME= set PYTHONPATH= goto end diff --git a/emsdk.ps1 b/emsdk.ps1 index e9e6008..81b798a 100644 --- a/emsdk.ps1 +++ b/emsdk.ps1 @@ -1,6 +1,7 @@ $ScriptDirectory = Split-Path -parent $PSCommandPath $PythonLocations = $( + "python\3.13.3-0_64bit\python.exe", "python\3.9.2-1_64bit\python.exe", "python\3.9.2-nuget_64bit\python.exe" ) diff --git a/emsdk.py b/emsdk.py index f01ebf5..22c0838 100644 --- a/emsdk.py +++ b/emsdk.py @@ -143,11 +143,7 @@ if machine.startswith('x64') or machine.startswith('amd64') or machine.startswit elif machine.endswith('86'): ARCH = 'x86' elif machine.startswith('aarch64') or machine.lower().startswith('arm64'): - if WINDOWS: - errlog('No support for Windows on Arm, fallback to x64') - ARCH = 'x86_64' - else: - ARCH = 'arm64' + ARCH = 'arm64' elif machine.startswith('arm'): ARCH = 'arm' else: @@ -988,17 +984,16 @@ def cmake_configure(generator, build_root, src_root, build_type, extra_cmake_arg generator = [] cmdline = ['cmake'] + generator + ['-DCMAKE_BUILD_TYPE=' + build_type, '-DPYTHON_EXECUTABLE=' + sys.executable] - # Target macOS 10.14 at minimum, to support widest range of Mac devices - # from "Early 2008" and newer: - # https://en.wikipedia.org/wiki/MacBook_(2006-2012)#Supported_operating_systems - cmdline += ['-DCMAKE_OSX_DEPLOYMENT_TARGET=10.14'] + # Target macOS 11.0 Big Sur at minimum, to support older Mac devices. + # See https://en.wikipedia.org/wiki/MacOS#Hardware_compatibility for min-spec details. + cmdline += ['-DCMAKE_OSX_DEPLOYMENT_TARGET=11.0'] cmdline += extra_cmake_args + [src_root] print('Running CMake: ' + str(cmdline)) # Specify the deployment target also as an env. var, since some Xcode versions # read this instead of the CMake field. - os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.14' + os.environ['MACOSX_DEPLOYMENT_TARGET'] = '11.0' def quote_parens(x): if ' ' in x: diff --git a/emsdk_manifest.json b/emsdk_manifest.json index fd43f59..1d05304 100644 --- a/emsdk_manifest.json +++ b/emsdk_manifest.json @@ -156,6 +156,56 @@ }, + { + "id": "node", + "version": "22.16.0", + "bitness": 32, + "arch": "x86", + "windows_url": "node-v22.16.0-win-x86.zip", + "activated_path": "%installation_dir%/bin", + "activated_path_skip": "node", + "activated_cfg": "NODE_JS='%installation_dir%/bin/node%.exe%'", + "activated_env": "EMSDK_NODE=%installation_dir%/bin/node%.exe%" + }, + { + "id": "node", + "version": "22.16.0", + "arch": "arm", + "bitness": 32, + "linux_url": "node-v22.16.0-linux-armv7l.tar.xz", + "activated_path": "%installation_dir%/bin", + "activated_path_skip": "node", + "activated_cfg": "NODE_JS='%installation_dir%/bin/node%.exe%'", + "activated_env": "EMSDK_NODE=%installation_dir%/bin/node%.exe%" + }, + { + "id": "node", + "version": "22.16.0", + "bitness": 64, + "arch": "x86_64", + "windows_url": "node-v22.16.0-win-x64.zip", + "macos_url": "node-v22.16.0-darwin-x64.tar.gz", + "linux_url": "node-v22.16.0-linux-x64.tar.xz", + "activated_path": "%installation_dir%/bin", + "activated_path_skip": "node", + "activated_cfg": "NODE_JS='%installation_dir%/bin/node%.exe%'", + "activated_env": "EMSDK_NODE=%installation_dir%/bin/node%.exe%" + }, + { + "id": "node", + "version": "22.16.0", + "arch": "arm64", + "bitness": 64, + "windows_url": "node-v22.16.0-win-arm64.zip", + "macos_url": "node-v22.16.0-darwin-arm64.tar.gz", + "linux_url": "node-v22.16.0-linux-arm64.tar.xz", + "activated_path": "%installation_dir%/bin", + "activated_path_skip": "node", + "activated_cfg": "NODE_JS='%installation_dir%/bin/node%.exe%'", + "activated_env": "EMSDK_NODE=%installation_dir%/bin/node%.exe%" + }, + + { "id": "python", "version": "3.9.2-nuget", @@ -192,6 +242,44 @@ "activated_cfg": "PYTHON='%installation_dir%/bin/python3'", "activated_env": "EMSDK_PYTHON=%installation_dir%/bin/python3;SSL_CERT_FILE=%installation_dir%/lib/python3.9/site-packages/certifi/cacert.pem" }, + + { + "id": "python", + "version": "3.13.3", + "bitness": 64, + "arch": "x86_64", + "windows_url": "python-3.13.3-0-win-amd64.zip", + "activated_cfg": "PYTHON='%installation_dir%/python.exe'", + "activated_env": "EMSDK_PYTHON=%installation_dir%/python.exe" + }, + { + "id": "python", + "version": "3.13.3", + "bitness": 64, + "arch": "arm64", + "windows_url": "python-3.13.3-0-win-arm64.zip", + "activated_cfg": "PYTHON='%installation_dir%/python.exe'", + "activated_env": "EMSDK_PYTHON=%installation_dir%/python.exe" + }, + { + "id": "python", + "version": "3.13.3", + "bitness": 64, + "arch": "x86_64", + "macos_url": "python-3.13.3-0-macos-x86_64.tar.gz", + "activated_cfg": "PYTHON='%installation_dir%/bin/python3'", + "activated_env": "EMSDK_PYTHON=%installation_dir%/bin/python3;SSL_CERT_FILE=%installation_dir%/lib/python3.13/site-packages/certifi/cacert.pem" + }, + { + "id": "python", + "version": "3.13.3", + "bitness": 64, + "arch": "arm64", + "macos_url": "python-3.13.3-0-macos-arm64.tar.gz", + "activated_cfg": "PYTHON='%installation_dir%/bin/python3'", + "activated_env": "EMSDK_PYTHON=%installation_dir%/bin/python3;SSL_CERT_FILE=%installation_dir%/lib/python3.13/site-packages/certifi/cacert.pem" + }, + { "id": "emscripten", "version": "tag-%tag%", @@ -350,19 +438,19 @@ { "version": "main", "bitness": 64, - "uses": ["python-3.9.2-nuget-64bit", "llvm-git-main-64bit", "node-20.18.0-64bit", "emscripten-main-64bit", "binaryen-main-64bit"], + "uses": ["python-3.13.3-64bit", "llvm-git-main-64bit", "node-22.16.0-64bit", "emscripten-main-64bit", "binaryen-main-64bit"], "os": "win" }, { "version": "main", "bitness": 64, - "uses": ["python-3.9.2-64bit", "llvm-git-main-64bit", "node-20.18.0-64bit", "emscripten-main-64bit", "binaryen-main-64bit"], + "uses": ["python-3.13.3-64bit", "llvm-git-main-64bit", "node-22.16.0-64bit", "emscripten-main-64bit", "binaryen-main-64bit"], "os": "macos" }, { "version": "main", "bitness": 64, - "uses": ["llvm-git-main-64bit", "node-20.18.0-64bit", "emscripten-main-64bit", "binaryen-main-64bit"], + "uses": ["llvm-git-main-64bit", "node-22.16.0-64bit", "emscripten-main-64bit", "binaryen-main-64bit"], "os": "linux" }, { @@ -374,14 +462,14 @@ { "version": "releases-%releases-tag%", "bitness": 64, - "uses": ["node-20.18.0-64bit", "releases-%releases-tag%-64bit"], + "uses": ["node-22.16.0-64bit", "releases-%releases-tag%-64bit"], "os": "linux", "custom_install_script": "emscripten_npm_install" }, { "version": "releases-%releases-tag%", "bitness": 64, - "uses": ["node-20.18.0-64bit", "python-3.9.2-64bit", "releases-%releases-tag%-64bit"], + "uses": ["node-22.16.0-64bit", "python-3.13.3-64bit", "releases-%releases-tag%-64bit"], "os": "macos", "arch": "x86_64", "custom_install_script": "emscripten_npm_install" @@ -389,7 +477,7 @@ { "version": "releases-%releases-tag%", "bitness": 64, - "uses": ["node-20.18.0-64bit", "python-3.9.2-64bit", "releases-%releases-tag%-64bit"], + "uses": ["node-22.16.0-64bit", "python-3.13.3-64bit", "releases-%releases-tag%-64bit"], "os": "macos", "arch": "arm64", "custom_install_script": "emscripten_npm_install" @@ -397,7 +485,7 @@ { "version": "releases-%releases-tag%", "bitness": 64, - "uses": ["node-20.18.0-64bit", "python-3.9.2-nuget-64bit", "releases-%releases-tag%-64bit"], + "uses": ["node-22.16.0-64bit", "python-3.13.3-64bit", "releases-%releases-tag%-64bit"], "os": "win", "custom_install_script": "emscripten_npm_install" } diff --git a/scripts/update_node.py b/scripts/update_node.py index 774c38a..722b6ff 100755 --- a/scripts/update_node.py +++ b/scripts/update_node.py @@ -18,8 +18,8 @@ import os import shutil from zip import unzip_cmd, zip_cmd -version = '20.18.0' -base = 'https://nodejs.org/dist/v20.18.0/' +version = '22.16.0' +base = f'https://nodejs.org/dist/v{version}/' upload_base = 'gs://webassembly/emscripten-releases-builds/deps/' suffixes = [ diff --git a/scripts/update_python.py b/scripts/update_python.py index a37b701..98273f1 100755 --- a/scripts/update_python.py +++ b/scripts/update_python.py @@ -8,12 +8,13 @@ http://storage.google.com/webassembly. We only supply binaries for windows and macOS, but we do it very different ways for those two OSes. +On Linux, we depend on the system version of python. Windows recipe: - 1. Download the "embeddable zip file" version of python from python.org - 2. Remove .pth file to work around https://bugs.python.org/issue34841 - 3. Download and install pywin32 in the `site-packages` directory - 4. Re-zip and upload to storage.google.com + 1. Download precompiled version of python from NuGet package manager, + either the package "python" for AMD64, or "pythonarm64" for ARM64. + 2. Set up pip and install pywin32 and psutil via pip for emrun to work. + 3. Re-zip and upload to storage.google.com macOS recipe: 1. Clone cpython @@ -32,27 +33,35 @@ import sys from subprocess import check_call from zip import unzip_cmd, zip_cmd -version = '3.9.2' +version = '3.13.3' major_minor_version = '.'.join(version.split('.')[:2]) # e.g. '3.9.2' -> '3.9' -download_url = 'https://www.nuget.org/api/v2/package/python/%s' % version # This is not part of official Python version, but a repackaging number appended by emsdk # when a version of Python needs to be redownloaded. -revision = '4' +revision = '0' -pywin32_version = '227' -pywin32_base = 'https://github.com/mhammond/pywin32/releases/download/b%s/' % pywin32_version +PSUTIL = 'psutil==7.0.0' upload_base = 'gs://webassembly/emscripten-releases-builds/deps/' +# Detects whether current python interpreter architecture is ARM64 or AMD64 +# If running AMD64 python on an ARM64 Windows, this still intentionally returns AMD64 +def find_python_arch(): + import sysconfig + arch = sysconfig.get_platform().lower() + if 'amd64' in arch: + return 'amd64' + if 'arm64' in arch: + return 'arm64' + raise f'Unknown Python sysconfig platform "{arch}" (neither AMD64 or ARM64)' + + def make_python_patch(): - pywin32_filename = 'pywin32-%s.win-amd64-py%s.exe' % (pywin32_version, major_minor_version) - filename = 'python-%s-amd64.zip' % (version) - out_filename = 'python-%s-%s-amd64+pywin32.zip' % (version, revision) - if not os.path.exists(pywin32_filename): - url = pywin32_base + pywin32_filename - print('Downloading pywin32: ' + url) - urllib.request.urlretrieve(url, pywin32_filename) + python_arch = find_python_arch() + package_name = 'pythonarm64' if python_arch == 'arm64' else 'python' + download_url = f'https://www.nuget.org/api/v2/package/{package_name}/{version}' + filename = f'python-{version}-win-{python_arch}.zip' + out_filename = f'python-{version}-{revision}-win-{python_arch}.zip' if not os.path.exists(filename): print(f'Downloading python: {download_url} to {filename}') @@ -62,19 +71,17 @@ def make_python_patch(): check_call(unzip_cmd() + [os.path.abspath(filename)], cwd='python-nuget') os.remove(filename) - os.mkdir('pywin32') - rtn = subprocess.call(unzip_cmd() + [os.path.abspath(pywin32_filename)], cwd='pywin32') - assert rtn in [0, 1] + src_dir = os.path.join('python-nuget', 'tools') + python_exe = os.path.join(src_dir, 'python.exe') + check_call([python_exe, '-m', 'ensurepip', '--upgrade']) + check_call([python_exe, '-m', 'pip', 'install', 'pywin32==310', '--no-warn-script-location']) + check_call([python_exe, '-m', 'pip', 'install', PSUTIL]) - os.mkdir(os.path.join('python-nuget', 'lib')) - shutil.move(os.path.join('pywin32', 'PLATLIB'), os.path.join('python-nuget', 'toolss', 'Lib', 'site-packages')) - - check_call(zip_cmd() + [os.path.join('..', '..', out_filename), '.'], cwd='python-nuget/tools') + check_call(zip_cmd() + [os.path.join('..', '..', out_filename), '.'], cwd=src_dir) print('Created: %s' % out_filename) # cleanup if everything went fine shutil.rmtree('python-nuget') - shutil.rmtree('pywin32') if '--upload' in sys.argv: upload_url = upload_base + out_filename @@ -92,7 +99,7 @@ def build_python(): check_call(['brew', 'install', 'openssl', 'xz', 'pkg-config']) if platform.machine() == 'x86_64': prefix = '/usr/local' - min_macos_version = '10.11' + min_macos_version = '11.0' elif platform.machine() == 'arm64': prefix = '/opt/homebrew' min_macos_version = '11.0' @@ -113,7 +120,9 @@ def build_python(): osname = 'linux' src_dir = 'cpython' - if not os.path.exists(src_dir): + if os.path.exists(src_dir): + check_call(['git', 'fetch'], cwd=src_dir) + else: check_call(['git', 'clone', 'https://github.com/python/cpython']) check_call(['git', 'checkout', 'v' + version], cwd=src_dir) @@ -143,7 +152,7 @@ def build_python(): # Install psutil module. This is needed by emrun to track when browser # process quits. - check_call([pybin, pip, 'install', 'psutil']) + check_call([pybin, pip, 'install', PSUTIL]) dirname = 'python-%s-%s' % (version, revision) if os.path.isdir(dirname): diff --git a/test/test.py b/test/test.py index 6d57881..e835ebf 100755 --- a/test/test.py +++ b/test/test.py @@ -176,9 +176,9 @@ int main() { # Test the normal tools like node don't re-download on re-install print('another install must re-download') - checked_call_with_output(emsdk + ' uninstall node-20.18.0-64bit') - checked_call_with_output(emsdk + ' install node-20.18.0-64bit', expected='Downloading:', unexpected='already installed') - checked_call_with_output(emsdk + ' install node-20.18.0-64bit', unexpected='Downloading:', expected='already installed') + checked_call_with_output(emsdk + ' uninstall node-22.16.0-64bit') + checked_call_with_output(emsdk + ' install node-22.16.0-64bit', expected='Downloading:', unexpected='already installed') + checked_call_with_output(emsdk + ' install node-22.16.0-64bit', unexpected='Downloading:', expected='already installed') def test_tot_upstream(self): print('test update-tags')