Skip to content

Commit 63a3480

Browse files
Merge pull request #379 from oscarbenjamin/pr_windows_arm
Add Windows on ARM wheels.
2 parents 2e84fc5 + 2f34270 commit 63a3480

9 files changed

+177
-57
lines changed

.github/workflows/buildwheel.yml

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
strategy:
1111
fail-fast: false
1212
matrix:
13-
os: [ubuntu-22.04, ubuntu-22.04-arm, windows-2022, macos-15-intel, macos-14]
13+
os: [ubuntu-22.04, ubuntu-22.04-arm, windows-2022, windows-11-arm, macos-15-intel, macos-14]
1414

1515
steps:
1616
- uses: actions/checkout@v6.0.2
@@ -22,7 +22,14 @@ jobs:
2222
- uses: msys2/setup-msys2@v2.30.0
2323
with:
2424
msystem: ucrt64
25-
if: ${{ startsWith( matrix.os , 'windows' ) }}
25+
update: true
26+
if: ${{ matrix.os == 'windows-2022' }}
27+
28+
- uses: msys2/setup-msys2@v2.30.0
29+
with:
30+
msystem: clangarm64
31+
update: true
32+
if: ${{ matrix.os == 'windows-11-arm' }}
2633

2734
# Install pkgconfig on Windows from choco rather than from msys and
2835
# avoid using the Strawberry one.
@@ -41,7 +48,7 @@ jobs:
4148
uses: pypa/cibuildwheel@298ed2fb2c105540f5ed055e8a6ad78d82dd3a7e # v3.3.1
4249
env:
4350
# override setting in pyproject.toml to use msys2 instead of msys64 bash
44-
CIBW_BEFORE_ALL_WINDOWS: msys2 -c bin/cibw_before_all_windows.sh
51+
CIBW_BEFORE_ALL_WINDOWS: ${{ matrix.os == 'windows-11-arm' && 'msys2 -c bin/cibw_before_all_windows_arm64.sh' || 'msys2 -c bin/cibw_before_all_windows_amd64.sh' }}
4552

4653
- uses: actions/upload-artifact@v7
4754
with:
@@ -81,12 +88,16 @@ jobs:
8188
ubuntu-24.04-arm,
8289
windows-2022,
8390
windows-2025,
91+
windows-11-arm,
8492
macos-15-intel,
8593
macos-14,
8694
macos-15,
8795
]
8896
# This list to be kept in sync with python-requires in pyproject.toml.
8997
python-version: ['3.11', '3.12', '3.13', '3.13t', '3.14', '3.14t', 'pypy3.11']
98+
exclude:
99+
- os: windows-11-arm
100+
python-version: pypy3.11
90101

91102
steps:
92103
- uses: actions/setup-python@v6

bin/build_dependencies_unix.sh

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@ set -o errexit
1818

1919
SKIP_GMP=no
2020
SKIP_MPFR=no
21+
PATCH_GMP_C23=no
22+
PATCH_LDD=no
23+
PATCH_IMMINTRIN=no
24+
GMP_FAT_ARG="--enable-fat"
25+
GMP_ASSEMBLY_ARG=
26+
HOST_ARG=
2127

2228
USE_GMP=gmp
2329
PATCH_GMP_ARM64=no
@@ -38,6 +44,9 @@ do
3844
echo " --host <HOST> - set the host (target) for GMP build"
3945
echo " --skip-gmp - skip building GMP"
4046
echo " --skip-mpfr - skip building MPFR"
47+
echo " --disable-assembly - disable GMP assembly routines"
48+
echo " --patch-ldd - patch flint shared linking for mingw on arm64"
49+
echo " --patch-immintrin - patch flint arm64 msvc header to avoid immintrin.h"
4150
echo
4251
echo "Legacy options:"
4352
echo " --gmp gmp - build based on GMP (default)"
@@ -84,6 +93,12 @@ do
8493
SKIP_MPFR=yes
8594
shift
8695
;;
96+
--disable-assembly)
97+
# GMP does not allow --enable-fat together with --disable-assembly.
98+
GMP_FAT_ARG=
99+
GMP_ASSEMBLY_ARG="--disable-assembly"
100+
shift
101+
;;
87102
--patch-gmp-arm64)
88103
# Needed only for GMP 6.2.1 on OSX arm64 (Apple M1) hardware
89104
# As of GMP 6.3.0 this patch is no longer needed
@@ -95,6 +110,16 @@ do
95110
PATCH_GMP_C23=yes
96111
shift
97112
;;
113+
--patch-ldd)
114+
# Needed only for the FLINT shared build on mingw arm64.
115+
PATCH_LDD=yes
116+
shift
117+
;;
118+
--patch-immintrin)
119+
# Needed only for the FLINT headers consumed by MSVC on Windows arm64.
120+
PATCH_IMMINTRIN=yes
121+
shift
122+
;;
98123
--use-gmp-github-mirror)
99124
USE_GMP_GITHUB_MIRROR=yes
100125
shift
@@ -191,7 +216,8 @@ if [ "$USE_GMP" = "gmp" ]; then
191216
./configfsf.guess
192217

