Skip to content

Commit

Permalink
Build and test windows wheels
Browse files Browse the repository at this point in the history
Closes #468
  • Loading branch information
skirpichev committed Mar 7, 2024
1 parent eb8dfcb commit 92ddff5
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 42 deletions.
45 changes: 35 additions & 10 deletions .github/workflows/build_wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,53 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]

os: [ubuntu-latest, macos-latest, windows-2019]
steps:
- uses: actions/checkout@v3

- uses: msys2/setup-msys2@v2
name: Setup msys2
with:
update: true
install: >-
mingw-w64-ucrt-x86_64-gcc
autotools
# path-type inherit is used so that when cibuildwheel calls msys2 to
# run bin/cibw_before_build_windows.sh the virtual environment
# created by cibuildwheel will be available within msys2. The
# msys2/setup-msys2 README warns that using inherit here can be
# problematic in some situations. Maybe there is a better way to do
# this.
path-type: inherit
msystem: ucrt64
if: ${{ matrix.os == 'windows-2019' }}
- name: Build wheels
uses: pypa/cibuildwheel@v2.16.0
uses: pypa/cibuildwheel@v2.16.5
env:
CIBW_PRERELEASE_PYTHONS: True
CIBW_SKIP: pp*
CIBW_SKIP: pp* *-win32
CIBW_BUILD: 'cp311-*'
CIBW_BEFORE_BUILD: bash scripts/before_ci_build.sh
CIBW_BEFORE_BUILD_WINDOWS: >
pip install delvewheel &&
msys2 -c scripts/before_ci_build_windows.sh &&
call mingw64/dll2lib.bat 64 "D:\a\_temp\msys64\ucrt64\bin\libgmp-10.dll" gmp &&
call mingw64/dll2lib.bat 64 "D:\a\_temp\msys64\ucrt64\bin\libmpfr-6.dll" mpfr &&
call mingw64/dll2lib.bat 64 "D:\a\_temp\msys64\ucrt64\bin\libmpc-3.dll" mpc
CIBW_TEST_EXTRAS: tests
CIBW_TEST_COMMAND: >
pytest {package}/test/ &&
python {package}/test_cython/runtests.py
CIBW_TEST_COMMAND_WINDOWS: >
pytest {package}/test/
CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: >
cd "D:\a\_temp\msys64\ucrt64" &&
delvewheel repair {wheel} -w {dest_dir} --add-path bin --no-mangle-all &&
cd "D:\a\gmpy\gmpy" &&
msys2 -c scripts/repair_ci_wheel_windows.sh
CIBW_REPAIR_WHEEL_COMMAND_LINUX: >
bash scripts/repair_ci_wheel.sh {dest_dir} {wheel}
CIBW_REPAIR_WHEEL_COMMAND_MACOS: >
bash scripts/repair_ci_wheel.sh {dest_dir} {wheel} {delocate_archs}
- uses: actions/upload-artifact@v3
with:
name: wheels
Expand All @@ -39,24 +66,22 @@ jobs:
strategy:
matrix:
os: [macos-12]

steps:
- uses: actions/checkout@v3

- name: Build wheel
uses: pypa/cibuildwheel@v2.16.0
uses: pypa/cibuildwheel@v2.16.5
env:
CIBW_PRERELEASE_PYTHONS: True
CIBW_BEFORE_BUILD: bash scripts/before_ci_build_apple_silicon.sh
CIBW_SKIP: pp*
CIBW_BUILD: 'cp311-*'
CIBW_ARCHS_MACOS: arm64
CIBW_TEST_EXTRAS: tests
CIBW_TEST_COMMAND: >
pytest {package}/test/ &&
python {package}/test_cython/runtests.py
CIBW_REPAIR_WHEEL_COMMAND_MACOS: >
bash scripts/repair_ci_wheel.sh {dest_dir} {wheel} {delocate_archs}
- uses: actions/upload-artifact@v3
with:
name: wheels
Expand Down
38 changes: 38 additions & 0 deletions mingw64/dll2lib.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
echo "dll2lib"
@echo off

REM From https://github.com/GBillotey/Fractalshades/blob/master/win_build/dll2lib.bat

REM Usage: dll2lib [32|64] some-file.dll
REM
REM Generates some-file.lib from some-file.dll, making an intermediate
REM some-file.def from the results of dumpbin /exports some-file.dll.
REM
REM Requires 'dumpbin' and 'lib' in PATH - run from VS developer prompt.
REM
REM Script inspired by http://stackoverflow.com/questions/9946322/how-to-generate-an-import-library-lib-file-from-a-dll
REM See also https://gist.github.com/Trass3r/8d0232a66b098530d07b0e48df6ad5ef
SETLOCAL
set PATH="C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30133\bin\HostX86\x86\"
if "%1"=="32" (set machine=x86) else (set machine=x64)
set mypath=%~p2
cd %mypath%
set dll_file=%~f2
set dll_file_no_ext=%~n2
set exports_file=%dll_file_no_ext%-exports.txt
set def_file=%dll_file_no_ext%.def
set lib_file=%dll_file_no_ext%.lib
set lib_name=%dll_file_no_ext%

dumpbin /exports %dll_file% > %exports_file%

echo LIBRARY %lib_name% > %def_file%
echo EXPORTS >> %def_file%
for /f "skip=19 tokens=1,4" %%A in (%exports_file%) do if NOT "%%B" == "" (echo %%B @%%A >> %def_file%)

