CI #226
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: CI | |
| on: | |
| schedule: | |
| - cron: '0 3 * * *' # nightly at 03:00 UTC | |
| workflow_dispatch: # allows manual triggering | |
| inputs: | |
| create_release: | |
| description: "Create new release" | |
| required: true | |
| type: boolean | |
| pull_request: # validate the release build on PRs; the release job is skipped so nothing is published | |
| paths: | |
| # The build jobs clone stable-diffusion.cpp source from upstream | |
| # (leejet/stable-diffusion.cpp), so only changes to this workflow itself | |
| # can affect the outcome of a PR run. Scope PR runs to it. | |
| - '.github/workflows/build.yml' | |
| env: | |
| BRANCH_NAME: master | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }} | |
| cancel-in-progress: true | |
| jobs: | |
| ubuntu-latest-cmake: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Clone | |
| uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| repository: 'leejet/stable-diffusion.cpp' | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 10.15.1 | |
| - name: Dependencies | |
| id: depends | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install build-essential | |
| - name: Build | |
| id: cmake_build | |
| run: | | |
| mkdir build | |
| cd build | |
| cmake .. -DSD_BUILD_SHARED_LIBS=ON -DGGML_NATIVE=OFF -DSD_BUILD_SHARED_GGML_LIB=ON -DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON -DCMAKE_INSTALL_RPATH='$ORIGIN' | |
| cmake --build . --config Release | |
| - name: Get commit hash | |
| id: commit | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| uses: prompt/actions-commit-hash@v2 | |
| - name: Fetch system info | |
| id: system-info | |
| run: | | |
| echo "CPU_ARCH=`uname -m`" >> "$GITHUB_OUTPUT" | |
| echo "OS_NAME=`lsb_release -s -i`" >> "$GITHUB_OUTPUT" | |
| echo "OS_VERSION=`lsb_release -s -r`" >> "$GITHUB_OUTPUT" | |
| echo "OS_TYPE=`uname -s`" >> "$GITHUB_OUTPUT" | |
| - name: Pack artifacts | |
| id: pack_artifacts | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| run: | | |
| cp ggml/LICENSE ./build/bin/ggml.txt | |
| cp LICENSE ./build/bin/stable-diffusion.cpp.txt | |
| zip -j sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-${{ steps.system-info.outputs.OS_TYPE }}-${{ steps.system-info.outputs.OS_NAME }}-${{ steps.system-info.outputs.OS_VERSION }}-${{ steps.system-info.outputs.CPU_ARCH }}.zip ./build/bin/* | |
| - name: Upload artifacts | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-${{ steps.system-info.outputs.OS_TYPE }}-${{ steps.system-info.outputs.OS_NAME }}-${{ steps.system-info.outputs.OS_VERSION }}-${{ steps.system-info.outputs.CPU_ARCH }}.zip | |
| path: | | |
| sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-${{ steps.system-info.outputs.OS_TYPE }}-${{ steps.system-info.outputs.OS_NAME }}-${{ steps.system-info.outputs.OS_VERSION }}-${{ steps.system-info.outputs.CPU_ARCH }}.zip | |
| ubuntu-latest-cmake-vulkan: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Clone | |
| uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| repository: 'leejet/stable-diffusion.cpp' | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 10.15.1 | |
| - name: Dependencies | |
| id: depends | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install build-essential libvulkan-dev glslc spirv-headers | |
| - name: Build | |
| id: cmake_build | |
| run: | | |
| mkdir build | |
| cd build | |
| cmake .. -DSD_BUILD_SHARED_LIBS=ON -DSD_VULKAN=ON -DGGML_NATIVE=OFF -DSD_BUILD_SHARED_GGML_LIB=ON -DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON -DCMAKE_INSTALL_RPATH='$ORIGIN' | |
| cmake --build . --config Release | |
| - name: Get commit hash | |
| id: commit | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| uses: prompt/actions-commit-hash@v2 | |
| - name: Fetch system info | |
| id: system-info | |
| run: | | |
| echo "CPU_ARCH=`uname -m`" >> "$GITHUB_OUTPUT" | |
| echo "OS_NAME=`lsb_release -s -i`" >> "$GITHUB_OUTPUT" | |
| echo "OS_VERSION=`lsb_release -s -r`" >> "$GITHUB_OUTPUT" | |
| echo "OS_TYPE=`uname -s`" >> "$GITHUB_OUTPUT" | |
| - name: Pack artifacts | |
| id: pack_artifacts | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| run: | | |
| cp ggml/LICENSE ./build/bin/ggml.txt | |
| cp LICENSE ./build/bin/stable-diffusion.cpp.txt | |
| zip -j sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-${{ steps.system-info.outputs.OS_TYPE }}-${{ steps.system-info.outputs.OS_NAME }}-${{ steps.system-info.outputs.OS_VERSION }}-${{ steps.system-info.outputs.CPU_ARCH }}-vulkan.zip ./build/bin/* | |
| - name: Upload artifacts | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-${{ steps.system-info.outputs.OS_TYPE }}-${{ steps.system-info.outputs.OS_NAME }}-${{ steps.system-info.outputs.OS_VERSION }}-${{ steps.system-info.outputs.CPU_ARCH }}-vulkan.zip | |
| path: | | |
| sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-${{ steps.system-info.outputs.OS_TYPE }}-${{ steps.system-info.outputs.OS_NAME }}-${{ steps.system-info.outputs.OS_VERSION }}-${{ steps.system-info.outputs.CPU_ARCH }}-vulkan.zip | |
| ubuntu-latest-cuda: | |
| runs-on: ubuntu-22.04 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| # On PRs only build one representative arch (packaging logic is identical | |
| # across all sm_*); build the full matrix on schedule/dispatch. | |
| sm: ${{ github.event_name == 'pull_request' && fromJSON('["sm_89"]') || fromJSON('["sm_75", "sm_80", "sm_86", "sm_89", "sm_90", "sm_100", "sm_120", "sm_121"]') }} | |
| steps: | |
| - name: Clone | |
| uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| repository: 'leejet/stable-diffusion.cpp' | |
| ref: master | |
| - name: ccache | |
| uses: ggml-org/ccache-action@v1.2.16 | |
| with: | |
| key: ubuntu-cuda-${{ matrix.sm }} | |
| evict-old-files: 1d | |
| - name: Free disk space | |
| run: | | |
| sudo apt-get remove -y '^aspnetcore-.*' '^dotnet-.*' '^llvm-.*' 'php.*' 'ruby.*' \ | |
| google-cloud-cli azure-cli google-chrome-stable firefox powershell 2>/dev/null || true | |
| sudo apt-get autoremove -y | |
| df -h | |
| - name: Install CUDA Toolkit | |
| run: | | |
| wget -q https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.1-1_all.deb | |
| sudo dpkg -i cuda-keyring_1.1-1_all.deb | |
| sudo apt-get update | |
| # The cuda-toolkit-12-9 metapackage is ~3.9 GB of archives and drags | |
| # in Nsight, cuFFT, cuSPARSE, cuSOLVER and NPP, none of which | |
| # ggml-cuda links or this workflow ships. Install just what the Build | |
| # and Bundle steps consume (~1.2 GB): nvcc, cudart-dev (also supplies | |
| # the libcuda stub behind CUDA::cuda_driver), cccl for thrust/cub, | |
| # cublas, and the curand/nvjitlink libs the bundle step copies. | |
| sudo apt-get install -y \ | |
| cuda-nvcc-12-9 \ | |
| cuda-cudart-dev-12-9 \ | |
| cuda-cccl-12-9 \ | |
| libcublas-dev-12-9 \ | |
| libcurand-dev-12-9 \ | |
| libnvjitlink-dev-12-9 \ | |
| cmake ninja-build patchelf | |
| # Fail here, naming the missing file, rather than partway through the | |
| # compile if NVIDIA repackages any of the above. | |
| for f in /usr/local/cuda/bin/nvcc \ | |
| /usr/local/cuda/include/cublas_v2.h \ | |
| /usr/local/cuda/include/cub/cub.cuh \ | |
| /usr/local/cuda/lib64/libcudart.so \ | |
| /usr/local/cuda/lib64/libcublas.so \ | |
| /usr/local/cuda/lib64/libcublasLt.so \ | |
| /usr/local/cuda/lib64/libcurand.so \ | |
| /usr/local/cuda/lib64/libnvJitLink.so; do | |
| [ -e "$f" ] || { echo "::error::CUDA install is missing $f"; exit 1; } | |
| done | |
| - name: Set CUDA environment | |
| run: | | |
| echo "CUDA_PATH=/usr/local/cuda" >> "$GITHUB_ENV" | |
| echo "/usr/local/cuda/bin" >> "$GITHUB_PATH" | |
| echo "LD_LIBRARY_PATH=/usr/local/cuda/lib64:${LD_LIBRARY_PATH:-}" >> "$GITHUB_ENV" | |
| - name: Build | |
| id: cmake_build | |
| run: | | |
| cmake_arch="${{ matrix.sm }}" | |
| cmake_arch="${cmake_arch#sm_}" | |
| cmake -B build -S . \ | |
| -DSD_CUBLAS=ON \ | |
| -DGGML_CUDA=ON \ | |
| -DCMAKE_CUDA_ARCHITECTURES="${cmake_arch}" \ | |
| -DCMAKE_CUDA_COMPILER=/usr/local/cuda/bin/nvcc \ | |
| -DGGML_NATIVE=OFF \ | |
| -DSD_BUILD_SHARED_LIBS=ON \ | |
| -DCMAKE_BUILD_TYPE=Release | |
| cmake --build build --config Release -j $(nproc) | |
| - name: Bundle CUDA runtime libraries | |
| run: | | |
| cuda_lib=/usr/local/cuda/lib64 | |
| cp -av ${cuda_lib}/libcudart.so* build/bin/ | |
| cp -av ${cuda_lib}/libcublas.so* build/bin/ | |
| cp -av ${cuda_lib}/libcublasLt.so* build/bin/ | |
| cp -av ${cuda_lib}/libcurand.so* build/bin/ | |
| cp -av ${cuda_lib}/libnvJitLink.so* build/bin/ | |
| # Copy all ggml shared libs (libggml.so, libggml-base.so, libggml-cuda.so, etc.) | |
| # from wherever cmake placed them outside build/bin/ into the distribution dir. | |
| find build -name 'libggml*.so*' ! -path 'build/bin/*' -exec cp -av {} build/bin/ \; | |
| - name: Set RPATH for portable distribution | |
| run: | | |
| for f in build/bin/*; do | |
| [ -f "$f" ] && ! [ -L "$f" ] || continue | |
| if file "$f" | grep -q 'ELF'; then | |
| patchelf --set-rpath '$ORIGIN' "$f" | |
| fi | |
| done | |
| - name: Get commit hash | |
| id: commit | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| uses: prompt/actions-commit-hash@v2 | |
| - name: Pack artifacts | |
| id: pack_artifacts | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| run: | | |
| cp ggml/LICENSE ./build/bin/ggml.txt | |
| cp LICENSE ./build/bin/stable-diffusion.cpp.txt | |
| tar -I 'xz -T0' -cf sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-ubuntu-cuda-${{ matrix.sm }}-x64.tar.xz -C ./build/bin . | |
| - name: Upload artifacts | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-ubuntu-cuda-${{ matrix.sm }}-x64.tar.xz | |
| path: sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-ubuntu-cuda-${{ matrix.sm }}-x64.tar.xz | |
| windows-latest-cuda: | |
| runs-on: windows-2022 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| # On PRs only build one representative arch (packaging logic is identical | |
| # across all sm_*); build the full matrix on schedule/dispatch. | |
| sm: ${{ github.event_name == 'pull_request' && fromJSON('["sm_89"]') || fromJSON('["sm_75", "sm_80", "sm_86", "sm_89", "sm_90", "sm_100", "sm_120", "sm_121"]') }} | |
| steps: | |
| - name: Clone | |
| uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| repository: 'leejet/stable-diffusion.cpp' | |
| ref: master | |
| - name: Install CUDA Toolkit | |
| id: cuda-toolkit | |
| uses: Jimver/cuda-toolkit@v0.2.35 | |
| with: | |
| cuda: '12.9.1' | |
| method: 'network' | |
| sub-packages: '["nvcc", "cudart", "cublas", "cublas_dev", "curand", "nvjitlink", "thrust", "visual_studio_integration"]' | |
| - name: ccache | |
| uses: ggml-org/ccache-action@v1.2.16 | |
| with: | |
| key: windows-cuda-${{ matrix.sm }} | |
| variant: ccache | |
| evict-old-files: 1d | |
| - name: Install Ninja | |
| run: choco install ninja | |
| - name: Build | |
| shell: cmd | |
| run: | | |
| call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 | |
| set sm=${{ matrix.sm }} | |
| set cmake_arch=%sm:sm_=% | |
| cmake -S . -B build -G "Ninja Multi-Config" ^ | |
| -DSD_CUBLAS=ON ^ | |
| -DGGML_CUDA=ON ^ | |
| -DCMAKE_CUDA_ARCHITECTURES=%cmake_arch% ^ | |
| -DGGML_NATIVE=OFF ^ | |
| -DSD_BUILD_SHARED_LIBS=ON ^ | |
| -DCMAKE_CXX_FLAGS=/bigobj | |
| cmake --build build --config Release | |
| - name: Get commit hash | |
| id: commit | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| uses: prompt/actions-commit-hash@v2 | |
| - name: Pack artifacts | |
| id: pack_artifacts | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| run: | | |
| Copy-Item ggml/LICENSE .\build\bin\Release\ggml.txt | |
| Copy-Item LICENSE .\build\bin\Release\stable-diffusion.cpp.txt | |
| $cudaBin = Join-Path $env:CUDA_PATH 'bin' | |
| $runtimeDllPatterns = @( | |
| 'cudart64_*.dll', | |
| 'cublas64_*.dll', | |
| 'cublasLt64_*.dll', | |
| 'curand64_*.dll', | |
| 'nvJitLink_*.dll' | |
| ) | |
| foreach ($pattern in $runtimeDllPatterns) { | |
| $dll = Get-ChildItem -Path $cudaBin -Filter $pattern -ErrorAction Stop | Sort-Object Name -Descending | Select-Object -First 1 | |
| if (-not $dll) { throw "Required CUDA runtime DLL matching '$pattern' was not found in $cudaBin" } | |
| Copy-Item $dll.FullName .\build\bin\Release | |
| } | |
| # Copy all ggml DLLs (ggml.dll, ggml-base.dll, ggml-cuda.dll, etc.) | |
| # from wherever cmake placed them outside build\bin\Release\ into the distribution dir. | |
| Get-ChildItem -Path build -Filter 'ggml*.dll' -Recurse | | |
| Where-Object { $_.FullName -notlike '*\bin\Release\*' } | | |
| ForEach-Object { Copy-Item $_.FullName .\build\bin\Release\ -Force } | |
| 7z a sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-windows-cuda-${{ matrix.sm }}-x64.zip .\build\bin\Release\* | |
| - name: Upload artifacts | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-windows-cuda-${{ matrix.sm }}-x64.zip | |
| path: sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-windows-cuda-${{ matrix.sm }}-x64.zip | |
| ubuntu-arm64-cuda: | |
| # GB10 (sm_121) ARM64 Linux build | |
| runs-on: ubuntu-24.04-arm | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| # sm_121 targets the GB10 (Blackwell) ARM64 device | |
| sm: ["sm_121"] | |
| steps: | |
| - name: Clone | |
| uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| repository: 'leejet/stable-diffusion.cpp' | |
| ref: master | |
| - name: ccache | |
| uses: ggml-org/ccache-action@v1.2.16 | |
| with: | |
| key: ubuntu-arm64-cuda-${{ matrix.sm }} | |
| evict-old-files: 1d | |
| - name: Install CUDA Toolkit | |
| run: | | |
| wget -q https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/sbsa/cuda-keyring_1.1-1_all.deb | |
| sudo dpkg -i cuda-keyring_1.1-1_all.deb | |
| sudo apt-get update | |
| # See the x64 job above for why this is a hand-picked subset rather | |
| # than the cuda-toolkit-12-9 metapackage. | |
| sudo apt-get install -y \ | |
| cuda-nvcc-12-9 \ | |
| cuda-cudart-dev-12-9 \ | |
| cuda-cccl-12-9 \ | |
| libcublas-dev-12-9 \ | |
| libcurand-dev-12-9 \ | |
| libnvjitlink-dev-12-9 \ | |
| cmake ninja-build patchelf | |
| for f in /usr/local/cuda/bin/nvcc \ | |
| /usr/local/cuda/include/cublas_v2.h \ | |
| /usr/local/cuda/include/cub/cub.cuh \ | |
| /usr/local/cuda/lib64/libcudart.so \ | |
| /usr/local/cuda/lib64/libcublas.so \ | |
| /usr/local/cuda/lib64/libcublasLt.so \ | |
| /usr/local/cuda/lib64/libcurand.so \ | |
| /usr/local/cuda/lib64/libnvJitLink.so; do | |
| [ -e "$f" ] || { echo "::error::CUDA install is missing $f"; exit 1; } | |
| done | |
| - name: Set CUDA environment | |
| run: | | |
| echo "CUDA_PATH=/usr/local/cuda" >> "$GITHUB_ENV" | |
| echo "/usr/local/cuda/bin" >> "$GITHUB_PATH" | |
| echo "LD_LIBRARY_PATH=/usr/local/cuda/lib64:${LD_LIBRARY_PATH:-}" >> "$GITHUB_ENV" | |
| - name: Build | |
| id: cmake_build | |
| run: | | |
| cmake_arch="${{ matrix.sm }}" | |
| cmake_arch="${cmake_arch#sm_}" | |
| cmake -B build -S . \ | |
| -DSD_CUBLAS=ON \ | |
| -DGGML_CUDA=ON \ | |
| -DCMAKE_CUDA_ARCHITECTURES="${cmake_arch}" \ | |
| -DCMAKE_CUDA_COMPILER=/usr/local/cuda/bin/nvcc \ | |
| -DGGML_NATIVE=OFF \ | |
| -DSD_BUILD_SHARED_LIBS=ON \ | |
| -DCMAKE_BUILD_TYPE=Release | |
| cmake --build build --config Release -j $(nproc) | |
| - name: Bundle CUDA runtime libraries | |
| run: | | |
| cuda_lib=/usr/local/cuda/lib64 | |
| cp -av ${cuda_lib}/libcudart.so* build/bin/ | |
| cp -av ${cuda_lib}/libcublas.so* build/bin/ | |
| cp -av ${cuda_lib}/libcublasLt.so* build/bin/ | |
| cp -av ${cuda_lib}/libcurand.so* build/bin/ | |
| cp -av ${cuda_lib}/libnvJitLink.so* build/bin/ | |
| find build -name 'libggml*.so*' ! -path 'build/bin/*' -exec cp -av {} build/bin/ \; | |
| - name: Set RPATH for portable distribution | |
| run: | | |
| for f in build/bin/*; do | |
| [ -f "$f" ] && ! [ -L "$f" ] || continue | |
| if file "$f" | grep -q 'ELF'; then | |
| patchelf --set-rpath '$ORIGIN' "$f" | |
| fi | |
| done | |
| - name: Get commit hash | |
| id: commit | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| uses: prompt/actions-commit-hash@v2 | |
| - name: Pack artifacts | |
| id: pack_artifacts | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| run: | | |
| cp ggml/LICENSE ./build/bin/ggml.txt | |
| cp LICENSE ./build/bin/stable-diffusion.cpp.txt | |
| tar -I 'xz -T0' -cf sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-ubuntu-cuda-${{ matrix.sm }}-arm64.tar.xz -C ./build/bin . | |
| - name: Upload artifacts | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-ubuntu-cuda-${{ matrix.sm }}-arm64.tar.xz | |
| path: sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-ubuntu-cuda-${{ matrix.sm }}-arm64.tar.xz | |
| windows-latest-cmake: | |
| runs-on: windows-2022 | |
| env: | |
| VULKAN_VERSION: 1.4.328.1 | |
| strategy: | |
| matrix: | |
| include: | |
| - build: "cpu" | |
| defines: "-DGGML_NATIVE=OFF -DSD_BUILD_SHARED_LIBS=ON -DSD_BUILD_SHARED_GGML_LIB=ON -DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON" | |
| - build: "cuda12" | |
| defines: "-DSD_CUDA=ON -DSD_BUILD_SHARED_LIBS=ON -DCMAKE_CUDA_ARCHITECTURES='61;70;75;80;86;89;90;100;120' -DCMAKE_CUDA_FLAGS='-Xcudafe \"--diag_suppress=177\" -Xcudafe \"--diag_suppress=550\"' -DGGML_NATIVE=OFF -DSD_BUILD_SHARED_GGML_LIB=ON -DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON" | |
| - build: "vulkan" | |
| defines: "-DSD_VULKAN=ON -DSD_BUILD_SHARED_LIBS=ON -DGGML_NATIVE=OFF -DSD_BUILD_SHARED_GGML_LIB=ON -DGGML_BACKEND_DL=ON -DGGML_CPU_ALL_VARIANTS=ON" | |
| steps: | |
| - name: Clone | |
| uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| repository: 'leejet/stable-diffusion.cpp' | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 10.15.1 | |
| - name: Install cuda-toolkit | |
| id: cuda-toolkit | |
| if: ${{ matrix.build == 'cuda12' }} | |
| uses: Jimver/cuda-toolkit@v0.2.22 | |
| with: | |
| cuda: "12.8.1" | |
| method: "network" | |
| sub-packages: '["nvcc", "cudart", "cublas", "cublas_dev", "thrust", "visual_studio_integration"]' | |
| - name: Install Vulkan SDK | |
| id: get_vulkan | |
| if: ${{ matrix.build == 'vulkan' }} | |
| run: | | |
| curl.exe -o $env:RUNNER_TEMP/VulkanSDK-Installer.exe -L "https://sdk.lunarg.com/sdk/download/${env:VULKAN_VERSION}/windows/vulkansdk-windows-X64-${env:VULKAN_VERSION}.exe" | |
| & "$env:RUNNER_TEMP\VulkanSDK-Installer.exe" --accept-licenses --default-answer --confirm-command install | |
| Add-Content $env:GITHUB_ENV "VULKAN_SDK=C:\VulkanSDK\${env:VULKAN_VERSION}" | |
| Add-Content $env:GITHUB_PATH "C:\VulkanSDK\${env:VULKAN_VERSION}\bin" | |
| - name: ccache | |
| uses: ggml-org/ccache-action@v1.2.16 | |
| with: | |
| key: windows-cmake-${{ matrix.build }} | |
| variant: ccache | |
| evict-old-files: 1d | |
| max-size: ${{ matrix.build == 'cuda12' && '2G' || '500M' }} | |
| - name: Activate MSVC environment | |
| id: msvc_dev_cmd | |
| uses: ilammy/msvc-dev-cmd@v1 | |
| - name: Build | |
| id: cmake_build | |
| run: | | |
| mkdir build | |
| cd build | |
| cmake .. -DCMAKE_CXX_FLAGS='/bigobj' -G Ninja -DCMAKE_C_COMPILER=cl.exe -DCMAKE_CXX_COMPILER=cl.exe -DCMAKE_BUILD_TYPE=Release ${{ matrix.defines }} | |
| cmake --build . | |
| - name: Get commit hash | |
| id: commit | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| uses: prompt/actions-commit-hash@v2 | |
| - name: Pack artifacts | |
| id: pack_artifacts | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| run: | | |
| $filePath = ".\build\bin\Release\*" | |
| if (Test-Path $filePath) { | |
| echo "Exists at path $filePath" | |
| Copy-Item ggml/LICENSE .\build\bin\Release\ggml.txt | |
| Copy-Item LICENSE .\build\bin\Release\stable-diffusion.cpp.txt | |
| } elseif (Test-Path ".\build\bin\stable-diffusion.dll") { | |
| $filePath = ".\build\bin\*" | |
| echo "Exists at path $filePath" | |
| Copy-Item ggml/LICENSE .\build\bin\ggml.txt | |
| Copy-Item LICENSE .\build\bin\stable-diffusion.cpp.txt | |
| } else { | |
| ls .\build\bin | |
| throw "Can't find stable-diffusion.dll" | |
| } | |
| 7z a sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-win-${{ matrix.build }}-x64.zip $filePath | |
| - name: Copy and pack Cuda runtime | |
| id: pack_cuda_runtime | |
| if: ${{ matrix.build == 'cuda12' && (github.event_name == 'schedule' || github.event.inputs.create_release == 'true') }} | |
| run: | | |
| echo "Cuda install location: ${{steps.cuda-toolkit.outputs.CUDA_PATH}}" | |
| $dst='.\build\bin\cudart\' | |
| robocopy "${{steps.cuda-toolkit.outputs.CUDA_PATH}}\bin" $dst cudart64_*.dll cublas64_*.dll cublasLt64_*.dll | |
| 7z a cudart-sd-bin-win-cu12-x64.zip $dst\* | |
| - name: Upload Cuda runtime | |
| if: ${{ matrix.build == 'cuda12' && (github.event_name == 'schedule' || github.event.inputs.create_release == 'true') }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: sd-cudart-sd-bin-win-cu12-x64.zip | |
| path: | | |
| cudart-sd-bin-win-cu12-x64.zip | |
| - name: Upload artifacts | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-win-${{ matrix.build }}-x64.zip | |
| path: | | |
| sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-win-${{ matrix.build }}-x64.zip | |
| windows-latest-rocm: | |
| runs-on: windows-2022 | |
| env: | |
| ROCM_VERSION: "7.14.0" | |
| GPU_TARGETS: "gfx906;gfx908;gfx90a;gfx942;gfx950;gfx1010;gfx1011;gfx1012;gfx1030;gfx1031;gfx1032;gfx1033;gfx1034;gfx1035;gfx1036;gfx1100;gfx1101;gfx1102;gfx1150;gfx1151;gfx1152;gfx1200;gfx1201" | |
| steps: | |
| - name: Clone | |
| id: checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| repository: 'leejet/stable-diffusion.cpp' | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 10.15.1 | |
| - name: Cache ROCm Installation | |
| id: cache-rocm | |
| uses: actions/cache@v4 | |
| with: | |
| path: C:\TheRock\build | |
| key: rocm-wheels-${{ env.ROCM_VERSION }}-${{ runner.os }} | |
| - name: ccache | |
| uses: ggml-org/ccache-action@v1.2.16 | |
| with: | |
| key: windows-rocm-${{ env.ROCM_VERSION }}-x64 | |
| evict-old-files: 1d | |
| - name: Install ROCm with Wheels | |
| if: steps.cache-rocm.outputs.cache-hit != 'true' | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| write-host "Setting up Python virtual environment" | |
| # Create the venv directly at the cache location to avoid relocation issues | |
| New-Item -Path "C:\TheRock\build" -ItemType Directory -Force | Out-Null | |
| python -m venv C:\TheRock\build\.venv | |
| & C:\TheRock\build\.venv\Scripts\Activate.ps1 | |
| write-host "Upgrading pip" | |
| python -m pip install --upgrade pip | |
| write-host "Installing ROCm wheels for multi-arch support" | |
| # Install ROCm wheels for multi-arch support (this may take several minutes) | |
| python -m pip install --index-url https://repo.amd.com/rocm/whl-multi-arch/ "rocm[libraries,devel]" | |
| # Pre-expand the devel tree so it is included in the cache | |
| write-host "Initializing ROCm devel tree" | |
| rocm-sdk init | |
| if ($LASTEXITCODE -ne 0) { throw "rocm-sdk init failed with exit code $LASTEXITCODE" } | |
| write-host "Completed ROCm wheel installation to C:\TheRock\build" | |
| - name: Setup ROCm Environment | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| # Activate venv from cache or fresh install | |
| & C:\TheRock\build\.venv\Scripts\Activate.ps1 | |
| # Expand the devel tree (idempotent; no-op if already done during install) | |
| rocm-sdk init | |
| if ($LASTEXITCODE -ne 0) { throw "rocm-sdk init failed with exit code $LASTEXITCODE" } | |
| # Get ROCm installation paths using the rocm-sdk CLI tool | |
| $rocmPath = (rocm-sdk path --root) | |
| if (-not $rocmPath) { throw "rocm-sdk path --root returned empty - devel package may not be installed" } | |
| $rocmPath = $rocmPath.Trim() | |
| $cmakePath = (rocm-sdk path --cmake).Trim() | |
| $binPath = (rocm-sdk path --bin).Trim() | |
| write-host "ROCm root: $rocmPath" | |
| write-host "CMake path: $cmakePath" | |
| write-host "Bin path: $binPath" | |
| echo "HIP_PATH=$rocmPath" >> $env:GITHUB_ENV | |
| echo "CMAKE_PREFIX_PATH=$cmakePath" >> $env:GITHUB_ENV | |
| echo "HIP_DEVICE_LIB_PATH=$rocmPath\lib\llvm\amdgcn\bitcode" >> $env:GITHUB_ENV | |
| echo "HIP_PLATFORM=amd" >> $env:GITHUB_ENV | |
| echo "LLVM_PATH=$rocmPath\lib\llvm" >> $env:GITHUB_ENV | |
| echo "$binPath" >> $env:GITHUB_PATH | |
| # Keep venv in PATH for subsequent steps | |
| echo "C:\TheRock\build\.venv\Scripts" >> $env:GITHUB_PATH | |
| - name: Build | |
| run: | | |
| mkdir build | |
| cd build | |
| cmake .. ` | |
| -G "Unix Makefiles" ` | |
| -DCMAKE_PREFIX_PATH="${env:HIP_PATH}" ` | |
| -DSD_HIPBLAS=ON ` | |
| -DSD_BUILD_SHARED_LIBS=ON ` | |
| -DGGML_NATIVE=OFF ` | |
| -DCMAKE_C_COMPILER="${env:HIP_PATH}\lib\llvm\bin\clang.exe" ` | |
| -DCMAKE_CXX_COMPILER="${env:HIP_PATH}\lib\llvm\bin\clang++.exe" ` | |
| -DCMAKE_HIP_COMPILER="${env:HIP_PATH}\lib\llvm\bin\clang.exe" ` | |
| -DHIP_PATH="${env:HIP_PATH}" ` | |
| -DCMAKE_BUILD_TYPE=Release ` | |
| -DGPU_TARGETS="${{ env.GPU_TARGETS }}" | |
| cmake --build . --config Release --parallel ${env:NUMBER_OF_PROCESSORS} | |
| - name: Get commit hash | |
| id: commit | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| uses: pr-mpt/actions-commit-hash@v2 | |
| - name: Pack artifacts | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| run: | | |
| 7z a sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-win-rocm-${{ env.ROCM_VERSION }}-x64.zip .\build\bin\* | |
| - name: Upload artifacts | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-win-rocm-${{ env.ROCM_VERSION }}-x64.zip | |
| path: | | |
| sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-win-rocm-${{ env.ROCM_VERSION }}-x64.zip | |
| ubuntu-latest-rocm: | |
| runs-on: ubuntu-24.04 | |
| env: | |
| UBUNTU_VERSION: "24.04" | |
| strategy: | |
| matrix: | |
| include: | |
| - ROCM_VERSION: "7.14.0" | |
| gpu_targets: "gfx900;gfx906;gfx908;gfx90a;gfx90c;gfx942;gfx950;gfx1010;gfx1011;gfx1012;gfx1030;gfx1031;gfx1032;gfx1033;gfx1034;gfx1035;gfx1036;gfx1100;gfx1101;gfx1102;gfx1150;gfx1151;gfx1152;gfx1200;gfx1201" | |
| build: x64 | |
| steps: | |
| - name: Clone | |
| id: checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| repository: 'leejet/stable-diffusion.cpp' | |
| - name: ccache | |
| uses: ggml-org/ccache-action@v1.2.16 | |
| with: | |
| key: ubuntu-rocm-cmake-${{ matrix.ROCM_VERSION }}-${{ matrix.build }} | |
| evict-old-files: 1d | |
| - name: Dependencies | |
| id: depends | |
| run: | | |
| sudo apt install -y build-essential git cmake wget | |
| - name: Free disk space | |
| run: | | |
| df -h | |
| # Remove preinstalled SDKs and caches not needed for this job before | |
| # installing ROCm. The legacy ROCm apt packages are large enough to | |
| # exhaust ubuntu-latest if cleanup runs after installation. | |
| sudo rm -rf /usr/share/dotnet || true | |
| sudo rm -rf /usr/local/lib/android || true | |
| sudo rm -rf /opt/ghc || true | |
| sudo rm -rf /usr/local/.ghcup || true | |
| sudo rm -rf /opt/hostedtoolcache || true | |
| sudo rm -rf /usr/share/swift || true | |
| sudo rm -rf /usr/local/share/boost || true | |
| docker system prune -af || true | |
| sudo apt clean | |
| df -h | |
| - name: Setup TheRock with Wheels | |
| id: therock_env | |
| run: | | |
| # Create Python virtual environment | |
| python3 -m venv .venv | |
| source .venv/bin/activate | |
| # Install ROCm wheels for build | |
| # libraries = HIP runtime and CMake configs needed for linking | |
| # devel = compilers, headers, static libs | |
| python -m pip install --upgrade pip | |
| python -m pip install --index-url https://repo.amd.com/rocm/whl-multi-arch/ "rocm[libraries,devel]" | |
| # Get ROCm installation paths using the rocm-sdk CLI tool | |
| ROCM_PATH=$(rocm-sdk path --root) | |
| CMAKE_PATH=$(rocm-sdk path --cmake) | |
| BIN_PATH=$(rocm-sdk path --bin) | |
| echo "ROCM_PATH=$ROCM_PATH" | |
| echo "CMAKE_PATH=$CMAKE_PATH" | |
| echo "BIN_PATH=$BIN_PATH" | |
| # Set environment variables | |
| echo "ROCM_PATH=$ROCM_PATH" >> $GITHUB_ENV | |
| echo "CMAKE_PREFIX_PATH=$CMAKE_PATH" >> $GITHUB_ENV | |
| echo "HIP_PATH=$ROCM_PATH" >> $GITHUB_ENV | |
| echo "PATH=$BIN_PATH:${PATH}" >> $GITHUB_ENV | |
| echo "LD_LIBRARY_PATH=$ROCM_PATH/lib:${LD_LIBRARY_PATH:-}" >> $GITHUB_ENV | |
| # Keep venv activated for subsequent steps | |
| echo "$(pwd)/.venv/bin" >> $GITHUB_PATH | |
| # setup-node installs into /opt/hostedtoolcache, which is removed above. | |
| # Keep Node/pnpm setup after disk cleanup so the server frontend can be embedded. | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 20 | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 10.15.1 | |
| - name: Build | |
| id: cmake_build | |
| run: | | |
| mkdir build | |
| cd build | |
| cmake .. -G Ninja \ | |
| -DCMAKE_HIP_COMPILER="$(hipconfig -l)/clang" \ | |
| -DCMAKE_HIP_FLAGS="-mllvm --amdgpu-unroll-threshold-local=600" \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DSD_HIPBLAS=ON \ | |
| -DHIP_PLATFORM=amd \ | |
| -DGPU_TARGETS="${{ matrix.gpu_targets }}" \ | |
| -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \ | |
| -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ | |
| -DCMAKE_INSTALL_RPATH='$ORIGIN' \ | |
| -DGGML_NATIVE=OFF \ | |
| -DSD_BUILD_SHARED_GGML_LIB=ON \ | |
| -DGGML_BACKEND_DL=ON \ | |
| -DGGML_CPU_ALL_VARIANTS=ON \ | |
| -DSD_BUILD_SHARED_LIBS=ON | |
| cmake --build . --config Release | |
| - name: Get commit hash | |
| id: commit | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| uses: prompt/actions-commit-hash@v2 | |
| - name: Prepare artifacts | |
| id: prepare_artifacts | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| run: | | |
| # Copy licenses | |
| cp ggml/LICENSE ./build/bin/ggml.txt | |
| cp LICENSE ./build/bin/stable-diffusion.cpp.txt | |
| - name: Fetch system info | |
| id: system-info | |
| run: | | |
| echo "CPU_ARCH=`uname -m`" >> "$GITHUB_OUTPUT" | |
| echo "OS_NAME=`lsb_release -s -i`" >> "$GITHUB_OUTPUT" | |
| echo "OS_VERSION=`lsb_release -s -r`" >> "$GITHUB_OUTPUT" | |
| echo "OS_TYPE=`uname -s`" >> "$GITHUB_OUTPUT" | |
| - name: Pack artifacts | |
| id: pack_artifacts | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| run: | | |
| cp ggml/LICENSE ./build/bin/ggml.txt | |
| cp LICENSE ./build/bin/stable-diffusion.cpp.txt | |
| zip -y -r sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-${{ steps.system-info.outputs.OS_TYPE }}-Ubuntu-${{ env.UBUNTU_VERSION }}-${{ steps.system-info.outputs.CPU_ARCH }}-rocm-${{ matrix.ROCM_VERSION }}.zip ./build/bin | |
| - name: Upload artifacts | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-${{ steps.system-info.outputs.OS_TYPE }}-Ubuntu-${{ env.UBUNTU_VERSION }}-${{ steps.system-info.outputs.CPU_ARCH }}-rocm-${{ matrix.ROCM_VERSION }}.zip | |
| path: | | |
| sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-${{ steps.system-info.outputs.OS_TYPE }}-Ubuntu-${{ env.UBUNTU_VERSION }}-${{ steps.system-info.outputs.CPU_ARCH }}-rocm-${{ matrix.ROCM_VERSION }}.zip | |
| macos-arm64-cmake: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: macos-14 | |
| label: macos-14 | |
| - os: macos-latest | |
| label: macos-latest | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - name: Clone | |
| uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| repository: 'leejet/stable-diffusion.cpp' | |
| - name: ccache | |
| uses: ggml-org/ccache-action@v1.2.21 | |
| with: | |
| key: macos-arm64-${{ matrix.label }} | |
| evict-old-files: 1d | |
| - name: Build | |
| id: cmake_build | |
| run: | | |
| sysctl -a | |
| mkdir build | |
| cd build | |
| cmake .. \ | |
| -DGGML_METAL=ON \ | |
| -DGGML_METAL_USE_BF16=ON \ | |
| -DGGML_METAL_EMBED_LIBRARY=ON \ | |
| -DSD_BUILD_SHARED_LIBS=ON \ | |
| -DCMAKE_INSTALL_RPATH='@loader_path' \ | |
| -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \ | |
| -DCMAKE_BUILD_TYPE=Release | |
| cmake --build . --config Release -j $(sysctl -n hw.logicalcpu) | |
| - name: Get commit hash | |
| id: commit | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| uses: prompt/actions-commit-hash@v2 | |
| - name: Fetch system info | |
| id: system-info | |
| run: | | |
| echo "CPU_ARCH=`uname -m`" >> "$GITHUB_OUTPUT" | |
| echo "OS_NAME=`sw_vers -productName`" >> "$GITHUB_OUTPUT" | |
| echo "OS_VERSION=`sw_vers -productVersion`" >> "$GITHUB_OUTPUT" | |
| echo "OS_TYPE=`uname -s`" >> "$GITHUB_OUTPUT" | |
| - name: Pack artifacts | |
| id: pack_artifacts | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| run: | | |
| cp ggml/LICENSE ./build/bin/ggml.txt | |
| cp LICENSE ./build/bin/stable-diffusion.cpp.txt | |
| zip -j sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-${{ steps.system-info.outputs.OS_TYPE }}-${{ steps.system-info.outputs.OS_NAME }}-${{ steps.system-info.outputs.OS_VERSION }}-${{ steps.system-info.outputs.CPU_ARCH }}.zip ./build/bin/* | |
| - name: Upload artifacts | |
| if: ${{ github.event_name == 'schedule' || github.event.inputs.create_release == 'true' }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-${{ steps.system-info.outputs.OS_TYPE }}-${{ steps.system-info.outputs.OS_NAME }}-${{ steps.system-info.outputs.OS_VERSION }}-${{ steps.system-info.outputs.CPU_ARCH }}.zip | |
| path: | | |
| sd-${{ env.BRANCH_NAME }}-${{ steps.commit.outputs.short }}-bin-${{ steps.system-info.outputs.OS_TYPE }}-${{ steps.system-info.outputs.OS_NAME }}-${{ steps.system-info.outputs.OS_VERSION }}-${{ steps.system-info.outputs.CPU_ARCH }}.zip | |
| release: | |
| # always() overrides the default behavior of skipping this job when a | |
| # needed build job fails (e.g. one CUDA sm_* matrix leg fails while | |
| # sibling legs succeed and upload). The job must still run so the | |
| # per-family checks below can decide what's actually complete and safe | |
| # to publish. | |
| if: ${{ always() && (github.event_name == 'schedule' || github.event.inputs.create_release == 'true') }} | |
| permissions: | |
| contents: write | |
| runs-on: ubuntu-latest | |
| needs: | |
| - ubuntu-latest-cmake | |
| - ubuntu-latest-cmake-vulkan | |
| - ubuntu-latest-cuda | |
| - ubuntu-arm64-cuda | |
| - windows-latest-cuda | |
| - ubuntu-latest-rocm | |
| - macos-arm64-cmake | |
| - windows-latest-cmake | |
| - windows-latest-rocm | |
| steps: | |
| - name: Clone | |
| id: checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| fetch-depth: 0 | |
| repository: 'leejet/stable-diffusion.cpp' | |
| - name: Download artifacts | |
| id: download-artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: ./artifact | |
| pattern: sd-* | |
| merge-multiple: true | |
| - name: Get commit count | |
| id: commit_count | |
| run: | | |
| echo "count=$(git rev-list --count HEAD)" >> $GITHUB_OUTPUT | |
| - name: Get commit hash | |
| id: commit | |
| uses: prompt/actions-commit-hash@v2 | |
| - name: Generate tag name | |
| id: tag_name | |
| run: | | |
| TAG_NAME="${{ env.BRANCH_NAME }}-${{ steps.commit_count.outputs.count }}-${{ steps.commit.outputs.short }}" | |
| echo "name=${TAG_NAME}" >> $GITHUB_OUTPUT | |
| - name: Check release artifacts | |
| id: check_artifacts | |
| env: | |
| BRANCH: ${{ env.BRANCH_NAME }} | |
| SHORT: ${{ steps.commit.outputs.short }} | |
| run: | | |
| total_missing=0 | |
| summary="" | |
| check_family() { | |
| local family="$1"; shift | |
| local patterns=("$@") | |
| local missing=0 | |
| for pattern in "${patterns[@]}"; do | |
| if ! ls $pattern >/dev/null 2>&1; then | |
| echo "::error::[$family] Missing artifact: $pattern" | |
| missing=$((missing + 1)) | |
| fi | |
| done | |
| if [ "$missing" -gt 0 ]; then | |
| echo "::warning::$family family is incomplete ($missing artifact(s) missing) — dropping all $family artifacts from this release." | |
| for pattern in "${patterns[@]}"; do | |
| rm -fv $pattern 2>/dev/null || true | |
| done | |
| total_missing=$((total_missing + missing)) | |
| summary="${summary}${summary:+, }${family}: $missing missing, family dropped" | |
| fi | |
| } | |
| # Each backend family must be published as a complete, internally | |
| # consistent set across every platform/variant/SDK it covers — never | |
| # a partial mix. A gap in one family drops that whole family from | |
| # the release; other families are unaffected. | |
| # CUDA: 8 sm_* variants on ubuntu x64 and windows x64; only sm_121 | |
| # (GB10) is built for ubuntu arm64. | |
| cuda_patterns=() | |
| for sm in sm_75 sm_80 sm_86 sm_89 sm_90 sm_100 sm_120 sm_121; do | |
| cuda_patterns+=("artifact/sd-${BRANCH}-${SHORT}-ubuntu-cuda-${sm}-x64.tar.xz") | |
| cuda_patterns+=("artifact/sd-${BRANCH}-${SHORT}-windows-cuda-${sm}-x64.zip") | |
| done | |
| cuda_patterns+=("artifact/sd-${BRANCH}-${SHORT}-ubuntu-cuda-sm_121-arm64.tar.xz") | |
| check_family cuda "${cuda_patterns[@]}" | |
| # TheRock nightly ROCm 7.14.0 (windows-latest-rocm + the 7.14.0 leg | |
| # of ubuntu-latest-rocm). Kept separate from the HIP SDK line below | |
| # since they're different SDKs, not just different platforms. | |
| check_family rocm-therock \ | |
| "artifact/sd-${BRANCH}-${SHORT}-bin-win-rocm-7.14.0-x64.zip" \ | |
| "artifact/sd-${BRANCH}-${SHORT}-bin-Linux-Ubuntu-24.04-x86_64-rocm-7.14.0.zip" | |
| # CPU: ubuntu-latest-cmake's filename embeds the runner's OS name/ | |
| # version via lsb_release, so it's wildcarded rather than pinned. | |
| check_family cpu \ | |
| "artifact/sd-${BRANCH}-${SHORT}-bin-Linux-*-x86_64.zip" \ | |
| "artifact/sd-${BRANCH}-${SHORT}-bin-win-cpu-x64.zip" | |
| # Vulkan: same runner as CPU, differs only in -DSD_VULKAN=ON. | |
| # Only builds Linux since the runner doesn't have a dedicated Windows vulkan build. | |
| check_family vulkan \ | |
| "artifact/sd-${BRANCH}-${SHORT}-bin-Linux-*-x86_64-vulkan.zip" | |
| check_family metal \ | |
| "artifact/sd-${BRANCH}-${SHORT}-bin-Darwin-macOS-*-arm64.zip" | |
| echo "missing=$total_missing" >> "$GITHUB_OUTPUT" | |
| echo "summary=$summary" >> "$GITHUB_OUTPUT" | |
| files=$(find ./artifact -maxdepth 1 \( -name '*.zip' -o -name '*.tar.xz' \) 2>/dev/null | wc -l) | |
| # Never create or update a release with nothing to publish. | |
| if [ "$files" -eq 0 ]; then | |
| echo "::error::No release artifacts found in ./artifact — aborting before creating a release." | |
| exit 1 | |
| fi | |
| if [ "$total_missing" -gt 0 ]; then | |
| echo "$total_missing artifact(s) missing ($summary) — continuing to publish the $files artifact(s) from complete families. The job will still fail below so the gap gets noticed." | |
| else | |
| echo "All expected artifacts present. Found $files artifact(s) ready to upload." | |
| fi | |
| - name: Determine release summary | |
| id: release_summary | |
| run: | | |
| if [[ "${{ github.event_name }}" == "schedule" ]]; then | |
| echo "value=Nightly release for ${{ github.sha }}" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "value=$(git log -1 --pretty=%s)" >> "$GITHUB_OUTPUT" | |
| fi | |
| # Get the release for this tag, creating it if it does not exist yet. | |
| # This is idempotent: if a previous run created the release but failed | |
| # partway through uploading (e.g. a transient GitHub outage), re-running | |
| # reuses the existing release so the upload step below can fill the gaps. | |
| - name: Create or get release | |
| id: release | |
| uses: actions/github-script@v8 | |
| env: | |
| TAG_NAME: ${{ steps.tag_name.outputs.name }} | |
| RELEASE_SUMMARY: ${{ steps.release_summary.outputs.value }} | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const tag = process.env.TAG_NAME; | |
| const { owner, repo } = context.repo; | |
| let release; | |
| try { | |
| release = (await github.rest.repos.getReleaseByTag({ owner, repo, tag })).data; | |
| core.info(`Reusing existing release ${tag} (id ${release.id})`); | |
| } catch (e) { | |
| if (e.status !== 404) throw e; | |
| try { | |
| release = (await github.rest.repos.createRelease({ owner, repo, tag_name: tag, body: process.env.RELEASE_SUMMARY })).data; | |
| core.info(`Created release ${tag} (id ${release.id})`); | |
| } catch (createError) { | |
| if (createError.status !== 422) throw createError; | |
| release = (await github.rest.repos.getReleaseByTag({ owner, repo, tag })).data; | |
| core.info(`Reusing concurrently created release ${tag} (id ${release.id})`); | |
| } | |
| } | |
| core.setOutput('id', release.id); | |
| - name: Upload release | |
| id: upload_release | |
| uses: actions/github-script@v8 | |
| env: | |
| RELEASE_ID: ${{ steps.release.outputs.id }} | |
| with: | |
| github-token: ${{secrets.GITHUB_TOKEN}} | |
| script: | | |
| const fs = require('fs'); | |
| const { owner, repo } = context.repo; | |
| const release_id = Number(process.env.RELEASE_ID); | |
| const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); | |
| // Retry transient failures (network errors, 5xx, rate limits) with | |
| // exponential backoff so a momentary GitHub blip does not abort the | |
| // whole upload and leave the release partially populated. | |
| async function withRetry(label, fn, attempts = 5) { | |
| for (let i = 1; ; i++) { | |
| try { | |
| return await fn(); | |
| } catch (e) { | |
| const transient = !e.status || e.status >= 500 || e.status === 429; | |
| if (i >= attempts || !transient) throw e; | |
| const delay = Math.min(30000, 1000 * 2 ** (i - 1)); | |
| core.warning(`${label} failed (attempt ${i}/${attempts}): ${e.message}. Retrying in ${delay}ms`); | |
| await sleep(delay); | |
| } | |
| } | |
| } | |
| const files = fs.readdirSync('./artifact').filter((f) => f.endsWith('.zip') || f.endsWith('.tar.xz')); | |
| const wanted = new Set(files); | |
| // Reconcile existing release assets against what this run decided to | |
| // publish: drop anything not fully uploaded (a broken partial upload) | |
| // and anything not in the current file set. The latter case matters | |
| // because the release is reused across runs against the same tag — | |
| // if a family was complete and published in an earlier run but this | |
| // run finds it incomplete and drops it locally, its assets from that | |
| // earlier run would otherwise linger and make the family look | |
| // complete even though this run couldn't reproduce it. | |
| const existing = new Set(); | |
| for (const a of await github.paginate(github.rest.repos.listReleaseAssets, { owner, repo, release_id })) { | |
| if (a.state === 'uploaded' && wanted.has(a.name)) { | |
| existing.add(a.name); | |
| } else { | |
| const reason = a.state !== 'uploaded' ? `incomplete (${a.state})` : 'stale (not part of this run)'; | |
| core.warning(`deleting ${reason} asset ${a.name}`); | |
| await github.rest.repos.deleteReleaseAsset({ owner, repo, asset_id: a.id }); | |
| } | |
| } | |
| let uploaded = 0; | |
| let skipped = 0; | |
| for (const file of files) { | |
| if (existing.has(file)) { | |
| core.info(`skipping ${file} (already uploaded)`); | |
| skipped++; | |
| continue; | |
| } | |
| const data = fs.readFileSync(`./artifact/${file}`); | |
| await withRetry(`upload ${file}`, () => | |
| github.rest.repos.uploadReleaseAsset({ owner, repo, release_id, name: file, data }) | |
| .catch(async (e) => { | |
| if (e.status !== 422) throw e; | |
| const assets = await github.paginate(github.rest.repos.listReleaseAssets, { owner, repo, release_id }); | |
| const asset = assets.find((a) => a.name === file); | |
| if (asset?.state === 'uploaded') { | |
| core.info(`accepting ${file} (already uploaded)`); | |
| return; | |
| } | |
| if (asset) { | |
| core.warning(`deleting conflicting asset ${file} (${asset.state})`); | |
| await github.rest.repos.deleteReleaseAsset({ owner, repo, asset_id: asset.id }); | |
| throw new Error(`retrying upload for ${file} after deleting conflicting asset`); | |
| } | |
| throw e; | |
| })); | |
| core.info(`uploaded ${file}`); | |
| uploaded++; | |
| } | |
| core.info(`Done: ${uploaded} uploaded, ${skipped} already present, ${files.length} total.`); | |
| - name: Fail if any artifacts were missing | |
| if: steps.check_artifacts.outputs.missing != '0' | |
| run: | | |
| echo "::error::${{ steps.check_artifacts.outputs.missing }} artifact(s) were missing (${{ steps.check_artifacts.outputs.summary }}) — the incomplete families were dropped from this release; other families were still published. See the 'Check release artifacts' step for the full per-file list." | |
| exit 1 |