Skip to content

Commit d07c793

Browse files
authored
Update Python to 3.13.3 and add support to Windows on ARM64. (#1477)
Update Python to 3.13.0 and add support to Windows on AMD64. Rewrite packaging of pywin32 because it is no longer shipped via separate binary installers, but has migrated to use pip.
1 parent 3bcf1dc commit d07c793

File tree

7 files changed

+98
-44
lines changed

7 files changed

+98
-44
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ https://emscripten.org/docs/building_from_source/toolchain_what_is_needed.html.
6565

6666
### Linux
6767

68-
- `python`: Version 3.9.2 or above.
68+
- `python`: Version 3.9.2 or above. Version 3.13.3 or a newer 3.13.x is recommended.
6969
- `java`: For running closure compiler (optional)
7070

7171
The emsdk pre-compiled binaries are built against Ubuntu/Focal 20.04 LTS and

emsdk

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@
88

99
# First look for python bundled in Emsdk
1010
if [ -z "$EMSDK_PYTHON" ]; then
11-
PYTHON3="$(dirname "$0")/python/3.9.2-1_64bit/bin/python3"
11+
PYTHON3="$(dirname "$0")/python/3.13.3-0_64bit/bin/python3"
12+
if [ ! -f "$PYTHON3" ]; then
13+
PYTHON3="$(dirname "$0")/python/3.9.2-1_64bit/bin/python3"
14+
fi
1215
if [ -f "$PYTHON3" ]; then
1316
EMSDK_PYTHON="$PYTHON3"
1417

emsdk.bat

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@ setlocal
77
:: When using our bundled python we never want the users
88
:: PYTHONHOME or PYTHONPATH
99
:: https://github.com/emscripten-core/emsdk/issues/598
10+
11+
if exist "%~dp0python\3.13.3-0_64bit\python.exe" (
12+
set EMSDK_PY="%~dp0python\3.13.3-0_64bit\python.exe"
13+
set PYTHONHOME=
14+
set PYTHONPATH=
15+
goto end
16+
)
17+
1018
if exist "%~dp0python\3.9.2-1_64bit\python.exe" (
1119
set EMSDK_PY="%~dp0python\3.9.2-1_64bit\python.exe"
1220
set PYTHONHOME=

emsdk.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
$ScriptDirectory = Split-Path -parent $PSCommandPath
22

33
$PythonLocations = $(
4+
"python\3.13.3-0_64bit\python.exe",
45
"python\3.9.2-1_64bit\python.exe",
56
"python\3.9.2-nuget_64bit\python.exe"
67
)

emsdk.py

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,7 @@ def exit_with_error(msg):
143143
elif machine.endswith('86'):
144144
ARCH = 'x86'
145145
elif machine.startswith('aarch64') or machine.lower().startswith('arm64'):
146-
if WINDOWS:
147-
errlog('No support for Windows on Arm, fallback to x64')
148-
ARCH = 'x86_64'
149-
else:
150-
ARCH = 'arm64'
146+
ARCH = 'arm64'
151147
elif machine.startswith('arm'):
152148
ARCH = 'arm'
153149
else:
@@ -988,17 +984,16 @@ def cmake_configure(generator, build_root, src_root, build_type, extra_cmake_arg
988984
generator = []
989985

990986
cmdline = ['cmake'] + generator + ['-DCMAKE_BUILD_TYPE=' + build_type, '-DPYTHON_EXECUTABLE=' + sys.executable]
991-
# Target macOS 10.14 at minimum, to support widest range of Mac devices
992-
# from "Early 2008" and newer:
993-
# https://en.wikipedia.org/wiki/MacBook_(2006-2012)#Supported_operating_systems
994-
cmdline += ['-DCMAKE_OSX_DEPLOYMENT_TARGET=10.14']
987+
# Target macOS 11.0 Big Sur at minimum, to support older Mac devices.
988+
# See https://en.wikipedia.org/wiki/MacOS#Hardware_compatibility for min-spec details.
989+
cmdline += ['-DCMAKE_OSX_DEPLOYMENT_TARGET=11.0']
995990
cmdline += extra_cmake_args + [src_root]
996991

997992
print('Running CMake: ' + str(cmdline))
998993

999994
# Specify the deployment target also as an env. var, since some Xcode versions
1000995
# read this instead of the CMake field.
1001-
os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.14'
996+
os.environ['MACOSX_DEPLOYMENT_TARGET'] = '11.0'
1002997

1003998
def quote_parens(x):
1004999
if ' ' in x:

emsdk_manifest.json

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,44 @@
192192
"activated_cfg": "PYTHON='%installation_dir%/bin/python3'",
193193
"activated_env": "EMSDK_PYTHON=%installation_dir%/bin/python3;SSL_CERT_FILE=%installation_dir%/lib/python3.9/site-packages/certifi/cacert.pem"
194194
},
195+
196+
{
197+
"id": "python",
198+
"version": "3.13.3",
199+
"bitness": 64,
200+
"arch": "x86_64",
201+
"windows_url": "python-3.13.3-0-win-amd64.zip",
202+
"activated_cfg": "PYTHON='%installation_dir%/python.exe'",
203+
"activated_env": "EMSDK_PYTHON=%installation_dir%/python.exe"
204+
},
205+
{
206+
"id": "python",
207+
"version": "3.13.3",
208+
"bitness": 64,
209+
"arch": "arm64",
210+
"windows_url": "python-3.13.3-0-win-arm64.zip",
211+
"activated_cfg": "PYTHON='%installation_dir%/python.exe'",
212+
"activated_env": "EMSDK_PYTHON=%installation_dir%/python.exe"
213+
},
214+
{
215+
"id": "python",
216+
"version": "3.13.3",
217+
"bitness": 64,
218+
"arch": "x86_64",
219+
"macos_url": "python-3.13.3-0-macos-x86_64.tar.gz",
220+
"activated_cfg": "PYTHON='%installation_dir%/bin/python3'",
221+
"activated_env": "EMSDK_PYTHON=%installation_dir%/bin/python3;SSL_CERT_FILE=%installation_dir%/lib/python3.13/site-packages/certifi/cacert.pem"
222+
},
223+
{
224+
"id": "python",
225+
"version": "3.13.3",
226+
"bitness": 64,
227+
"arch": "arm64",
228+
"macos_url": "python-3.13.3-0-macos-arm64.tar.gz",
229+
"activated_cfg": "PYTHON='%installation_dir%/bin/python3'",
230+
"activated_env": "EMSDK_PYTHON=%installation_dir%/bin/python3;SSL_CERT_FILE=%installation_dir%/lib/python3.13/site-packages/certifi/cacert.pem"
231+
},
232+
195233
{
196234
"id": "emscripten",
197235
"version": "tag-%tag%",
@@ -350,13 +388,13 @@
350388
{
351389
"version": "main",
352390
"bitness": 64,
353-
"uses": ["python-3.9.2-nuget-64bit", "llvm-git-main-64bit", "node-20.18.0-64bit", "emscripten-main-64bit", "binaryen-main-64bit"],
391+
"uses": ["python-3.13.3-64bit", "llvm-git-main-64bit", "node-20.18.0-64bit", "emscripten-main-64bit", "binaryen-main-64bit"],
354392
"os": "win"
355393
},
356394
{
357395
"version": "main",
358396
"bitness": 64,
359-
"uses": ["python-3.9.2-64bit", "llvm-git-main-64bit", "node-20.18.0-64bit", "emscripten-main-64bit", "binaryen-main-64bit"],
397+
"uses": ["python-3.13.3-64bit", "llvm-git-main-64bit", "node-20.18.0-64bit", "emscripten-main-64bit", "binaryen-main-64bit"],
360398
"os": "macos"
361399
},
362400
{
@@ -381,23 +419,23 @@
381419
{
382420
"version": "releases-%releases-tag%",
383421
"bitness": 64,
384-
"uses": ["node-20.18.0-64bit", "python-3.9.2-64bit", "releases-%releases-tag%-64bit"],
422+
"uses": ["node-20.18.0-64bit", "python-3.13.3-64bit", "releases-%releases-tag%-64bit"],
385423
"os": "macos",
386424
"arch": "x86_64",
387425
"custom_install_script": "emscripten_npm_install"
388426
},
389427
{
390428
"version": "releases-%releases-tag%",
391429
"bitness": 64,
392-
"uses": ["node-20.18.0-64bit", "python-3.9.2-64bit", "releases-%releases-tag%-64bit"],
430+
"uses": ["node-20.18.0-64bit", "python-3.13.3-64bit", "releases-%releases-tag%-64bit"],
393431
"os": "macos",
394432
"arch": "arm64",
395433
"custom_install_script": "emscripten_npm_install"
396434
},
397435
{
398436
"version": "releases-%releases-tag%",
399437
"bitness": 64,
400-
"uses": ["node-20.18.0-64bit", "python-3.9.2-nuget-64bit", "releases-%releases-tag%-64bit"],
438+
"uses": ["node-20.18.0-64bit", "python-3.13.3-64bit", "releases-%releases-tag%-64bit"],
401439
"os": "win",
402440
"custom_install_script": "emscripten_npm_install"
403441
}

scripts/update_python.py

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@
88
http://storage.google.com/webassembly.
99
1010
We only supply binaries for windows and macOS, but we do it very different ways for those two OSes.
11+
On Linux, we depend on the system version of python.
1112
1213
Windows recipe:
13-
1. Download the "embeddable zip file" version of python from python.org
14-
2. Remove .pth file to work around https://bugs.python.org/issue34841
15-
3. Download and install pywin32 in the `site-packages` directory
16-
4. Re-zip and upload to storage.google.com
14+
1. Download precompiled version of python from NuGet package manager,
15+
either the package "python" for AMD64, or "pythonarm64" for ARM64.
16+
2. Set up pip and install pywin32 and psutil via pip for emrun to work.
17+
3. Re-zip and upload to storage.google.com
1718
1819
macOS recipe:
1920
1. Clone cpython
@@ -32,27 +33,35 @@
3233
from subprocess import check_call
3334
from zip import unzip_cmd, zip_cmd
3435

35-
version = '3.9.2'
36+
version = '3.13.3'
3637
major_minor_version = '.'.join(version.split('.')[:2]) # e.g. '3.9.2' -> '3.9'
37-
download_url = 'https://www.nuget.org/api/v2/package/python/%s' % version
3838
# This is not part of official Python version, but a repackaging number appended by emsdk
3939
# when a version of Python needs to be redownloaded.
40-
revision = '4'
40+
revision = '0'
4141

42-
pywin32_version = '227'
43-
pywin32_base = 'https://github.com/mhammond/pywin32/releases/download/b%s/' % pywin32_version
42+
PSUTIL = 'psutil==7.0.0'
4443

4544
upload_base = 'gs://webassembly/emscripten-releases-builds/deps/'
4645

4746

47+
# Detects whether current python interpreter architecture is ARM64 or AMD64
48+
# If running AMD64 python on an ARM64 Windows, this still intentionally returns AMD64
49+
def find_python_arch():
50+
import sysconfig
51+
arch = sysconfig.get_platform().lower()
52+
if 'amd64' in arch:
53+
return 'amd64'
54+
if 'arm64' in arch:
55+
return 'arm64'
56+
raise f'Unknown Python sysconfig platform "{arch}" (neither AMD64 or ARM64)'
57+
58+
4859
def make_python_patch():
49-
pywin32_filename = 'pywin32-%s.win-amd64-py%s.exe' % (pywin32_version, major_minor_version)
50-
filename = 'python-%s-amd64.zip' % (version)
51-
out_filename = 'python-%s-%s-amd64+pywin32.zip' % (version, revision)
52-
if not os.path.exists(pywin32_filename):
53-
url = pywin32_base + pywin32_filename
54-
print('Downloading pywin32: ' + url)
55-
urllib.request.urlretrieve(url, pywin32_filename)
60+
python_arch = find_python_arch()
61+
package_name = 'pythonarm64' if python_arch == 'arm64' else 'python'
62+
download_url = f'https://www.nuget.org/api/v2/package/{package_name}/{version}'
63+
filename = f'python-{version}-win-{python_arch}.zip'
64+
out_filename = f'python-{version}-{revision}-win-{python_arch}.zip'
5665

5766
if not os.path.exists(filename):
5867
print(f'Downloading python: {download_url} to {filename}')
@@ -62,19 +71,17 @@ def make_python_patch():
6271
check_call(unzip_cmd() + [os.path.abspath(filename)], cwd='python-nuget')
6372
os.remove(filename)
6473

65-
os.mkdir('pywin32')
66-
rtn = subprocess.call(unzip_cmd() + [os.path.abspath(pywin32_filename)], cwd='pywin32')
67-
assert rtn in [0, 1]
68-
69-
os.mkdir(os.path.join('python-nuget', 'lib'))
70-
shutil.move(os.path.join('pywin32', 'PLATLIB'), os.path.join('python-nuget', 'toolss', 'Lib', 'site-packages'))
74+
src_dir = os.path.join('python-nuget', 'tools')
75+
python_exe = os.path.join(src_dir, 'python.exe')
76+
check_call([python_exe, '-m', 'ensurepip', '--upgrade'])
77+
check_call([python_exe, '-m', 'pip', 'install', 'pywin32==310', '--no-warn-script-location'])
78+
check_call([python_exe, '-m', 'pip', 'install', PSUTIL])
7179

72-
check_call(zip_cmd() + [os.path.join('..', '..', out_filename), '.'], cwd='python-nuget/tools')
80+
check_call(zip_cmd() + [os.path.join('..', '..', out_filename), '.'], cwd=src_dir)
7381
print('Created: %s' % out_filename)
7482

7583
# cleanup if everything went fine
7684
shutil.rmtree('python-nuget')
77-
shutil.rmtree('pywin32')
7885

7986
if '--upload' in sys.argv:
8087
upload_url = upload_base + out_filename
@@ -92,7 +99,7 @@ def build_python():
9299
check_call(['brew', 'install', 'openssl', 'xz', 'pkg-config'])
93100
if platform.machine() == 'x86_64':
94101
prefix = '/usr/local'
95-
min_macos_version = '10.11'
102+
min_macos_version = '11.0'
96103
elif platform.machine() == 'arm64':
97104
prefix = '/opt/homebrew'
98105
min_macos_version = '11.0'
@@ -113,7 +120,9 @@ def build_python():
113120
osname = 'linux'
114121

115122
src_dir = 'cpython'
116-
if not os.path.exists(src_dir):
123+
if os.path.exists(src_dir):
124+
check_call(['git', 'fetch'], cwd=src_dir)
125+
else:
117126
check_call(['git', 'clone', 'https://github.com/python/cpython'])
118127
check_call(['git', 'checkout', 'v' + version], cwd=src_dir)
119128

@@ -143,7 +152,7 @@ def build_python():
143152

144153
# Install psutil module. This is needed by emrun to track when browser
145154
# process quits.
146-
check_call([pybin, pip, 'install', 'psutil'])
155+
check_call([pybin, pip, 'install', PSUTIL])
147156

148157
dirname = 'python-%s-%s' % (version, revision)
149158
if os.path.isdir(dirname):

0 commit comments

Comments
 (0)