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 9, 2024
1 parent eb8dfcb commit d0c2829
Show file tree
Hide file tree
Showing 12 changed files with 166 additions and 105 deletions.
39 changes: 22 additions & 17 deletions .github/workflows/build_wheels.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,36 @@ 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:
install: >-
mingw-w64-ucrt-x86_64-gcc
autotools
msystem: ucrt64
path-type: inherit
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_BEFORE_BUILD: bash scripts/before_ci_build.sh
CIBW_SKIP: pp* *-win32
CIBW_BEFORE_ALL: bash scripts/cibw_before_all.sh
CIBW_BEFORE_ALL_WINDOWS: >
msys2 -c scripts/cibw_before_all.sh &&
scripts\cibw_before_all_windows.bat
CIBW_BEFORE_BUILD_WINDOWS: pip install delvewheel
CIBW_TEST_EXTRAS: tests
CIBW_TEST_COMMAND: >
pytest {package}/test/ &&
python {package}/test_cython/runtests.py
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}
CIBW_REPAIR_WHEEL_COMMAND: >
bash scripts/cibw_repair_wheel_command.sh {dest_dir} {wheel}
CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: >
scripts\cibw_repair_wheel_command_windows.bat {dest_dir} {wheel}
- uses: actions/upload-artifact@v3
with:
name: wheels
Expand All @@ -39,12 +49,10 @@ 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
Expand All @@ -54,9 +62,6 @@ jobs:
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
28 changes: 0 additions & 28 deletions scripts/before_ci_build.sh

This file was deleted.

7 changes: 4 additions & 3 deletions scripts/before_ci_build_apple_silicon.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ MPC_VERSION=1.3.1
export CPPFLAGS=" --target=arm64-apple-macos11"
export LDFLAGS=" -arch arm64"
EXTRA="--build=x86_64-apple-darwin --host=aarch64-apple-darwin --target=aarch64-apple-darwin"
PREFIX="$(pwd)/.local/"
if [ ! -f finish_before_ci_build ]; then
if [[ "$OSTYPE" == "linux-gnu" || "$OSTYPE" == "linux-musl" || "$OSTYPE" == "darwin"* ]]; then
curl -O https://ftp.gnu.org/gnu/gmp/gmp-${GMP_VERSION}.tar.xz
Expand All @@ -14,13 +15,13 @@ if [ ! -f finish_before_ci_build ]; then
# that use build machine micro-architecure. configfsf.guess is the one that
# comes with autotools which is micro-architecture agnostic.
# config.guess is a custom gmp script which knows about micro-architectures.
cd gmp-${GMP_VERSION} && ./configure $EXTRA --enable-fat && make -j4 && make install && cd ../
cd gmp-${GMP_VERSION} && ./configure $EXTRA --enable-fat --prefix=$PREFIX && make -j4 && make install && cd ../
curl -O -k https://ftp.gnu.org/gnu/mpfr/mpfr-${MPFR_VERSION}.tar.gz
tar -xf mpfr-${MPFR_VERSION}.tar.gz
cd mpfr-${MPFR_VERSION} && ./configure $EXTRA && make -j4 && make install && cd ../
cd mpfr-${MPFR_VERSION} && ./configure $EXTRA --prefix=$PREFIX --with-gmp=$PREFIX && make -j4 && make install && cd ../
curl -O https://ftp.gnu.org/gnu/mpc/mpc-${MPC_VERSION}.tar.gz
tar -xf mpc-${MPC_VERSION}.tar.gz
cd mpc-${MPC_VERSION} && ./configure $EXTRA && make -j4 && make install && cd ../
cd mpc-${MPC_VERSION} && ./configure $EXTRA --prefix=$PREFIX --with-gmp=$PREFIX --with-mpfr=$PREFIX && make -j4 && make install && cd ../
fi
touch finish_before_ci_build
else
Expand Down
52 changes: 52 additions & 0 deletions scripts/cibw_before_all.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/bin/bash

set -e -x

GMP_VERSION=6.3.0
MPFR_VERSION=4.2.1
MPC_VERSION=1.3.1

PREFIX="$(pwd)/.local/"

# -- 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 \
--prefix=$PREFIX
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 \
--with-gmp=$PREFIX \
--prefix=$PREFIX
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 \
--with-gmp=$PREFIX \
--with-mpfr=$PREFIX \
--prefix=$PREFIX
make -j6
make install
cd ../

