Build Wheels for Sequenzo #146
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # GitHub Actions workflow for Sequenzo package | |
| name: Build Wheels for Sequenzo | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| pull_request: | |
| branches: [ main ] | |
| workflow_dispatch: | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| jobs: | |
| build: | |
| name: Build ${{ matrix.os }} Py${{ matrix.python-version }} | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest, windows-latest] | |
| python-version: ['3.9', '3.10', '3.11', '3.12'] | |
| steps: | |
| - name: Checkout source with submodules | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Set up Python | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Ensure setuptools/wheel for macOS Python 3.12 | |
| if: runner.os == 'macOS' && matrix.python-version == '3.12' | |
| run: python -m pip install --upgrade pip setuptools wheel | |
| # Add OpenMP support | |
| - name: Install OpenMP (macOS) | |
| if: runner.os == 'macOS' | |
| run: | | |
| brew install libomp | |
| echo "CC=clang" >> $GITHUB_ENV | |
| echo "CXX=clang++" >> $GITHUB_ENV | |
| echo "LDFLAGS=-L$(brew --prefix libomp)/lib" >> $GITHUB_ENV | |
| echo "CPPFLAGS=-I$(brew --prefix libomp)/include" >> $GITHUB_ENV | |
| echo "SEQUENZO_ENABLE_OPENMP=1" >> $GITHUB_ENV | |
| - name: Install OpenMP (Linux) | |
| if: runner.os == 'Linux' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libomp-dev | |
| echo "SEQUENZO_ENABLE_OPENMP=1" >> $GITHUB_ENV | |
| - name: Setup MSVC with OpenMP (Windows) | |
| if: runner.os == 'Windows' | |
| uses: ilammy/msvc-dev-cmd@v1 | |
| with: | |
| arch: x64 | |
| - name: Enable OpenMP (Windows) | |
| if: runner.os == 'Windows' | |
| run: | | |
| echo "SEQUENZO_ENABLE_OPENMP=1" >> $env:GITHUB_ENV | |
| # Install dependencies with fallback strategy | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install --only-binary=all "numpy<2.5" || pip install "numpy<2.5" | |
| pip install --only-binary=all "scipy<1.16" || echo "scipy will be installed in cibuildwheel" | |
| pip install --prefer-binary Cython pybind11 build "cibuildwheel==2.23.3" twine | |
| pip install --prefer-binary fastcluster || echo "fastcluster installation attempted" | |
| - name: Build Cython wheels on macOS | |
| if: runner.os == 'macOS' | |
| run: | | |
| python setup.py build_ext --inplace | |
| python -m build | |
| - name: Clean previous build outputs | |
| if: runner.os != 'macOS' | |
| run: | | |
| rm -rf build/ dist/ *.egg-info | |
| find . -name "*.so" -delete | |
| shell: bash | |
| - name: Build wheels with cibuildwheel | |
| if: runner.os != 'macOS' | |
| run: python -m cibuildwheel --output-dir dist | |
| env: | |
| CIBW_SKIP: "*-musllinux* pp*" # 跳过 musllinux 和 PyPy | |
| CIBW_ARCHS_WINDOWS: "AMD64" | |
| CIBW_ARCHS_LINUX: "x86_64" | |
| CIBW_BUILD_VERBOSITY: "1" | |
| # Environment variables | |
| CIBW_ENVIRONMENT_LINUX: SEQUENZO_ENABLE_OPENMP=1 | |
| CIBW_ENVIRONMENT_WINDOWS: SEQUENZO_ENABLE_OPENMP=1 DISTUTILS_USE_SDK=1 | |
| # Linux: install system dependencies | |
| CIBW_BEFORE_BUILD_LINUX: > | |
| yum install -y libgomp-devel || | |
| apt-get update && apt-get install -y libomp-dev || | |
| echo "System dependencies installation attempted" | |
| # Windows: skip all extra dependencies, let setup.py handle them | |
| CIBW_BEFORE_BUILD_WINDOWS: > | |
| echo "Using setup.py dependencies only" | |
| # Universal dependency installation (fallback) | |
| CIBW_BEFORE_BUILD: > | |
| echo "Using setup.py dependencies only" | |
| # Test command | |
| CIBW_TEST_COMMAND: > | |
| python -c "import sequenzo; print('Sequenzo import successful'); | |
| import importlib; | |
| mod = importlib.util.find_spec('sequenzo.clustering.clustering_c_code'); | |
| print('C++ extensions loaded' if mod else 'WARNING: C++ extensions not found')" | |
| - name: Show dist content | |
| run: ls -lah dist/ | |
| shell: bash | |
| - name: Check wheels | |
| run: twine check dist/* | |
| - name: Verify OpenMP Support | |
| run: | | |
| echo "=== Verifying built wheels ===" | |
| python -c " | |
| import subprocess | |
| import sys | |
| import os | |
| wheel_files = [f for f in os.listdir('dist') if f.endswith('.whl') and 'cp${{ matrix.python-version }}' in f.replace('.', '')] | |
| if wheel_files: | |
| wheel_file = wheel_files[0] | |
| print(f'Installing wheel: {wheel_file}') | |
| subprocess.run([sys.executable, '-m', 'pip', 'install', '--force-reinstall', f'dist/{wheel_file}'], check=True) | |
| import sequenzo | |
| print('Sequenzo import successful') | |
| try: | |
| import sequenzo.clustering.clustering_c_code as cc | |
| print('C++ extensions loaded successfully') | |
| except ImportError as e: | |
| print(f'WARNING: C++ extensions loading failed: {e}') | |
| else: | |
| print('ERROR: No matching wheel files found') | |
| " | |
| shell: bash | |
| - name: Upload wheels | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: wheels-${{ matrix.os }}-${{ matrix.python-version }} | |
| path: dist/ |