diff --git a/.github/workflows/buildwheel.yml b/.github/workflows/buildwheel.yml index 36f03726..2b45a59f 100644 --- a/.github/workflows/buildwheel.yml +++ b/.github/workflows/buildwheel.yml @@ -10,7 +10,7 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-22.04, ubuntu-22.04-arm, windows-2022, macos-15-intel, macos-14] + os: [ubuntu-22.04, ubuntu-22.04-arm, windows-2022, windows-11-arm, macos-15-intel, macos-14] steps: - uses: actions/checkout@v6.0.2 @@ -22,7 +22,14 @@ jobs: - uses: msys2/setup-msys2@v2.30.0 with: msystem: ucrt64 - if: ${{ startsWith( matrix.os , 'windows' ) }} + update: true + if: ${{ matrix.os == 'windows-2022' }} + + - uses: msys2/setup-msys2@v2.30.0 + with: + msystem: clangarm64 + update: true + if: ${{ matrix.os == 'windows-11-arm' }} # Install pkgconfig on Windows from choco rather than from msys and # avoid using the Strawberry one. @@ -41,7 +48,7 @@ jobs: uses: pypa/cibuildwheel@298ed2fb2c105540f5ed055e8a6ad78d82dd3a7e # v3.3.1 env: # override setting in pyproject.toml to use msys2 instead of msys64 bash - CIBW_BEFORE_ALL_WINDOWS: msys2 -c bin/cibw_before_all_windows.sh + 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' }} - uses: actions/upload-artifact@v7 with: @@ -81,12 +88,16 @@ jobs: ubuntu-24.04-arm, windows-2022, windows-2025, + windows-11-arm, macos-15-intel, macos-14, macos-15, ] # This list to be kept in sync with python-requires in pyproject.toml. python-version: ['3.11', '3.12', '3.13', '3.13t', '3.14', '3.14t', 'pypy3.11'] + exclude: + - os: windows-11-arm + python-version: pypy3.11 steps: - uses: actions/setup-python@v6 diff --git a/bin/build_dependencies_unix.sh b/bin/build_dependencies_unix.sh index f4805e85..07a48aca 100755 --- a/bin/build_dependencies_unix.sh +++ b/bin/build_dependencies_unix.sh @@ -18,6 +18,12 @@ set -o errexit SKIP_GMP=no SKIP_MPFR=no +PATCH_GMP_C23=no +PATCH_LDD=no +PATCH_IMMINTRIN=no +GMP_FAT_ARG="--enable-fat" +GMP_ASSEMBLY_ARG= +HOST_ARG= USE_GMP=gmp PATCH_GMP_ARM64=no @@ -38,6 +44,9 @@ do echo " --host - set the host (target) for GMP build" echo " --skip-gmp - skip building GMP" echo " --skip-mpfr - skip building MPFR" + echo " --disable-assembly - disable GMP assembly routines" + echo " --patch-ldd - patch flint shared linking for mingw on arm64" + echo " --patch-immintrin - patch flint arm64 msvc header to avoid immintrin.h" echo echo "Legacy options:" echo " --gmp gmp - build based on GMP (default)" @@ -84,6 +93,12 @@ do SKIP_MPFR=yes shift ;; + --disable-assembly) + # GMP does not allow --enable-fat together with --disable-assembly. + GMP_FAT_ARG= + GMP_ASSEMBLY_ARG="--disable-assembly" + shift + ;; --patch-gmp-arm64) # Needed only for GMP 6.2.1 on OSX arm64 (Apple M1) hardware # As of GMP 6.3.0 this patch is no longer needed @@ -95,6 +110,16 @@ do PATCH_GMP_C23=yes shift ;; + --patch-ldd) + # Needed only for the FLINT shared build on mingw arm64. + PATCH_LDD=yes + shift + ;; + --patch-immintrin) + # Needed only for the FLINT headers consumed by MSVC on Windows arm64. + PATCH_IMMINTRIN=yes + shift + ;; --use-gmp-github-mirror) USE_GMP_GITHUB_MIRROR=yes shift @@ -191,7 +216,8 @@ if [ "$USE_GMP" = "gmp" ]; then ./configfsf.guess ./configure --prefix=$PREFIX\ - --enable-fat\ + $GMP_FAT_ARG\ + $GMP_ASSEMBLY_ARG\ --enable-shared=yes\ --enable-static=no\ --host=$HOST_ARG @@ -310,6 +336,20 @@ echo curl -O -L https://github.com/flintlib/flint/releases/download/v$FLINTVER/flint-$FLINTVER.tar.gz tar xf flint-$FLINTVER.tar.gz cd flint-$FLINTVER + if [ "$PATCH_LDD" = "yes" ]; then + echo + echo -------------------------------------------- + echo " patching FLINT" + echo -------------------------------------------- + patch -N -Z -p1 < ../../../bin/patch-flint-windows-arm64-link.diff + fi + if [ "$PATCH_IMMINTRIN" = "yes" ]; then + echo + echo -------------------------------------------- + echo " patching FLINT" + echo -------------------------------------------- + patch -N -Z -p1 < ../../../bin/patch-flint-windows-arm64-immintrin.diff + fi ./bootstrap.sh ./configure --prefix=$PREFIX\ --host=$HOST_ARG\ diff --git a/bin/cibw_before_all_windows.sh b/bin/cibw_before_all_windows.sh index b512a0b2..03df0c72 100755 --- a/bin/cibw_before_all_windows.sh +++ b/bin/cibw_before_all_windows.sh @@ -2,52 +2,26 @@ set -o errexit -pacman -S --noconfirm \ - mingw-w64-ucrt-x86_64-gcc\ - mingw-w64-ucrt-x86_64-tools-git\ - m4\ - make\ - base-devel\ - autoconf-wrapper\ - automake-wrapper\ - libtool\ - git\ - # - -bin/build_dependencies_unix.sh \ - --use-gmp-github-mirror\ - --patch-C23\ - # +if [ $# -lt 2 ]; then + echo "usage: $0 ..." + exit 1 +fi -# Assumes the standard GitHub Actions Windows 2022 runner layout. -PATH="$PATH:$(find "/c/Program Files/Microsoft Visual Studio/2022/" -name "Hostx86")/x64/" +llvm_machine="$1" +shift -if [ "${RUNNER_ARCH}" = "ARM64" ] -then - msvc_machine=arm64 -else - msvc_machine=x64 -fi +bin/build_dependencies_unix.sh "$@" mkdir -p .local/lib cd .local/bin for dll_file in libgmp-*.dll libmpfr-*.dll libflint*.dll do - lib_name=$(basename -s .dll ${dll_file}) - exports_file=${lib_name}-exports.txt + lib_name=$(basename -s .dll "${dll_file}") def_file=${lib_name}.def - lib_file=${lib_name}.lib - name=$(echo ${lib_name}|sed 's/^lib//;s/[-.][0-9].*$//') - - dumpbin //exports ${dll_file} > ${exports_file} - - echo LIBRARY ${lib_name} > ${def_file} - echo EXPORTS >> ${def_file} - awk 'NR>19 && $4 != "" {print $4 " @"$1}' ${exports_file} >> ${def_file} - sed -i 's/$/\r/' ${def_file} + name=$(echo "${lib_name}" | sed 's/^lib//;s/[-.][0-9].*$//') - lib //def:${def_file} //out:${lib_file} //machine:${msvc_machine} - rm ${exports_file} ${def_file} ${lib_name}.exp - mv ${lib_file} ../lib/${name}.lib + gendef "${dll_file}" + llvm-lib /def:"${def_file}" /out:"../lib/${name}.lib" /machine:${llvm_machine} /nologo + rm "${def_file}" done cd ../.. diff --git a/bin/cibw_before_all_windows_amd64.sh b/bin/cibw_before_all_windows_amd64.sh new file mode 100755 index 00000000..a99e399a --- /dev/null +++ b/bin/cibw_before_all_windows_amd64.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +set -o errexit + +pacman -S --noconfirm \ + mingw-w64-ucrt-x86_64-gcc \ + mingw-w64-ucrt-x86_64-llvm-tools \ + mingw-w64-ucrt-x86_64-tools-git \ + m4 \ + make \ + base-devel \ + autoconf-wrapper \ + automake-wrapper \ + libtool \ + git \ + # + +bin/cibw_before_all_windows.sh \ + x64 \ + --use-gmp-github-mirror \ + --patch-C23 \ + # diff --git a/bin/cibw_before_all_windows_arm64.sh b/bin/cibw_before_all_windows_arm64.sh new file mode 100755 index 00000000..02b602ed --- /dev/null +++ b/bin/cibw_before_all_windows_arm64.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +set -o errexit + +pacman -S --noconfirm \ + mingw-w64-clang-aarch64-toolchain \ + mingw-w64-clang-aarch64-llvm-tools \ + mingw-w64-clang-aarch64-tools-git \ + m4 \ + make \ + base-devel \ + autoconf-wrapper \ + automake-wrapper \ + libtool \ + git \ + # + +bin/cibw_before_all_windows.sh \ + arm64 \ + --use-gmp-github-mirror \ + --disable-assembly \ + --host aarch64-w64-mingw32 \ + --patch-C23 \ + --patch-ldd \ + --patch-immintrin \ + # diff --git a/bin/patch-flint-windows-arm64-immintrin.diff b/bin/patch-flint-windows-arm64-immintrin.diff new file mode 100644 index 00000000..27eaad9f --- /dev/null +++ b/bin/patch-flint-windows-arm64-immintrin.diff @@ -0,0 +1,12 @@ +diff --git a/src/longlong_msc_arm64.h b/src/longlong_msc_arm64.h +index 44d96f03f..6ade48289 100644 +--- a/src/longlong_msc_arm64.h ++++ b/src/longlong_msc_arm64.h +@@ -14,7 +14,6 @@ + + #include + #include +-#include + + /* Trailing and leading zeros */ + # define flint_clz _CountLeadingZeros64 diff --git a/bin/patch-flint-windows-arm64-link.diff b/bin/patch-flint-windows-arm64-link.diff new file mode 100644 index 00000000..1b67c584 --- /dev/null +++ b/bin/patch-flint-windows-arm64-link.diff @@ -0,0 +1,27 @@ +diff --git a/Makefile.in b/Makefile.in +index 0f25aa2b5..f6f46b7d6 100644 +--- a/Makefile.in ++++ b/Makefile.in +@@ -416,18 +416,12 @@ endif + ifneq ($(SHARED), 0) + shared: $(FLINT_DIR)/$(FLINT_LIB_FULL) + +-# The following is to avoid reaching the maximum length of command line +-# arguments, mainly present on MinGW. +-define xxx_merged_lobj_rule +-$(BUILD_DIR)/$(1)_merged.lo: $($(1)_LOBJS) | $(BUILD_DIR) +- @$(LD) -r $($(1)_LOBJS) -o $(BUILD_DIR)/$(1)_merged.lo +-endef +-$(foreach dir, $(DIRS), $(eval $(call xxx_merged_lobj_rule,$(dir)))) +-MERGED_LOBJS:=$(foreach dir, $(DIRS),$(BUILD_DIR)/$(dir)_merged.lo) ++SHARED_LINK_RSP := $(BUILD_DIR)/libflint-shared.rsp + +-$(FLINT_DIR)/$(FLINT_LIB_FULL): $(MERGED_LOBJS) ++$(FLINT_DIR)/$(FLINT_LIB_FULL): $(LOBJS) | $(BUILD_DIR) + @echo "Building $(FLINT_LIB_FULL)" +- @$(CC) $(CFLAGS) -shared $(EXTRA_SHARED_FLAGS) $(MERGED_LOBJS) -o $(FLINT_LIB_FULL) $(LDFLAGS) $(LIBS) ++ @: $(file >$(SHARED_LINK_RSP))$(foreach obj,$(LOBJS),$(file >>$(SHARED_LINK_RSP),$(obj))) ++ @$(CC) $(CFLAGS) -shared $(EXTRA_SHARED_FLAGS) @$(SHARED_LINK_RSP) -o $(FLINT_LIB_FULL) $(LDFLAGS) $(LIBS) + @$(RM_F) $(FLINT_LIB) + @$(RM_F) $(FLINT_LIB_MAJOR) + @$(LN_S) $(FLINT_LIB_FULL) $(FLINT_LIB) diff --git a/doc/source/build.rst b/doc/source/build.rst index a86e8788..14d29421 100644 --- a/doc/source/build.rst +++ b/doc/source/build.rst @@ -352,21 +352,30 @@ builds on Windows using MSVC. The `MSYS2 `_ project provides a Unix-like environment for Windows and a package manager that can be used to install the dependencies. -The git repo for ``python-flint`` has a script `bin/cibw_before_all_windows.sh -`_ -that installs the dependencies under MSYS2 and builds ``GMP``, ``MPFR``, -``FLINT``. This script is used for building the Windows binaries for PyPI. We -use the ``UCRT64`` (``mingw-w64-ucrt-x86_64``) toolchain under MSYS2 to build -``GMP``, ``MPFR`` and ``FLINT`` because it makes it possible to have a fat -build of ``GMP`` -(``--enable-fat``) which bundles micro-architecture specific optimisations for -``x86_64`` in a redistributable shared library. This is important for -performance on modern ``x86_64`` CPUs and is not possible if building ``GMP`` -with MSVC. The Python extension modules themselves are then built with MSVC via +The git repo for ``python-flint`` has scripts +`bin/cibw_before_all_windows_amd64.sh +`_ +and `bin/cibw_before_all_windows_arm64.sh +`_ +that install the dependencies under MSYS2 and build ``GMP``, ``MPFR``, +``FLINT``. These scripts are used for building the Windows binaries for PyPI. + +For ``x86_64`` wheels we use the ``UCRT64`` (``mingw-w64-ucrt-x86_64``) +toolchain under MSYS2 to build ``GMP``, ``MPFR`` and ``FLINT`` because it +makes it possible to have a fat build of ``GMP`` (``--enable-fat``) which +bundles micro-architecture specific optimisations for ``x86_64`` in a +redistributable shared library. This is important for performance on modern +``x86_64`` CPUs and is not possible if building ``GMP`` with MSVC. + +For Windows ``arm64`` wheels we use the ``CLANGARM64`` MSYS2 toolchain instead. +The ``GMP`` build there does not use ``--enable-fat`` and instead uses the +generic build that works with that toolchain. + +The Python extension modules themselves are then built with MSVC via ``meson --vsenv`` while linking against the MSYS2-built ``GMP``, ``MPFR`` and ``FLINT`` libraries through ``pkg-config``. This mixed-toolchain arrangement -keeps the ``GMP`` fat build while using the standard Windows compiler for the -extension modules. +keeps the MSYS2 dependency builds while using the standard Windows compiler for +the extension modules on both ``x86_64`` and ``arm64``. .. _non_standard_location: diff --git a/pyproject.toml b/pyproject.toml index e51663dc..399b0e23 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -94,7 +94,7 @@ files = ["src"] addopts = "--import-mode=importlib" [tool.cibuildwheel] -skip = "*-win32 *-manylinux_i686 *-manylinux_armv7l *-musllinux_*" +skip = "*-win32 pp*-win_arm64 *-manylinux_i686 *-manylinux_armv7l *-musllinux_*" enable = [ # Uncomment this to test beta versions of CPython in CI (but comment out @@ -154,7 +154,6 @@ repair-wheel-command = [ ] [tool.cibuildwheel.windows] -before-all = "C:\\msys64\\usr\\bin\\bash bin/cibw_before_all_windows.sh" before-build = "pip install wheel delvewheel" config-settings = {setup-args = ["--vsenv"], build-dir = "build"} repair-wheel-command = [