193218
./configure --prefix=$PREFIX\
194-
--enable-fat\
219+
$GMP_FAT_ARG\
220+
$GMP_ASSEMBLY_ARG\
195221
--enable-shared=yes\
196222
--enable-static=no\
197223
--host=$HOST_ARG
@@ -310,6 +336,20 @@ echo
310336
curl -O -L https://github.com/flintlib/flint/releases/download/v$FLINTVER/flint-$FLINTVER.tar.gz
311337
tar xf flint-$FLINTVER.tar.gz
312338
cd flint-$FLINTVER
339+
if [ "$PATCH_LDD" = "yes" ]; then
340+
echo
341+
echo --------------------------------------------
342+
echo " patching FLINT"
343+
echo --------------------------------------------
344+
patch -N -Z -p1 < ../../../bin/patch-flint-windows-arm64-link.diff
345+
fi
346+
if [ "$PATCH_IMMINTRIN" = "yes" ]; then
347+
echo
348+
echo --------------------------------------------
349+
echo " patching FLINT"
350+
echo --------------------------------------------
351+
patch -N -Z -p1 < ../../../bin/patch-flint-windows-arm64-immintrin.diff
352+
fi
313353
./bootstrap.sh
314354
./configure --prefix=$PREFIX\
315355
--host=$HOST_ARG\

bin/cibw_before_all_windows.sh

Lines changed: 12 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,52 +2,26 @@
22

33
set -o errexit
44