lib /def:%def_file% /out:%lib_file% /machine:%machine%

REM Clean up temporary intermediate files
del %exports_file% %def_file% %dll_file_no_ext%.exp

ren %lib_file% %3.lib
56 changes: 56 additions & 0 deletions scripts/before_ci_build_windows.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#!/bin/sh

set -e -x

GMP_VERSION=6.3.0
MPFR_VERSION=4.2.1
MPC_VERSION=1.3.1

# OSTYPE: msys
PREFIX=/ucrt64

if [ ! -f finish_before_ci_build ]
then
# -- build GMP --
curl -s -O https://ftp.gnu.org/gnu/gmp/gmp-${GMP_VERSION}.tar.xz
tar -xf gmp-${GMP_VERSION}.tar.xz
cd gmp-${GMP_VERSION}
# config.guess uses microarchitecture and configfsf.guess doesn't
# We replace config.guess with configfsf.guess to avoid microarchitecture
# specific code in common code.
rm config.guess && mv configfsf.guess config.guess && chmod +x config.guess
./configure --enable-fat \
--enable-shared \
--disable-static
make -j6
make install
cd ../

# -- build MPFR
curl -s -O https://ftp.gnu.org/gnu/mpfr/mpfr-${MPFR_VERSION}.tar.gz
tar -xf mpfr-${MPFR_VERSION}.tar.gz
cd mpfr-${MPFR_VERSION}
./configure --enable-shared \
--disable-static
make -j6
make install
cd ../
# -- build MPC --
curl -s -O https://ftp.gnu.org/gnu/mpc/mpc-${MPC_VERSION}.tar.gz
tar -xf mpc-${MPC_VERSION}.tar.gz
cd mpc-${MPC_VERSION}
./configure --enable-shared \
--disable-static
make -j6
make install
cd ../

# -- copy headers --
cp $PREFIX/include/{gmp,mpfr,mpc}.h gmpy2/

touch finish_before_ci_build
else
(cd gmp-*[0-9] && make install)
(cd mpfr-*[0-9] && make install)
(cd mpc-*[0-9] && make install)
fi
12 changes: 12 additions & 0 deletions scripts/repair_ci_wheel_windows.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#dest_dir=$1
#wheel=$2
#wheel unpack --dest ${dest_dir} ${wheel}
#cp /gmp/include/{gmp,mpfr,mpc}.h ${dest_dir}/gmpy2-*/gmpy2/
#(cd ${dest_dir} && wheel pack gmpy2-*[0-9])
#cp ${dest_dir}/gmpy2-*.whl ${wheel}
#rm -rf ${dest_dir}/*
#delvewheel repair ${wheel} -w ${dest_dir} --add-path ../gmpy2.libs
# cleanup libs from before_ci_build*.sh
(cd gmp-*[0-9] && make uninstall)
(cd mpfr-*[0-9] && make uninstall)
(cd mpc-*[0-9] && make uninstall)
35 changes: 3 additions & 32 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,12 @@
import platform
from setuptools import setup, Extension
from setuptools.command.build_ext import build_ext
import shutil
from pathlib import Path

ON_WINDOWS = platform.system() == 'Windows'
_comp_args = ["DSHARED=1"]
sources = ['src/gmpy2.c']
winlibs = ['gmp.h','mpfr.h','mpc.h',
'gmp.lib','mpfr.lib','mpc.lib',
'libgmp-10.dll','libmpfr-6.dll','libmpc-3.dll',
'libgcc_s_seh-1.dll','libwinpthread-1.dll']

# Copy the pre-built Windows libraries to the 'gmpy2' directory'.
# If you're not on Windows, delete the Windows libraries from the 'gmpy2'
# directory if the they exist.
src = Path('mingw64') / 'winlibs'
dst = Path('gmpy2')
if ON_WINDOWS:
for filename in winlibs:
try:
shutil.copy(src / filename, dst / filename)
except(FileNotFoundError):
pass
# Also copy gmpy2.h and gmpy2.pxd to gmpy2 directory to avoid symlink
# issues on Windows.
for filename in ['gmpy2.h', 'gmpy2.pxd']:
try:
shutil.copy(Path('src') / filename, dst / filename)
except(FileNotFoundError):
pass
else:
for filename in winlibs:
try:
(dst / filename).unlink()
except(FileNotFoundError):
pass

class Gmpy2Build(build_ext):
description = "Build gmpy2 with custom build options"
Expand Down Expand Up @@ -95,9 +66,9 @@ def build_extensions(self):
extensions = [
Extension('gmpy2.gmpy2',
sources=sources,
include_dirs=['./src'] + (['./gmpy2'] if ON_WINDOWS else []),
libraries=['mpc','mpfr','gmp'] if ON_WINDOWS else ['mpc','mpfr','gmp','m'],
library_dirs=(['./gmpy2'] if ON_WINDOWS else []),
include_dirs=([r'gmpy2'] if ON_WINDOWS else []),
libraries=['mpc','mpfr','gmp'],
library_dirs=([r'D:\a\_temp\msys64\ucrt64\bin'] if ON_WINDOWS else []),
extra_compile_args=_comp_args,
)
]
Expand Down

0 comments on commit 92ddff5

Please sign in to comment.