-
-
Notifications
You must be signed in to change notification settings - Fork 202
Add ARM64 Windows builds for Python 3.11+ #387
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
+143
−36
Merged
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
f80dc1f
Add ARM64 builds for Windows
zanieb 56339b6
Add `arm64` to `collect_python_build_artifacts`
zanieb 6b8d80c
Use the newer tcl-tk bin for arm64 builds
zanieb 66b7be1
Add recognized triple
zanieb c539516
All Tcl/Tk patch to fail
zanieb 527957b
Update abi platform
zanieb aa7e8e7
Disable 3.9 / 3.10
zanieb 140bd79
Add platformt ag entry
zanieb 137ba57
Update validation for arm64
zanieb 8f6311b
Allow arm64 libssl
zanieb 238f27c
Fix double underscore
zanieb b76ccc0
Add timeout to jobs
zanieb 4323f7d
Delete `x86_64-w64-mingw32-nmakehlp.exe` from tcltk
zanieb e2ed7fa
Patch tcltk toggle?
zanieb 11ec9b3
Allow `api-ms-win-crt-private-l1-1-0.dll`
zanieb dd7e34c
Enable 3.9 and 3.10 again?
zanieb 024f688
Revert "Enable 3.9 and 3.10 again?"
zanieb d49911d
Use consistency exception type
zanieb File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -92,6 +92,7 @@ jobs: | |
fi | ||
build: | ||
timeout-minutes: 60 | ||
needs: | ||
- generate-matrix | ||
- pythonbuild | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -370,7 +370,7 @@ def hack_props( | |
|
||
mpdecimal_version = DOWNLOADS["mpdecimal"]["version"] | ||
|
||
if meets_python_minimum_version(python_version, "3.14"): | ||
if meets_python_minimum_version(python_version, "3.14") or arch == "arm64": | ||
tcltk_commit = DOWNLOADS["tk-windows-bin"]["git_commit"] | ||
else: | ||
tcltk_commit = DOWNLOADS["tk-windows-bin-8612"]["git_commit"] | ||
|
@@ -464,6 +464,8 @@ def hack_props( | |
suffix = b"-x64" | ||
elif arch == "win32": | ||
suffix = b"" | ||
elif arch == "arm64": | ||
suffix = b"" | ||
else: | ||
raise Exception("unhandled architecture: %s" % arch) | ||
|
||
|
@@ -505,6 +507,7 @@ def hack_project_files( | |
build_directory: str, | ||
python_version: str, | ||
zlib_entry: str, | ||
arch: str, | ||
): | ||
"""Hacks Visual Studio project files to work with our build.""" | ||
|
||
|
@@ -518,6 +521,17 @@ def hack_project_files( | |
zlib_entry, | ||
) | ||
|
||
# `--include-tcltk` is forced off on arm64, undo that | ||
# See https://github.com/python/cpython/pull/132650 | ||
try: | ||
static_replace_in_file( | ||
cpython_source_path / "PC" / "layout" / "main.py", | ||
rb'if ns.arch in ("arm32", "arm64"):', | ||
rb'if ns.arch == "arm32":', | ||
) | ||
except NoSearchStringError: | ||
pass | ||
|
||
# Our SQLite directory is named weirdly. This throws off version detection | ||
# in the project file. Replace the parsing logic with a static string. | ||
sqlite3_version = DOWNLOADS["sqlite"]["actual_version"].encode("ascii") | ||
|
@@ -603,14 +617,18 @@ def hack_project_files( | |
# have a standalone zlib DLL, so we remove references to it. For Python | ||
# 3.14+, we're using tk-windows-bin 8.6.14 which includes a prebuilt zlib | ||
# DLL, so we skip this patch there. | ||
if meets_python_minimum_version( | ||
python_version, "3.12" | ||
) and meets_python_maximum_version(python_version, "3.13"): | ||
static_replace_in_file( | ||
pcbuild_path / "_tkinter.vcxproj", | ||
rb'<_TclTkDLL Include="$(tcltkdir)\bin\$(tclZlibDllName)" />', | ||
rb"", | ||
) | ||
# On arm64, we use the new version of tk-windows-bin for all versions. | ||
if meets_python_minimum_version(python_version, "3.12") and ( | ||
meets_python_maximum_version(python_version, "3.13") or arch == "arm64" | ||
): | ||
try: | ||
static_replace_in_file( | ||
pcbuild_path / "_tkinter.vcxproj", | ||
rb'<_TclTkDLL Include="$(tcltkdir)\bin\$(tclZlibDllName)" />', | ||
rb"", | ||
) | ||
except NoSearchStringError: | ||
pass | ||
|
||
# We don't need to produce python_uwp.exe and its *w variant. Or the | ||
# python3.dll, pyshellext, or pylauncher. | ||
|
@@ -730,9 +748,11 @@ def build_openssl_for_arch( | |
elif arch == "amd64": | ||
configure = "VC-WIN64A" | ||
prefix = "64" | ||
elif arch == "arm64": | ||
configure = "VC-WIN64-ARM" | ||
prefix = "arm64" | ||
else: | ||
print("invalid architecture: %s" % arch) | ||
sys.exit(1) | ||
raise Exception("unhandled architecture: %s" % arch) | ||
|
||
# The official CPython OpenSSL builds hack ms/uplink.c to change the | ||
# ``GetModuleHandle(NULL)`` invocation to load things from _ssl.pyd | ||
|
@@ -780,6 +800,12 @@ def build_openssl_for_arch( | |
log("copying %s to %s" % (source, dest)) | ||
shutil.copyfile(source, dest) | ||
|
||
# Copy `applink.c` to the include directory. | ||
source_applink = source_root / "ms" / "applink.c" | ||
dest_applink = install_root / "include" / "openssl" / "applink.c" | ||
log("copying %s to %s" % (source_applink, dest_applink)) | ||
shutil.copyfile(source_applink, dest_applink) | ||
|
||
Comment on lines
+803
to
+808
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you explain in the comment what this is and why it's needed? (Why didn't we need this before?) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can try, but I don't fully understand. |
||
|
||
def build_openssl( | ||
entry: str, | ||
|
@@ -801,6 +827,7 @@ def build_openssl( | |
|
||
root_32 = td / "x86" | ||
root_64 = td / "x64" | ||
root_arm64 = td / "arm64" | ||
|
||
if arch == "x86": | ||
root_32.mkdir() | ||
|
@@ -824,13 +851,28 @@ def build_openssl( | |
root_64, | ||
jom_archive=jom_archive, | ||
) | ||
elif arch == "arm64": | ||
root_arm64.mkdir() | ||
build_openssl_for_arch( | ||
perl_path, | ||
"arm64", | ||
openssl_archive, | ||
openssl_version, | ||
nasm_archive, | ||
root_arm64, | ||
jom_archive=jom_archive, | ||
) | ||
else: | ||
raise ValueError("unhandled arch: %s" % arch) | ||
raise Exception("unhandled architecture: %s" % arch) | ||
|
||
install = td / "out" | ||
|
||
if arch == "x86": | ||
shutil.copytree(root_32 / "install" / "32", install / "openssl" / "win32") | ||
elif arch == "arm64": | ||
shutil.copytree( | ||
root_arm64 / "install" / "arm64", install / "openssl" / "arm64" | ||
) | ||
else: | ||
shutil.copytree(root_64 / "install" / "64", install / "openssl" / "amd64") | ||
|
||
|
@@ -901,9 +943,14 @@ def build_libffi( | |
if arch == "x86": | ||
args.append("-x86") | ||
artifacts_path = ffi_source_path / "i686-pc-cygwin" | ||
else: | ||
elif arch == "arm64": | ||
args.append("-arm64") | ||
artifacts_path = ffi_source_path / "aarch64-w64-cygwin" | ||
elif arch == "amd64": | ||
args.append("-x64") | ||
artifacts_path = ffi_source_path / "x86_64-w64-cygwin" | ||
else: | ||
raise Exception("unhandled architecture: %s" % arch) | ||
|
||
subprocess.run(args, env=env, check=True) | ||
|
||
|
@@ -1069,8 +1116,10 @@ def find_additional_dependencies(project: pathlib.Path): | |
abi_platform = "win_amd64" | ||
elif arch == "win32": | ||
abi_platform = "win32" | ||
elif arch == "arm64": | ||
abi_platform = "win_arm64" | ||
else: | ||
raise ValueError("unhandled arch: %s" % arch) | ||
raise Exception("unhandled architecture: %s" % arch) | ||
|
||
if freethreaded: | ||
abi_tag = ".cp%st-%s" % (python_majmin, abi_platform) | ||
|
@@ -1171,8 +1220,8 @@ def find_additional_dependencies(project: pathlib.Path): | |
if name == "zlib": | ||
name = zlib_entry | ||
|
||
# On 3.14+, we use the latest tcl/tk version | ||
if ext == "_tkinter" and python_majmin == "314": | ||
# On 3.14+ and aarch64, we use the latest tcl/tk version | ||
if ext == "_tkinter" and (python_majmin == "314" or arch == "arm64"): | ||
name = name.replace("-8612", "") | ||
|
||
download_entry = DOWNLOADS[name] | ||
|
@@ -1258,16 +1307,18 @@ def build_cpython( | |
setuptools_wheel = download_entry("setuptools", BUILD) | ||
pip_wheel = download_entry("pip", BUILD) | ||
|
||
# On CPython 3.14+, we use the latest tcl/tk version which has additional runtime | ||
# dependencies, so we are conservative and use the old version elsewhere. | ||
if meets_python_minimum_version(python_version, "3.14"): | ||
tk_bin_archive = download_entry( | ||
"tk-windows-bin", BUILD, local_name="tk-windows-bin.tar.gz" | ||
) | ||
else: | ||
tk_bin_archive = download_entry( | ||
"tk-windows-bin-8612", BUILD, local_name="tk-windows-bin.tar.gz" | ||
) | ||
# On CPython 3.14+, we use the latest tcl/tk version which has additional | ||
# runtime dependencies, so we are conservative and use the old version | ||
# elsewhere. The old version isn't built for arm64, so we use the new | ||
# version there too | ||
tk_bin_entry = ( | ||
"tk-windows-bin" | ||
if meets_python_minimum_version(python_version, "3.14") or arch == "arm64" | ||
else "tk-windows-bin-8612" | ||
) | ||
tk_bin_archive = download_entry( | ||
tk_bin_entry, BUILD, local_name="tk-windows-bin.tar.gz" | ||
) | ||
|
||
# On CPython 3.14+, zstd is included | ||
if meets_python_minimum_version(python_version, "3.14"): | ||
|
@@ -1297,8 +1348,11 @@ def build_cpython( | |
elif arch == "x86": | ||
build_platform = "win32" | ||
build_directory = "win32" | ||
elif arch == "arm64": | ||
build_platform = "arm64" | ||
build_directory = "arm64" | ||
else: | ||
raise ValueError("unhandled arch: %s" % arch) | ||
raise Exception("unhandled architecture: %s" % arch) | ||
|
||
tempdir_opts = ( | ||
{"ignore_cleanup_errors": True} if sys.version_info >= (3, 12) else {} | ||
|
@@ -1332,7 +1386,7 @@ def build_cpython( | |
|
||
# We need all the OpenSSL library files in the same directory to appease | ||
# install rules. | ||
openssl_arch = {"amd64": "amd64", "x86": "win32"}[arch] | ||
openssl_arch = {"amd64": "amd64", "x86": "win32", "arm64": "arm64"}[arch] | ||
openssl_root = td / "openssl" / openssl_arch | ||
openssl_bin_path = openssl_root / "bin" | ||
openssl_lib_path = openssl_root / "lib" | ||
|
@@ -1346,6 +1400,17 @@ def build_cpython( | |
log("copying %s to %s" % (source, dest)) | ||
shutil.copyfile(source, dest) | ||
|
||
# Delete the tk nmake helper, it's not needed and links msvc | ||
tcltk_commit: str = DOWNLOADS[tk_bin_entry]["git_commit"] | ||
tcltk_path = td / ("cpython-bin-deps-%s" % tcltk_commit) | ||
( | ||
tcltk_path | ||
/ build_directory | ||
/ "lib" | ||
/ "nmake" | ||
/ "x86_64-w64-mingw32-nmakehlp.exe" | ||
).unlink() | ||
|
||
cpython_source_path = td / ("Python-%s" % python_version) | ||
pcbuild_path = cpython_source_path / "PCbuild" | ||
|
||
|
@@ -1368,6 +1433,7 @@ def build_cpython( | |
build_directory, | ||
python_version=python_version, | ||
zlib_entry=zlib_entry, | ||
arch=arch, | ||
) | ||
|
||
if pgo: | ||
|
@@ -1790,9 +1856,14 @@ def main() -> None: | |
if os.environ.get("Platform") == "x86": | ||
target_triple = "i686-pc-windows-msvc" | ||
arch = "x86" | ||
else: | ||
elif os.environ.get("Platform") == "arm64": | ||
target_triple = "aarch64-pc-windows-msvc" | ||
arch = "arm64" | ||
elif os.environ.get("Platform") == "x64": | ||
target_triple = "x86_64-pc-windows-msvc" | ||
arch = "amd64" | ||
else: | ||
raise Exception("unhandled architecture: %s" % os.environ.get("Platform")) | ||
|
||
# TODO need better dependency checking. | ||
|
||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.