5-
pacman -S --noconfirm \
6-
mingw-w64-ucrt-x86_64-gcc\
7-
mingw-w64-ucrt-x86_64-tools-git\
8-
m4\
9-
make\
10-
base-devel\
11-
autoconf-wrapper\
12-
automake-wrapper\
13-
libtool\
14-
git\
15-
#
16-
17-
bin/build_dependencies_unix.sh \
18-
--use-gmp-github-mirror\
19-
--patch-C23\
20-
#
5+
if [ $# -lt 2 ]; then
6+
echo "usage: $0 <llvm-machine> <build-dependencies-args>..."
7+
exit 1
8+
fi
219

22-
# Assumes the standard GitHub Actions Windows 2022 runner layout.
23-
PATH="$PATH:$(find "/c/Program Files/Microsoft Visual Studio/2022/" -name "Hostx86")/x64/"
10+
llvm_machine="$1"
11+
shift
2412

25-
if [ "${RUNNER_ARCH}" = "ARM64" ]
26-
then
27-
msvc_machine=arm64
28-
else
29-
msvc_machine=x64
30-
fi
13+
bin/build_dependencies_unix.sh "$@"
3114

3215
mkdir -p .local/lib
3316
cd .local/bin
3417
for dll_file in libgmp-*.dll libmpfr-*.dll libflint*.dll
3518
do
36-
lib_name=$(basename -s .dll ${dll_file})
37-
exports_file=${lib_name}-exports.txt
19+
lib_name=$(basename -s .dll "${dll_file}")
3820
def_file=${lib_name}.def
39-
lib_file=${lib_name}.lib
40-
name=$(echo ${lib_name}|sed 's/^lib//;s/[-.][0-9].*$//')
41-
42-
dumpbin //exports ${dll_file} > ${exports_file}
43-
44-
echo LIBRARY ${lib_name} > ${def_file}
45-
echo EXPORTS >> ${def_file}
46-
awk 'NR>19 && $4 != "" {print $4 " @"$1}' ${exports_file} >> ${def_file}
47-
sed -i 's/$/\r/' ${def_file}
21+
name=$(echo "${lib_name}" | sed 's/^lib//;s/[-.][0-9].*$//')
4822

49-
lib //def:${def_file} //out:${lib_file} //machine:${msvc_machine}
50-
rm ${exports_file} ${def_file} ${lib_name}.exp
51-
mv ${lib_file} ../lib/${name}.lib
23+
gendef "${dll_file}"
24+
llvm-lib /def:"${def_file}" /out:"../lib/${name}.lib" /machine:${llvm_machine} /nologo
25+
rm "${def_file}"
5226
done
5327
cd ../..
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/bin/bash
2+
3+
set -o errexit
4+
5+
pacman -S --noconfirm \
6+
mingw-w64-ucrt-x86_64-gcc \
7+
mingw-w64-ucrt-x86_64-llvm-tools \
8+
mingw-w64-ucrt-x86_64-tools-git \
9+
m4 \
10+
make \
11+
base-devel \
12+
autoconf-wrapper \
13+
automake-wrapper \
14+
libtool \
15+
git \
16+
#
17+
18+
bin/cibw_before_all_windows.sh \
19+
x64 \
20+
--use-gmp-github-mirror \
21+
--patch-C23 \
22+
#
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/bin/bash
2+
3+
set -o errexit
4+
5+
pacman -S --noconfirm \
6+
mingw-w64-clang-aarch64-toolchain \
7+
mingw-w64-clang-aarch64-llvm-tools \
8+
mingw-w64-clang-aarch64-tools-git \
9+
m4 \
10+
make \
11+
base-devel \
12+
autoconf-wrapper \
13+
automake-wrapper \
14+
libtool \
15+
git \
16+
#
17+
18+
bin/cibw_before_all_windows.sh \
19+
arm64 \
20+
--use-gmp-github-mirror \
21+
--disable-assembly \
22+
--host aarch64-w64-mingw32 \
23+
--patch-C23 \
24+
--patch-ldd \
25+
--patch-immintrin \
26+
#
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
diff --git a/src/longlong_msc_arm64.h b/src/longlong_msc_arm64.h
2+
index 44d96f03f..6ade48289 100644
3+
--- a/src/longlong_msc_arm64.h
4+
+++ b/src/longlong_msc_arm64.h
5+
@@ -14,7 +14,6 @@
6+
7+
#include <stdlib.h>
8+
#include <intrin.h>
9+
-#include <immintrin.h>
10+
11+
/* Trailing and leading zeros */
12+
# define flint_clz _CountLeadingZeros64
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
diff --git a/Makefile.in b/Makefile.in
2+
index 0f25aa2b5..f6f46b7d6 100644
3+
--- a/Makefile.in
4+
+++ b/Makefile.in
5+
@@ -416,18 +416,12 @@ endif
6+
ifneq ($(SHARED), 0)
7+
shared: $(FLINT_DIR)/$(FLINT_LIB_FULL)
8+
9+
-# The following is to avoid reaching the maximum length of command line
10+
-# arguments, mainly present on MinGW.
11+
-define xxx_merged_lobj_rule
12+
-$(BUILD_DIR)/$(1)_merged.lo: $($(1)_LOBJS) | $(BUILD_DIR)
13+
- @$(LD) -r $($(1)_LOBJS) -o $(BUILD_DIR)/$(1)_merged.lo
14+
-endef
15+
-$(foreach dir, $(DIRS), $(eval $(call xxx_merged_lobj_rule,$(dir))))
16+
-MERGED_LOBJS:=$(foreach dir, $(DIRS),$(BUILD_DIR)/$(dir)_merged.lo)
17+
+SHARED_LINK_RSP := $(BUILD_DIR)/libflint-shared.rsp
18+
19+
-$(FLINT_DIR)/$(FLINT_LIB_FULL): $(MERGED_LOBJS)
20+
+$(FLINT_DIR)/$(FLINT_LIB_FULL): $(LOBJS) | $(BUILD_DIR)
21+
@echo "Building $(FLINT_LIB_FULL)"
22+
- @$(CC) $(CFLAGS) -shared $(EXTRA_SHARED_FLAGS) $(MERGED_LOBJS) -o $(FLINT_LIB_FULL) $(LDFLAGS) $(LIBS)
23+
+ @: $(file >$(SHARED_LINK_RSP))$(foreach obj,$(LOBJS),$(file >>$(SHARED_LINK_RSP),$(obj)))
24+
+ @$(CC) $(CFLAGS) -shared $(EXTRA_SHARED_FLAGS) @$(SHARED_LINK_RSP) -o $(FLINT_LIB_FULL) $(LDFLAGS) $(LIBS)
25+
@$(RM_F) $(FLINT_LIB)
26+
@$(RM_F) $(FLINT_LIB_MAJOR)
27+
@$(LN_S) $(FLINT_LIB_FULL) $(FLINT_LIB)

doc/source/build.rst

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -352,21 +352,30 @@ builds on Windows using MSVC.
352352

353353
The `MSYS2 <https://www.msys2.org/>`_ project provides a Unix-like environment
354354
for Windows and a package manager that can be used to install the dependencies.
355-
The git repo for ``python-flint`` has a script `bin/cibw_before_all_windows.sh
356-
<https://github.com/flintlib/python-flint/blob/master/bin/cibw_before_all_windows.sh>`_
357-
that installs the dependencies under MSYS2 and builds ``GMP``, ``MPFR``,
358-
``FLINT``. This script is used for building the Windows binaries for PyPI. We
359-
use the ``UCRT64`` (``mingw-w64-ucrt-x86_64``) toolchain under MSYS2 to build
360-
``GMP``, ``MPFR`` and ``FLINT`` because it makes it possible to have a fat
361-
build of ``GMP``
362-
(``--enable-fat``) which bundles micro-architecture specific optimisations for
363-
``x86_64`` in a redistributable shared library. This is important for
364-
performance on modern ``x86_64`` CPUs and is not possible if building ``GMP``
365-
with MSVC. The Python extension modules themselves are then built with MSVC via
355+
The git repo for ``python-flint`` has scripts
356+
`bin/cibw_before_all_windows_amd64.sh
357+
<https://github.com/flintlib/python-flint/blob/master/bin/cibw_before_all_windows_amd64.sh>`_
358+
and `bin/cibw_before_all_windows_arm64.sh
359+
<https://github.com/flintlib/python-flint/blob/master/bin/cibw_before_all_windows_arm64.sh>`_
360+
that install the dependencies under MSYS2 and build ``GMP``, ``MPFR``,
361+
``FLINT``. These scripts are used for building the Windows binaries for PyPI.
362+
363+
For ``x86_64`` wheels we use the ``UCRT64`` (``mingw-w64-ucrt-x86_64``)
364+
toolchain under MSYS2 to build ``GMP``, ``MPFR`` and ``FLINT`` because it
365+
makes it possible to have a fat build of ``GMP`` (``--enable-fat``) which
366+
bundles micro-architecture specific optimisations for ``x86_64`` in a
367+
redistributable shared library. This is important for performance on modern
368+
``x86_64`` CPUs and is not possible if building ``GMP`` with MSVC.
369+
370+
For Windows ``arm64`` wheels we use the ``CLANGARM64`` MSYS2 toolchain instead.
371+
The ``GMP`` build there does not use ``--enable-fat`` and instead uses the
372+
generic build that works with that toolchain.
373+
374+
The Python extension modules themselves are then built with MSVC via
366375
``meson --vsenv`` while linking against the MSYS2-built ``GMP``, ``MPFR`` and
367376
``FLINT`` libraries through ``pkg-config``. This mixed-toolchain arrangement
368-
keeps the ``GMP`` fat build while using the standard Windows compiler for the
369-
extension modules.
377+
keeps the MSYS2 dependency builds while using the standard Windows compiler for
378+
the extension modules on both ``x86_64`` and ``arm64``.
370379

371380

372381
.. _non_standard_location:

pyproject.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ files = ["src"]
9494
addopts = "--import-mode=importlib"
9595

9696
[tool.cibuildwheel]
97-
skip = "*-win32 *-manylinux_i686 *-manylinux_armv7l *-musllinux_*"
97+
skip = "*-win32 pp*-win_arm64 *-manylinux_i686 *-manylinux_armv7l *-musllinux_*"
9898

9999
enable = [
100100
# Uncomment this to test beta versions of CPython in CI (but comment out
@@ -154,7 +154,6 @@ repair-wheel-command = [
154154
]
155155

156156
[tool.cibuildwheel.windows]
157-
before-all = "C:\\msys64\\usr\\bin\\bash bin/cibw_before_all_windows.sh"
158157
before-build = "pip install wheel delvewheel"
159158
config-settings = {setup-args = ["--vsenv"], build-dir = "build"}
160159
repair-wheel-command = [

0 commit comments

Comments
 (0)