Build Wheels #20
Workflow file for this run
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
| name: Build Wheels | |
| on: | |
| push: | |
| tags: [ 'v*' ] | |
| workflow_dispatch: | |
| jobs: | |
| build_wheels: | |
| name: Build wheels on ${{ matrix.os }} | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| include: | |
| - os: ubuntu-24.04 | |
| arch: x86_64 | |
| - os: windows-2022 | |
| arch: AMD64 | |
| - os: macos-13 | |
| arch: x86_64 | |
| - os: macos-14 | |
| arch: arm64 | |
| steps: | |
| - name: Checkout PyHelios | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 # Required for setuptools-scm | |
| # Ensure all tags are fetched | |
| fetch-tags: true | |
| - name: Debug version detection | |
| shell: bash | |
| run: | | |
| echo "=== Git tag information ===" | |
| git tag --list | head -10 | |
| echo "Current HEAD: $(git rev-parse HEAD)" | |
| echo "Describe: $(git describe --tags --always --dirty)" | |
| echo "=== Setuptools-scm version detection ===" | |
| python -m pip install setuptools-scm | |
| python -c "from setuptools_scm import get_version; print(f'Detected version: {get_version()}')" || echo "Version detection failed" | |
| - name: Set up Python | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: '3.8' # Use lowest supported version for compatibility | |
| - name: Setup MSVC (Windows) | |
| if: runner.os == 'Windows' | |
| uses: ilammy/msvc-dev-cmd@v1 | |
| - name: Install Helios dependencies (Linux) | |
| if: runner.os == 'Linux' | |
| run: | | |
| cd helios-core/utilities | |
| sudo bash dependencies.sh ALL | |
| - name: Install Helios dependencies (macOS) | |
| if: runner.os == 'macOS' | |
| run: | | |
| cd helios-core/utilities | |
| # Install base + visualization dependencies (no GPU/CUDA for macOS builds) | |
| bash dependencies.sh BASE | |
| bash dependencies.sh VIS | |
| - name: Debug environment (macOS) | |
| if: runner.os == 'macOS' | |
| run: | | |
| echo "=== Directory structure ===" | |
| ls -la | |
| echo "=== PyHelios build scripts ===" | |
| ls -la build_scripts/ | |
| echo "=== Helios core ===" | |
| ls -la helios-core/ || echo "helios-core not found" | |
| echo "=== Python version and location ===" | |
| python --version | |
| which python | |
| echo "=== Environment ===" | |
| env | grep -E "(PYTHON|PATH)" | head -10 | |
| - name: Install CUDA Toolkit (Windows) | |
| if: runner.os == 'Windows' | |
| shell: powershell | |
| run: | | |
| # Download CUDA 12.6 installer with integrity verification | |
| $installerUrl = "https://developer.download.nvidia.com/compute/cuda/12.6.2/network_installers/cuda_12.6.2_windows_network.exe" | |
| $expectedMD5 = "d109e3e1720d33f9ea75379c619e22a6" # Official MD5 hash from NVIDIA | |
| Write-Host "Downloading CUDA toolkit installer..." | |
| Invoke-WebRequest -Uri $installerUrl -OutFile "cuda_installer.exe" | |
| # Verify file integrity using official NVIDIA MD5 checksum | |
| Write-Host "Verifying installer integrity..." | |
| $actualMD5 = (Get-FileHash -Algorithm MD5 "cuda_installer.exe").Hash | |
| if ($actualMD5 -ne $expectedMD5) { | |
| Write-Error "CUDA installer MD5 verification failed!" | |
| Write-Error "Expected: $expectedMD5" | |
| Write-Error "Actual: $actualMD5" | |
| Write-Error "This may indicate a corrupted download or security issue." | |
| exit 1 | |
| } | |
| Write-Host "✓ Installer integrity verified using official NVIDIA MD5 checksum" | |
| # Install CUDA toolkit components needed for compilation | |
| Write-Host "Installing CUDA toolkit components..." | |
| Start-Process -FilePath ".\cuda_installer.exe" -ArgumentList "-s","nvcc_12.6","cudart_12.6","nvrtc_12.6","nvrtc_dev_12.6","visual_studio_integration_12.6" -Wait | |
| # Add CUDA to PATH for subsequent steps | |
| echo "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.6\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append | |
| Write-Host "✓ CUDA toolkit installation completed" | |
| - name: Install cibuildwheel and repair tools | |
| shell: bash | |
| run: | | |
| python -m pip install --upgrade pip | |
| python -m pip install cibuildwheel | |
| # Install platform-specific wheel repair tools | |
| if [ "${{ runner.os }}" = "Linux" ]; then | |
| python -m pip install auditwheel | |
| elif [ "${{ runner.os }}" = "macOS" ]; then | |
| python -m pip install delocate | |
| fi | |
| - name: Debug version detection | |
| shell: bash | |
| run: | | |
| echo "=== Version Detection Debug ===" | |
| echo "Git describe: $(git describe --tags --long --dirty)" | |
| echo "Git tags:" | |
| git tag -l --sort=-version:refname | head -10 | |
| echo "Git log (recent commits):" | |
| git log --oneline --decorate -5 | |
| pip install setuptools-scm | |
| echo "setuptools-scm version: $(python -m setuptools_scm)" | |
| echo "================================" | |
| - name: Build wheels | |
| run: python -m cibuildwheel --output-dir wheelhouse | |
| env: | |
| # Build for Python 3.8+ on all platforms | |
| CIBW_BUILD: cp38-* cp39-* cp310-* cp311-* cp312-* | |
| # Skip 32-bit builds and PyPy | |
| CIBW_SKIP: "*-win32 *-manylinux_i686 *-musllinux* pp*" | |
| # Architecture configuration based on runner | |
| CIBW_ARCHS: ${{ matrix.arch }} | |
| # Platform-specific build commands with broad CUDA compatibility | |
| CIBW_BEFORE_BUILD_MACOS: "python build_scripts/prepare_wheel.py --buildmode release --nogpu --verbose" | |
| CIBW_ENVIRONMENT_MACOS: "MACOSX_DEPLOYMENT_TARGET=14.0" | |
| CIBW_BEFORE_BUILD_WINDOWS: "set CMAKE_RC_COMPILER= && set PYHELIOS_CUDA_ARCHITECTURES=50;60;70;75;80;86;90 && python build_scripts/prepare_wheel.py --buildmode release --verbose" | |
| CIBW_BEFORE_BUILD_LINUX: "export PYHELIOS_CUDA_ARCHITECTURES=50;60;70;75;80;86;90 && python build_scripts/prepare_wheel.py --buildmode release --verbose" | |
| # Comprehensive wheel testing using pytest suite | |
| CIBW_TEST_COMMAND: | | |
| python -c " | |
| import pyhelios | |
| print(f'PyHelios {pyhelios.__version__} imported successfully') | |
| # Quick asset validation | |
| from pyhelios.assets import get_asset_manager | |
| manager = get_asset_manager() | |
| helios_build = manager._get_helios_build_path() | |
| if helios_build: | |
| print(f'HELIOS_BUILD assets found at: {helios_build}') | |
| else: | |
| raise RuntimeError('CRITICAL: HELIOS_BUILD assets not found') | |
| # Plugin status check | |
| from pyhelios.plugins import print_plugin_status | |
| print_plugin_status() | |
| print('Initial validation completed') | |
| " && | |
| python -m pytest {project}/tests/test_cross_platform.py {project}/tests/test_datatypes.py --tb=short -v | |
| CIBW_TEST_REQUIRES: "pytest pytest-forked" | |
| # Skip problematic platforms for testing | |
| CIBW_TEST_SKIP: "*-win32 *-manylinux_i686 *-musllinux*" | |
| # Repair wheels to bundle dependencies | |
| CIBW_REPAIR_WHEEL_COMMAND_MACOS: "delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel}" | |
| CIBW_REPAIR_WHEEL_COMMAND_LINUX: "auditwheel repair -w {dest_dir} {wheel}" | |
| - name: Debug build failure | |
| if: failure() | |
| shell: bash | |
| run: | | |
| echo "=== Build Failure Diagnostics ===" | |
| echo "Build directory contents:" | |
| find pyhelios_build -name "*.so" -o -name "*.dll" -o -name "*.dylib" 2>/dev/null || echo "No build directory found" | |
| echo "" | |
| echo "Plugin directory contents:" | |
| ls -la pyhelios/plugins/ 2>/dev/null || echo "No plugins directory found" | |
| echo "" | |
| echo "Wheel directory contents:" | |
| ls -la wheelhouse/ 2>/dev/null || echo "No wheelhouse directory found" | |
| echo "" | |
| echo "Python environment:" | |
| python --version | |
| pip list | grep -E "(cibuildwheel|auditwheel|delocate)" || echo "Wheel tools not found" | |
| - name: Upload wheels as artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: wheels-${{ matrix.os }}-${{ matrix.arch }} | |
| path: wheelhouse/*.whl | |
| retention-days: 7 | |
| test_wheels: | |
| name: Test wheels on ${{ matrix.os }} Python ${{ matrix.python-version }} | |
| runs-on: ${{ matrix.os }} | |
| needs: build_wheels | |
| strategy: | |
| matrix: | |
| include: | |
| - os: ubuntu-24.04 | |
| python-version: '3.8' | |
| - os: ubuntu-24.04 | |
| python-version: '3.11' | |
| - os: windows-2022 | |
| python-version: '3.8' | |
| - os: windows-2022 | |
| python-version: '3.11' | |
| - os: macos-13 | |
| python-version: '3.8' | |
| - os: macos-13 | |
| python-version: '3.11' | |
| - os: macos-14 | |
| python-version: '3.8' | |
| - os: macos-14 | |
| python-version: '3.11' | |
| steps: | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v4 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Download wheels | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: wheels-* | |
| merge-multiple: true | |
| path: wheelhouse | |
| - name: Install wheel | |
| run: | | |
| python -m pip install --upgrade pip | |
| python -m pip install --find-links wheelhouse --no-index pyhelios | |
| - name: Test basic functionality and asset validation | |
| run: | | |
| python -c " | |
| import pyhelios | |
| from pyhelios import Context, WeberPennTree, WPTType | |
| from pyhelios.types import vec2, vec3, RGBcolor | |
| print(f'PyHelios version: {pyhelios.__version__}') | |
| # Test basic Context operations | |
| context = Context() | |
| center = vec3(1, 2, 3) | |
| color = RGBcolor(0.5, 0.5, 0.5) | |
| uuid = context.addPatch(center=center, size=vec2(1, 1), color=color) | |
| print(f'Added patch with UUID: {uuid}') | |
| # Test plugin availability reporting | |
| from pyhelios.plugins import print_plugin_status | |
| print_plugin_status() | |
| # Comprehensive asset validation for pip-installed wheels | |
| print('\\n=== Asset Validation ===') | |
| from pyhelios.assets import get_asset_manager | |
| from pathlib import Path | |
| import os | |
| manager = get_asset_manager() | |
| # Test HELIOS_BUILD path resolution priority | |
| helios_build = manager._get_helios_build_path() | |
| if helios_build: | |
| print(f'HELIOS_BUILD path: {helios_build}') | |
| if 'pyhelios/assets/build' in str(helios_build): | |
| print('✓ Using pip-installed assets (correct priority)') | |
| else: | |
| print('⚠ Using development assets (check if intended)') | |
| else: | |
| print('✗ HELIOS_BUILD path not found') | |
| # Validate core assets exist | |
| package_root = Path(pyhelios.__file__).parent | |
| core_assets = package_root / 'assets' / 'build' / 'lib' / 'images' | |
| if core_assets.exists(): | |
| asset_files = list(core_assets.glob('*')) | |
| print(f'✓ Found {len(asset_files)} core asset files') | |
| for asset in asset_files[:3]: # Show first 3 | |
| print(f' - {asset.name}') | |
| else: | |
| print('✗ Core assets not found at expected location') | |
| # Test environment variable setting | |
| original_helios_build = os.environ.get('HELIOS_BUILD') | |
| manager.initialize() | |
| new_helios_build = os.environ.get('HELIOS_BUILD') | |
| if new_helios_build: | |
| print(f'✓ HELIOS_BUILD environment variable set: {new_helios_build}') | |
| else: | |
| print('✗ HELIOS_BUILD environment variable not set') | |
| # Test asset validation function | |
| validation_results = manager.validate_assets() | |
| total_assets = sum(result['files_found'] for result in validation_results.values()) | |
| print(f'✓ Asset validation completed: {total_assets} total assets found') | |
| print('Asset validation passed') | |
| " | |
| # publish: | |
| # name: Publish to PyPI | |
| # runs-on: ubuntu-latest | |
| # needs: [build_wheels, test_wheels] | |
| # if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') | |
| # environment: | |
| # name: pypi | |
| # url: https://pypi.org/p/pyhelios | |
| # permissions: | |
| # id-token: write # Required for trusted publishing | |
| # | |
| # steps: | |
| # - name: Download all wheels | |
| # uses: actions/download-artifact@v4 | |
| # with: | |
| # pattern: wheels-* | |
| # merge-multiple: true | |
| # path: wheelhouse | |
| # | |
| # - name: Publish to PyPI | |
| # uses: pypa/gh-action-pypi-publish@release/v1 | |
| # with: | |
| # packages-dir: wheelhouse/ | |
| # verify-metadata: false # Skip metadata verification due to dynamic versioning |