# -- copy headers --
cp $PREFIX/include/{gmp,mpfr,mpc}.h gmpy2/
9 changes: 9 additions & 0 deletions scripts/cibw_before_all_windows.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@echo on
cd .local\bin
set "PATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.29.30133\bin\HostX86\x86\"
call D:\a\gmpy\gmpy\scripts\dll2lib.bat 64 libgmp-10.dll
call D:\a\gmpy\gmpy\scripts\dll2lib.bat 64 libmpfr-6.dll
call D:\a\gmpy\gmpy\scripts\dll2lib.bat 64 libmpc-3.dll
ren libgmp-10.lib gmp.lib
ren libmpfr-6.lib mpfr.lib
ren libmpc-3.lib mpc.lib
12 changes: 12 additions & 0 deletions scripts/cibw_repair_wheel_command.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/bin/bash

DEST_DIR=$1
WHEEL=$2
LD_LIBRARY_PATH="$(pwd)/.local/lib:$LD_LIBRARY_PATH"

if [[ "$OSTYPE" == "darwin"* ]]
then
delocate-wheel --lib-sdir ../gmpy2.libs -w ${DEST_DIR} -v ${WHEEL}
else
auditwheel repair -w ${DEST_DIR} ${WHEEL}
fi
4 changes: 4 additions & 0 deletions scripts/cibw_repair_wheel_command_windows.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
set WHEELHOUSE=%1
set WHEELNAME=%2

msys2 -c scripts/cibw_repair_wheel_command_windows.sh
11 changes: 11 additions & 0 deletions scripts/cibw_repair_wheel_command_windows.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash

set -e -x

wheel=$WHEELNAME
dest_dir=$WHEELHOUSE

delvewheel repair ${wheel} -w ${dest_dir} --add-path .local/bin --no-mangle-all

cp .local/bin/{gmp,mpfr,mpc}.lib ${dest_dir}
(cd ${dest_dir}; wheel unpack --dest . gmpy2-*.whl; mv *.lib gmpy2-*/gmpy2.libs; wheel pack gmpy2-*[0-9]; rm -rf gmpy2-*[0-9])
35 changes: 35 additions & 0 deletions scripts/dll2lib.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
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
if "%1"=="32" (set machine=x86) else (set machine=x64)
cd %~p2
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
17 changes: 0 additions & 17 deletions scripts/repair_ci_wheel.sh

This file was deleted.

42 changes: 10 additions & 32 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,41 +1,19 @@
import os
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
if os.getenv('CIBUILDWHEEL'):
include_dirs = [os.path.join(os.path.dirname(__file__), '.local', 'include')]
library_dirs = [os.path.join(os.path.dirname(__file__), '.local',
'bin' if ON_WINDOWS else 'lib')]
else:
for filename in winlibs:
try:
(dst / filename).unlink()
except(FileNotFoundError):
pass
include_dirs = []
library_dirs = []

class Gmpy2Build(build_ext):
description = "Build gmpy2 with custom build options"
Expand Down Expand Up @@ -95,9 +73,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=include_dirs,
libraries=['mpc','mpfr','gmp'],
library_dirs=library_dirs,
extra_compile_args=_comp_args,
)
]
Expand Down
15 changes: 7 additions & 8 deletions test_cython/setup_cython.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@
library_dirs = sys.path + [gmpy2_packagedir]
libnames = ['mpc','mpfr','gmp']

if platform.system() != 'Windows':
bundled_libs = gmpy2_packagedir+'/../gmpy2.libs/'
if os.path.isdir(bundled_libs):
library_dirs += [bundled_libs]
if platform.system() == 'Linux':
libnames = [':' + d for d in os.listdir(bundled_libs)]
else:
libnames = [':' + bundled_libs + d for d in os.listdir(bundled_libs)]
bundled_libs = os.path.join(gmpy2_packagedir, '..', 'gmpy2.libs')
if os.path.isdir(bundled_libs):
library_dirs += [bundled_libs]
if platform.system() == 'Linux':
libnames = [':' + d for d in os.listdir(bundled_libs)]
elif platform.system() == 'Darwin':
libnames = [':' + bundled_libs + d for d in os.listdir(bundled_libs)]


extensions = [
Expand Down

0 comments on commit d0c2829

Please sign in to comment.