diff --git a/.github/workflows/build_wheels.yml b/.github/workflows/build_wheels.yml index cb5cd9f9..d7306243 100644 --- a/.github/workflows/build_wheels.yml +++ b/.github/workflows/build_wheels.yml @@ -8,26 +8,36 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, macos-latest] - + os: [ubuntu-latest, macos-latest, windows-2022] 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-2022' }} - 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 @@ -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 @@ -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 diff --git a/scripts/before_ci_build.sh b/scripts/before_ci_build.sh deleted file mode 100644 index 1a580278..00000000 --- a/scripts/before_ci_build.sh +++ /dev/null @@ -1,28 +0,0 @@ -set -e -x - -GMP_VERSION=6.3.0 -MPFR_VERSION=4.2.1 -MPC_VERSION=1.3.1 -if [ ! -f finish_before_ci_build ]; then - if [[ "$OSTYPE" == "linux-gnu" || "$OSTYPE" == "linux-musl" || "$OSTYPE" == "darwin"* ]]; then - 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 && make -j4 && make install && cd ../ - 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 && make -j4 && make install && cd ../ - 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 && make -j4 && make install && cd ../ - fi - 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 diff --git a/scripts/before_ci_build_apple_silicon.sh b/scripts/before_ci_build_apple_silicon.sh index fde9d97f..5c51983a 100644 --- a/scripts/before_ci_build_apple_silicon.sh +++ b/scripts/before_ci_build_apple_silicon.sh @@ -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 @@ -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 diff --git a/scripts/cibw_before_all.sh b/scripts/cibw_before_all.sh new file mode 100644 index 00000000..9433dc9c --- /dev/null +++ b/scripts/cibw_before_all.sh @@ -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/ diff --git a/scripts/cibw_before_all_windows.bat b/scripts/cibw_before_all_windows.bat new file mode 100644 index 00000000..39b0f638 --- /dev/null +++ b/scripts/cibw_before_all_windows.bat @@ -0,0 +1,9 @@ +@echo on +cd .local\bin +set "PATH=C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.38.33130\bin\HostX86\x64\" +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 diff --git a/scripts/cibw_repair_wheel_command.sh b/scripts/cibw_repair_wheel_command.sh new file mode 100644 index 00000000..da659d2a --- /dev/null +++ b/scripts/cibw_repair_wheel_command.sh @@ -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 diff --git a/scripts/cibw_repair_wheel_command_windows.bat b/scripts/cibw_repair_wheel_command_windows.bat new file mode 100644 index 00000000..f8dbe625 --- /dev/null +++ b/scripts/cibw_repair_wheel_command_windows.bat @@ -0,0 +1,4 @@ +set WHEELHOUSE=%1 +set WHEELNAME=%2 + +msys2 -c scripts/cibw_repair_wheel_command_windows.sh diff --git a/scripts/cibw_repair_wheel_command_windows.sh b/scripts/cibw_repair_wheel_command_windows.sh new file mode 100644 index 00000000..3105800d --- /dev/null +++ b/scripts/cibw_repair_wheel_command_windows.sh @@ -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]) diff --git a/scripts/dll2lib.bat b/scripts/dll2lib.bat new file mode 100644 index 00000000..8b28d306 --- /dev/null +++ b/scripts/dll2lib.bat @@ -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 diff --git a/scripts/repair_ci_wheel.sh b/scripts/repair_ci_wheel.sh deleted file mode 100644 index 0c55b371..00000000 --- a/scripts/repair_ci_wheel.sh +++ /dev/null @@ -1,17 +0,0 @@ -dest_dir=$1 -wheel=$2 -wheel unpack --dest ${dest_dir} ${wheel} -cp /usr/local/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}/* -if [[ "$OSTYPE" == "darwin"* ]] -then - delocate-wheel --require-archs $3 --lib-sdir ../gmpy2.libs -w ${dest_dir} -v ${wheel} -else - auditwheel repair -w ${dest_dir} ${wheel} -fi -# 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) diff --git a/setup.py b/setup.py index f7e7dc82..fac0c365 100644 --- a/setup.py +++ b/setup.py @@ -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" @@ -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, ) ] diff --git a/test_cython/setup_cython.py b/test_cython/setup_cython.py index 319387e5..77e28853 100644 --- a/test_cython/setup_cython.py +++ b/test_cython/setup_cython.py @@ -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 = [