diff --git a/.github/workflows/build_and_publish.yml b/.github/workflows/build_and_publish.yml new file mode 100644 index 0000000..b144665 --- /dev/null +++ b/.github/workflows/build_and_publish.yml @@ -0,0 +1,94 @@ +name: build_and_publish +on: + pull_request: + push: + branches: + - master + - wheels + release: + types: [published] + workflow_dispatch: + +concurrency: + group: wheels-${{ github.event_name }}-${{ github.ref_name }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + build_wheels: + name: build wheels (${{ matrix.os }}, ${{ matrix.build }}) + runs-on: ${{ matrix.os }} + env: + CIBW_BUILD: '${{ matrix.build }}-*' + CIBW_SKIP: '*i686 *win32 *s390x *ppc64le *musllinux* *aarch64' + CIBW_BUILD_VERBOSITY: 1 + CIBW_TEST_COMMAND: python -c "import pygtide; pygtide.test(); pygtide.update(); pygtide.test()" + MACOSX_DEPLOYMENT_TARGET: 15.0 + # Package the DLL dependencies in the wheel for windows + # delvewheel cannot mangle the libraries, stripping does not work. + CIBW_BEFORE_BUILD_WINDOWS: pip install delvewheel + CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: "delvewheel show {wheel} && delvewheel repair -w {dest_dir} {wheel} --no-mangle-all" + + strategy: + # for pushes to master, we only build a subset of wheels + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + build: [cp312, cp313, cp314] + exclude-flag: + - ${{ github.event_name != 'release' }} + exclude: + - build: cp12 + exclude-flag: true + - build: cp13 + exclude-flag: true + steps: + - uses: actions/checkout@v6 + + - uses: fortran-lang/setup-fortran@v1 + id: setup-fortran + with: + compiler: gcc + + - name: Build wheels + uses: pypa/cibuildwheel@v3.3.1 + + - uses: actions/upload-artifact@v6 + with: + name: cibw-wheels-${{ matrix.os }}-${{ matrix.build }}-${{ strategy.job-index }} + path: ./wheelhouse/*.whl + + build_sdist: + name: build sdist + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - name: Set up Python + uses: actions/setup-python@v6 + - name: Install build + shell: bash -l {0} + run: >- + python -m + pip install build --user + - name: Build a source tarball + shell: bash -l {0} + run: >- + python -m build + - uses: actions/upload-artifact@v6 + with: + name: sdist + path: dist/*.tar.gz + + publish: + name: publish release + if: github.event_name == 'release' + needs: [build_sdist, build_wheels] + runs-on: ubuntu-latest + steps: + - uses: actions/download-artifact@v7 + with: + path: dist + merge-multiple: true + - uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.PYPI }} diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml deleted file mode 100644 index 6061ded..0000000 --- a/.github/workflows/pypi.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: pypi -on: - release: - types: [published] - workflow_dispatch: - -jobs: - build_sdist: - name: build sdist - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - name: Set up Python - uses: actions/setup-python@v6 - - name: Install build - shell: bash -l {0} - run: >- - python -m - pip install build --user - - name: Build a source tarball - shell: bash -l {0} - run: >- - python -m build - - uses: actions/upload-artifact@v6 - with: - path: dist/*.tar.gz - - publish: - name: publish release - needs: [build_sdist] - runs-on: ubuntu-latest - steps: - - uses: actions/download-artifact@v7 - with: - name: artifact - path: dist - - uses: pypa/gh-action-pypi-publish@release/v1 - with: - user: __token__ - password: ${{ secrets.PYPI }} diff --git a/README.md b/README.md index 63b31d4..3bf7e75 100644 --- a/README.md +++ b/README.md @@ -24,13 +24,13 @@ There are two options: ### Installation options -#### Option 1: Install and compile source distribution from PyPi (Linux, macOS, Windows; Python 3.8–3.14) +#### Option 1: Install and compile source distribution from PyPi (Python 3.8–3.11) or install pre-compiled distribution (Linux, macOS, Windows; Python>=3.12) ```bash pip install pygtide ``` -#### Option 2: Build from source locally (Linux, macOS, Windows; Python 3.8–3.14) +#### Option 2: Build from source locally (Linux, macOS, Windows; Python>=3.8) **Requirements for building:** - A Fortran compiler (e.g., `gfortran` via MinGW on Windows; included in Linux/macOS gcc toolchains) `conda install gfortran` @@ -53,12 +53,6 @@ If Meson or Ninja are missing, pip will attempt to install them automatically. F pip install meson-python meson ninja ``` -#### Option 3: Pre-built wheels (Windows, Python 3.8–3.11) -Download the correct wheel for your Python version from the `windows/` subfolder and install: -```powershell -pip install [wheel_name_depending_on_python_version] -``` - ### After installation * Run tests to verify installation: diff --git a/setup.py b/setup.py index e6bd871..0d29f14 100644 --- a/setup.py +++ b/setup.py @@ -2,39 +2,39 @@ from pathlib import Path import sys -from setuptools import setup, Extension +from setuptools import setup, Distribution from setuptools.command.build import build as _build class build(_build): def run(self): # Detect platform-specific ABI extension - HERE = Path(__file__).resolve().parent - + here = Path(__file__).resolve().parent ext = '.pyd' if sys.platform.startswith('win') else '.so' - etpred_path = HERE / 'pygtide' / f'etpred{ext}' - + etpred_path = here / 'pygtide' / f'etpred{ext}' if etpred_path.exists(): print(f"Use ABI module {etpred_path}") else: print(f"Prebuilt ABI module not found: {etpred_path}\n" "Run build_pygtide_abi.py") - sys.path.insert(0, str(HERE)) + sys.path.insert(0, str(here)) import build_pygtide_abi + # Start Meson build build_pygtide_abi.build() if not etpred_path.exists(): raise FileNotFoundError(f"No ABI module, error in Meson build") + super().run() - # Define the prebuilt extension - etpred_module = Extension( - name='pygtide.etpred', - sources=[], # No sources; using prebuilt ABI - extra_objects=[str(etpred_path)], - ) - - super().run() +# tell setuptools to build platform-dependent wheels +class BinaryDistribution(Distribution): + def has_ext_modules(self): + return True # Metadata pulled from pyproject.toml -setup(cmdclass={'build': build}) +setup( + distclass=BinaryDistribution, + cmdclass={'build': build} +) +