Structure #841
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: Python Artifacts | |
| env: | |
| TRIGGER_ON_PR_PUSH: true # Set to true to enable triggers on PR pushes | |
| on: | |
| push: | |
| branches: | |
| - main | |
| - dev | |
| - development | |
| - master | |
| tags: | |
| - 'py-*' | |
| pull_request: | |
| branches: | |
| - main | |
| - dev | |
| - development | |
| - master | |
| workflow_dispatch: | |
| inputs: | |
| sha: | |
| description: Commit SHA | |
| type: string | |
| dry_run: | |
| description: 'Dry run (build but not publish)' | |
| type: boolean | |
| default: true | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| defaults: | |
| run: | |
| shell: bash | |
| jobs: | |
| check_pr_push: | |
| runs-on: ubuntu-latest | |
| if: | | |
| github.event_name == 'pull_request' && github.event.action != 'closed' || | |
| github.event_name == 'push' && contains(fromJSON('["main", "master", "dev", "development"]'), github.ref_name) || | |
| github.event_name == 'push' && startsWith(github.ref, 'refs/tags/py-') | |
| outputs: | |
| run: ${{ steps.check.outputs.run }} | |
| steps: | |
| - name: Check if should run on PR push | |
| id: check | |
| run: | | |
| # Always run on tag pushes (py-* tags trigger releases) | |
| if [ "${{ github.event_name }}" = "push" ] && [[ "${{ github.ref }}" == refs/tags/py-* ]]; then | |
| echo "run=true" >> $GITHUB_OUTPUT | |
| # Always run on pushes to main branches | |
| elif [ "${{ github.event_name }}" = "push" ] && [[ "${{ github.ref_name }}" =~ ^(main|master|dev|development)$ ]]; then | |
| echo "run=true" >> $GITHUB_OUTPUT | |
| # For PRs, check the TRIGGER_ON_PR_PUSH setting | |
| elif [ "${{ github.event_name }}" = "pull_request" ] && [ "${{ env.TRIGGER_ON_PR_PUSH }}" = "true" ]; then | |
| echo "run=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "run=false" >> $GITHUB_OUTPUT | |
| fi | |
| build_wheelspecos_rslib: | |
| needs: check_pr_push | |
| if: needs.check_pr_push.result == 'success' && needs.check_pr_push.outputs.run == 'true' | |
| runs-on: ${{ matrix.runner || matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # Linux x86_64 with CUDA support (uses GCC Toolset 13 for CUDA compatibility) | |
| - os: ubuntu-latest | |
| architecture: x86_64 | |
| cibw_archs: x86_64 | |
| cuda_feature: "--features cuda" | |
| install_cuda: true | |
| # GCC Toolset 13 paths for CUDA compatibility | |
| gcc_path_prefix: "/opt/rh/gcc-toolset-13/root/usr/bin:" | |
| gcc_ld_path: "/opt/rh/gcc-toolset-13/root/usr/lib64:/opt/rh/gcc-toolset-13/root/usr/lib:" | |
| gcc_cc: "/opt/rh/gcc-toolset-13/root/usr/bin/gcc" | |
| gcc_cxx: "/opt/rh/gcc-toolset-13/root/usr/bin/g++" | |
| # Linux aarch64 - DISABLED: LLVM 14 not available in manylinux_2_28 (AlmaLinux 8) | |
| # The prebuilt LLVM 14 binary is incompatible with the container, and | |
| # the llvm-toolset module only provides LLVM 13. Re-enable when we have | |
| # a solution (custom Docker image, build from source, or inkwell LLVM 13 support) | |
| # - os: ubuntu-24.04-arm | |
| # architecture: aarch64 | |
| # runner: ubuntu-24.04-arm | |
| # cibw_archs: aarch64 | |
| # cuda_feature: "" | |
| # install_cuda: false | |
| # gcc_path_prefix: "" | |
| # gcc_ld_path: "" | |
| # gcc_cc: "" | |
| # gcc_cxx: "" | |
| # macOS without CUDA (NVIDIA dropped macOS CUDA support in 2019) | |
| # Use macos-15 (not macos-14) because Xcode 15.4's libc++ has a | |
| # pointer_traits bug with CXX crate's contiguous iterators in C++20. | |
| - os: macos-15 | |
| architecture: aarch64 | |
| cuda_feature: "" | |
| install_cuda: false | |
| - os: macos-15-intel | |
| architecture: x86_64 | |
| cuda_feature: "" | |
| install_cuda: false | |
| # Windows x86_64 with CUDA support | |
| # Note: Uses specific sub-packages to avoid VS integration bug (see Jimver/cuda-toolkit#382) | |
| - os: windows-2022 | |
| architecture: x86_64 | |
| cuda_feature: "--features cuda" | |
| install_cuda: true | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ inputs.sha || github.sha }} | |
| submodules: recursive | |
| # Set up Visual Studio environment on Windows (required for nvcc to find cl.exe) | |
| - name: Set up Visual Studio environment (Windows) | |
| if: runner.os == 'Windows' && matrix.install_cuda | |
| uses: ilammy/msvc-dev-cmd@v1 | |
| with: | |
| arch: x64 | |
| # Install CUDA on Windows before cibuildwheel (cibuildwheel runs on host, not in containers) | |
| # Uses specific sub-packages to avoid VS 17.3.x bug that hangs on NSight/VS Integration | |
| # See: https://github.com/Jimver/cuda-toolkit/issues/382 | |
| - name: Install CUDA Toolkit (Windows) | |
| if: runner.os == 'Windows' && matrix.install_cuda | |
| uses: Jimver/cuda-toolkit@v0.2.30 | |
| with: | |
| cuda: '12.5.1' | |
| method: 'local' | |
| sub-packages: '["nvcc", "cudart", "cublas", "cublas_dev", "thrust"]' | |
| # On Windows, Git Bash's /usr/bin/link.exe shadows MSVC's link.exe. | |
| # Create .cargo/config.toml with the explicit MSVC linker path so cargo | |
| # uses the correct linker inside cibuildwheel (which runs on the host). | |
| - name: Configure MSVC linker for Cargo (Windows) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| $vsWhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" | |
| $vsPath = & $vsWhere -latest -property installationPath | |
| $linkPath = Get-ChildItem -Path "$vsPath\VC\Tools\MSVC" -Recurse -Filter "link.exe" | | |
| Where-Object { $_.FullName -like "*\bin\Hostx64\x64\*" } | | |
| Select-Object -First 1 -ExpandProperty FullName | |
| if ($linkPath) { | |
| $escapedPath = $linkPath.Replace('\', '/') | |
| $configContent = "[target.x86_64-pc-windows-msvc]`nlinker = `"$escapedPath`"" | |
| # Create in repo root (for CIBW_BEFORE_ALL cargo commands) | |
| New-Item -ItemType Directory -Force -Path .cargo | Out-Null | |
| $configContent | Out-File -FilePath ".cargo\config.toml" -Encoding UTF8 | |
| # Create in pecos-rslib directory (for maturin builds) | |
| New-Item -ItemType Directory -Force -Path "python\pecos-rslib\.cargo" | Out-Null | |
| $configContent | Out-File -FilePath "python\pecos-rslib\.cargo\config.toml" -Encoding UTF8 | |
| # Create in user cargo home (fallback) | |
| $cargoHome = if ($env:CARGO_HOME) { $env:CARGO_HOME } else { "$env:USERPROFILE\.cargo" } | |
| New-Item -ItemType Directory -Force -Path $cargoHome | Out-Null | |
| if (Test-Path "$cargoHome\config.toml") { | |
| "`n$configContent" | Out-File -FilePath "$cargoHome\config.toml" -Encoding UTF8 -Append | |
| } else { | |
| $configContent | Out-File -FilePath "$cargoHome\config.toml" -Encoding UTF8 | |
| } | |
| Write-Host "Configured MSVC linker: $linkPath" | |
| } else { | |
| Write-Error "Could not find MSVC link.exe" | |
| exit 1 | |
| } | |
| - name: Build wheels | |
| uses: pypa/cibuildwheel@v3.3.1 | |
| with: | |
| package-dir: python/pecos-rslib | |
| output-dir: wheelhouse | |
| env: | |
| # Build configuration | |
| CIBW_BUILD: "cp310-*" | |
| CIBW_SKIP: "*-win32 *-manylinux_i686 *-musllinux*" | |
| CIBW_ARCHS_LINUX: ${{ matrix.cibw_archs }} | |
| CIBW_MANYLINUX_X86_64_IMAGE: "manylinux_2_28" | |
| CIBW_MANYLINUX_AARCH64_IMAGE: "manylinux_2_28" | |
| # Linux configuration - GCC Toolset and CUDA paths are conditional via matrix variables | |
| CIBW_ENVIRONMENT_LINUX: > | |
| PATH=${{ matrix.gcc_path_prefix }}$HOME/.cargo/bin:$HOME/.pecos/llvm/bin:/usr/local/cuda-12.6/bin:$PATH | |
| LD_LIBRARY_PATH=${{ matrix.gcc_ld_path }}$LD_LIBRARY_PATH | |
| LLVM_SYS_140_PREFIX=$HOME/.pecos/llvm | |
| CUDA_PATH=/usr/local/cuda-12.6 | |
| MATURIN_PEP517_ARGS="${{ matrix.cuda_feature }}" | |
| CIBW_BEFORE_ALL_LINUX: | | |
| curl -sSf https://sh.rustup.rs | sh -s -- -y | |
| source $HOME/.cargo/env | |
| dnf install libffi-devel -y | |
| # Install CUDA Toolkit for GPU support on x86_64 (compile-time only, no GPU needed) | |
| if [ "${{ matrix.install_cuda }}" = "true" ]; then | |
| echo "Installing GCC 13 (required for CUDA 12.6 compatibility)..." | |
| dnf install -y gcc-toolset-13 | |
| source /opt/rh/gcc-toolset-13/enable | |
| echo "Installing CUDA Toolkit from NVIDIA repos..." | |
| dnf config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/cuda-rhel8.repo | |
| dnf install -y cuda-nvcc-12-6 cuda-cudart-devel-12-6 libcublas-devel-12-6 | |
| export CUDA_PATH=/usr/local/cuda-12.6 | |
| export PATH=$CUDA_PATH/bin:$PATH | |
| echo "CUDA installed at $CUDA_PATH" | |
| nvcc --version | |
| gcc --version | |
| else | |
| echo "Skipping CUDA installation (GPU support not enabled for this build)" | |
| fi | |
| cargo run --release -p pecos --features cli -- install llvm --force | |
| CIBW_REPAIR_WHEEL_COMMAND_LINUX: > | |
| auditwheel repair -w {dest_dir} {wheel} && | |
| pipx run abi3audit --strict --report {wheel} | |
| # macOS configuration | |
| CIBW_ENVIRONMENT_MACOS: > | |
| PATH=$HOME/.cargo/bin:$HOME/.pecos/llvm/bin:$PATH | |
| LLVM_SYS_140_PREFIX=$HOME/.pecos/llvm | |
| MACOSX_DEPLOYMENT_TARGET=13.2 | |
| CIBW_BEFORE_ALL_MACOS: | | |
| curl -sSf https://sh.rustup.rs | sh -s -- -y | |
| source $HOME/.cargo/env | |
| rustup update | |
| cargo run --release -p pecos --features cli -- install llvm --force | |
| # Create a codesign wrapper that strips DYLD_LIBRARY_PATH to prevent | |
| # crashes on macOS 15 when bundled libc++ conflicts with system libc++ | |
| mkdir -p $HOME/.pecos/bin | |
| printf '#!/bin/bash\nunset DYLD_LIBRARY_PATH\nexec /usr/bin/codesign "$@"\n' > $HOME/.pecos/bin/codesign | |
| chmod +x $HOME/.pecos/bin/codesign | |
| CIBW_REPAIR_WHEEL_COMMAND_MACOS: > | |
| PATH=$HOME/.pecos/bin:$PATH DYLD_LIBRARY_PATH=$HOME/.pecos/llvm/lib delocate-wheel --require-archs {delocate_archs} -w {dest_dir} -v {wheel} && | |
| pipx run abi3audit --strict --report {wheel} | |
| # Windows configuration - CUDA via Jimver/cuda-toolkit (installed before cibuildwheel) | |
| CIBW_ENVIRONMENT_WINDOWS: > | |
| PATH="C:\\Users\\runneradmin\\.pecos\\llvm\\bin;$PATH" | |
| LLVM_SYS_140_PREFIX="C:\\Users\\runneradmin\\.pecos\\llvm" | |
| MATURIN_PEP517_ARGS="${{ matrix.cuda_feature }}" | |
| CIBW_BEFORE_ALL_WINDOWS: > | |
| echo "=== Installing LLVM using pecos ===" && | |
| rustup update && | |
| echo "=== Running pecos install llvm ===" && | |
| cargo run --release -p pecos --features cli -- install llvm --force && | |
| echo "=== Checking LLVM installation ===" && | |
| (test -d "C:\\Users\\runneradmin\\.pecos\\llvm" && echo "LLVM directory exists" && ls -la "C:\\Users\\runneradmin\\.pecos\\llvm" && (ls -la "C:\\Users\\runneradmin\\.pecos\\llvm\\bin" || echo "bin directory not found")) || (echo "ERROR: LLVM directory not found!" && exit 1) && | |
| echo "=== Verifying LLVM_SYS_140_PREFIX ===" && | |
| echo "LLVM_SYS_140_PREFIX will be set to: C:\\Users\\runneradmin\\.pecos\\llvm" | |
| # Install delvewheel and patch it to ignore ext-ms-win-* API sets | |
| # (delvewheel ignores api-ms-win-* but not ext-ms-win-* which are also Windows API sets) | |
| CIBW_BEFORE_BUILD_WINDOWS: > | |
| pip install delvewheel && | |
| python -c "import delvewheel._dll_list as d,inspect,re as r;p=inspect.getfile(d);c=open(p).read();n=chr(10);open(p,'w').write(c.replace(r\"re.compile('api-.*'),\",r\"re.compile('api-.*'),\"+n+r\" re.compile('ext-.*'),\")) if 'ext-.*' not in c else None" | |
| # Note: --no-dll excludes Windows system DLLs that should not be bundled | |
| # combase.dll and rmclient.dll are core Windows components that fail when bundled | |
| CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: > | |
| delvewheel repair -v --add-path "C:\\Users\\runneradmin\\.pecos\\llvm\\bin" --no-dll "combase.dll;rmclient.dll" -w {dest_dir} {wheel} && | |
| pipx run abi3audit --strict --report {wheel} | |
| - name: Upload wheels | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: wheel-pecos-rslib-${{ matrix.os }}-${{ matrix.architecture }} | |
| path: ./wheelhouse/*.whl | |
| test_abi3_wheels: | |
| needs: build_wheelspecos_rslib | |
| if: | | |
| always() && | |
| needs.build_wheelspecos_rslib.result == 'success' | |
| runs-on: ${{ matrix.platform.runner }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] | |
| platform: | |
| - runner: ubuntu-latest | |
| os: ubuntu-latest | |
| architecture: x86_64 | |
| - runner: windows-latest | |
| os: windows-2022 | |
| architecture: x86_64 | |
| - runner: macos-15-intel | |
| os: macos-15-intel | |
| architecture: x86_64 | |
| - runner: macos-15 | |
| os: macos-15 | |
| architecture: aarch64 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ inputs.sha || github.sha }} | |
| - name: Set up Python ${{ matrix.python-version }} | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| - name: Download abi3 wheel | |
| uses: actions/download-artifact@v7 | |
| with: | |
| name: wheel-pecos-rslib-${{ matrix.platform.os }}-${{ matrix.platform.architecture }} | |
| path: ./pecos-rslib-wheel | |
| - name: Test abi3 wheel with Python ${{ matrix.python-version }} | |
| run: | | |
| echo "Testing abi3 wheel with Python ${{ matrix.python-version }}" | |
| python --version | |
| pip install --force-reinstall --verbose ./pecos-rslib-wheel/*.whl | |
| python -c 'import pecos_rslib; print(f"pecos_rslib version: {pecos_rslib.__version__}")' | |
| python -c 'import sys; print(f"Python version: {sys.version}")' | |
| - name: Debug DLL loading (Windows) | |
| if: failure() && runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| Write-Host "=== Listing wheel contents ===" | |
| $wheelFile = Get-ChildItem -Path ./pecos-rslib-wheel/*.whl | Select-Object -First 1 | |
| python -m zipfile -l $wheelFile | |
| Write-Host "`n=== Finding pecos_rslib installation ===" | |
| $sitePackages = python -c "import site; print(site.getsitepackages()[0])" | |
| Write-Host "Site packages: $sitePackages" | |
| Write-Host "`n=== Listing pecos_rslib directory ===" | |
| Get-ChildItem -Path "$sitePackages\pecos_rslib*" -Recurse | Select-Object FullName, Length | |
| Write-Host "`n=== Checking DLL dependencies with dumpbin ===" | |
| $pydFile = Get-ChildItem -Path "$sitePackages\pecos_rslib\*.pyd" -ErrorAction SilentlyContinue | Select-Object -First 1 | |
| if ($pydFile) { | |
| & "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\bin\Hostx64\x64\dumpbin.exe" /dependents $pydFile.FullName 2>&1 | Select-Object -First 50 | |
| } | |
| Write-Host "`n=== Checking pecos_rslib.libs directory ===" | |
| $libsDir = "$sitePackages\pecos_rslib.libs" | |
| if (Test-Path $libsDir) { | |
| Get-ChildItem -Path $libsDir | ForEach-Object { | |
| Write-Host "DLL: $($_.Name)" | |
| & "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.44.35207\bin\Hostx64\x64\dumpbin.exe" /dependents $_.FullName 2>&1 | Select-Object -First 30 | |
| } | |
| } else { | |
| Write-Host "No pecos_rslib.libs directory found" | |
| } | |
| build_sdist_quantum_pecos: | |
| needs: build_wheelspecos_rslib | |
| if: | | |
| always() && | |
| needs.build_wheelspecos_rslib.result == 'success' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ inputs.sha || github.sha }} | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.10' | |
| - name: Download pecos-rslib wheel | |
| uses: actions/download-artifact@v7 | |
| with: | |
| name: wheel-pecos-rslib-ubuntu-latest-x86_64 | |
| path: ./pecos-rslib-wheel | |
| - name: Install pecos-rslib | |
| run: pip install ./pecos-rslib-wheel/*.whl | |
| - name: Install build dependencies | |
| run: pip install build | |
| - name: Build quantum-pecos SDist | |
| run: | | |
| cd python/quantum-pecos | |
| python -m build --sdist --outdir dist | |
| - name: Test quantum-pecos SDist | |
| run: | | |
| pip install python/quantum-pecos/dist/*.tar.gz | |
| python -c 'import pecos; print(pecos.__version__)' | |
| - name: Upload quantum-pecos SDist | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: sdist-quantum-pecos | |
| path: python/quantum-pecos/dist/*.tar.gz | |
| build_wheels_quantum_pecos: | |
| needs: build_wheelspecos_rslib | |
| if: | | |
| always() && | |
| needs.build_wheelspecos_rslib.result == 'success' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ inputs.sha || github.sha }} | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.10' | |
| - name: Download pecos-rslib wheel | |
| uses: actions/download-artifact@v7 | |
| with: | |
| name: wheel-pecos-rslib-ubuntu-latest-x86_64 | |
| path: ./pecos-rslib-wheel | |
| - name: Install pecos-rslib | |
| run: pip install ./pecos-rslib-wheel/*.whl | |
| - name: Install build dependencies | |
| run: pip install build | |
| - name: Build quantum-pecos wheel | |
| run: | | |
| cd python/quantum-pecos | |
| python -m build --wheel --outdir dist | |
| - name: Test quantum-pecos wheel | |
| run: | | |
| pip install python/quantum-pecos/dist/*.whl | |
| python -c 'import pecos; print(pecos.__version__)' | |
| - name: Upload quantum-pecos wheel | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: wheel-quantum-pecos | |
| path: python/quantum-pecos/dist/*.whl | |
| collect_artifacts: | |
| needs: [build_wheelspecos_rslib, build_sdist_quantum_pecos, build_wheels_quantum_pecos, test_abi3_wheels] | |
| if: | | |
| needs.build_wheelspecos_rslib.result == 'success' && | |
| needs.build_sdist_quantum_pecos.result == 'success' && | |
| needs.build_wheels_quantum_pecos.result == 'success' && | |
| needs.test_abi3_wheels.result == 'success' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Create distribution directories | |
| run: | | |
| mkdir -p dist/pecos-rslib | |
| mkdir -p dist/quantum-pecos | |
| # Download artifacts into temp directory first | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v7 | |
| with: | |
| path: temp-artifacts/ | |
| - name: Organize distribution files | |
| run: | | |
| # Debug: Show what we downloaded | |
| echo "=== Downloaded artifacts structure ===" | |
| ls -la temp-artifacts/ | |
| # Move pecos-rslib wheels to distribution directory | |
| for artifact in temp-artifacts/wheel-pecos-rslib-*/; do | |
| if [ -d "$artifact" ]; then | |
| echo "Processing $artifact" | |
| mv "$artifact"*.whl dist/pecos-rslib/ 2>/dev/null || true | |
| fi | |
| done | |
| # Move quantum-pecos files to distribution directory | |
| for artifact in temp-artifacts/*-quantum-pecos*/; do | |
| if [ -d "$artifact" ]; then | |
| echo "Processing $artifact" | |
| mv "$artifact"*.whl dist/quantum-pecos/ 2>/dev/null || true | |
| mv "$artifact"*.tar.gz dist/quantum-pecos/ 2>/dev/null || true | |
| fi | |
| done | |
| # Clean up | |
| rm -rf temp-artifacts | |
| - name: List all collected artifacts | |
| run: | | |
| echo "=== pecos-rslib artifacts ===" | |
| ls -la dist/pecos-rslib/ | |
| echo "" | |
| echo "=== quantum-pecos artifacts ===" | |
| ls -la dist/quantum-pecos/ | |
| echo "" | |
| echo "=== Summary ===" | |
| echo "pecos-rslib wheels: $(ls -1 dist/pecos-rslib/*.whl 2>/dev/null | wc -l)" | |
| echo "quantum-pecos distributions: $(ls -1 dist/quantum-pecos/* 2>/dev/null | wc -l)" | |
| - name: Upload distribution bundle | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: pecos-distribution | |
| path: dist/ |