Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
097c649
ci: add GitHub Actions release workflow [no release]
drzsdrtfg Aug 17, 2026
dbf589e
ci: fix release jobs (explicit win targets, install libomp on mac) [n…
drzsdrtfg Aug 17, 2026
c44b090
ci: only publish release when all backend jobs succeed [no release]
drzsdrtfg Aug 17, 2026
407af39
ci: provision mac OpenMP off, Windows Vulkan SDK + CUDA toolkit [no r…
drzsdrtfg Aug 17, 2026
c8d66f6
ci: adopt llama.cpp release patterns (7z packing, CUDA 12/13 matrix, …
drzsdrtfg Aug 17, 2026
22ded67
ci: use valid Vulkan SDK 1.4.357.0 and full CUDA versions in matrix […
drzsdrtfg Aug 17, 2026
200068a
ci: bump cuda-toolkit to v0.2.36, CUDA 12.4/13.2 [no release]
drzsdrtfg Aug 17, 2026
9d4c568
ci: source vcvarsall before CUDA cmake so nvcc finds cl.exe [no release]
drzsdrtfg Aug 17, 2026
7c8e944
ci: fix robocopy exit-code mapping in CUDA bundle step [no release]
drzsdrtfg Aug 17, 2026
06356eb
ci: fix CUDA artifact zip path (build/bin is 1 level shallower than C…
drzsdrtfg Aug 17, 2026
2ba3acf
ci: bundle CUDA runtime from bin/lib/bin-x64 and stop double-shipping…
drzsdrtfg Aug 18, 2026
2afbd1c
ci(win-cuda): build with GGML_BACKEND_DL like llama.cpp so CUDA ships…
drzsdrtfg Aug 18, 2026
8f3bd1e
ci: port llama.cpp release pipeline for CPU/Vulkan/CUDA/Metal (get-ta…
drzsdrtfg Aug 18, 2026
63f9268
ci(win-cuda): pin CMAKE_CUDA_ARCHITECTURES per toolkit; use CUDA 13.3…
drzsdrtfg Aug 18, 2026
7834fa6
ci(win-cuda): use ggml-style virtual/real CUDA archs (faster) and bun…
drzsdrtfg Aug 18, 2026
a8f0344
ci: one-command releases (publish toggle, scripts/release.sh, docs/RE…
drzsdrtfg Aug 18, 2026
4e03548
ci: one-click GUI releases (publish defaults on) + GUI-first releasin…
drzsdrtfg Aug 18, 2026
348d7a0
ci: remove CLI release helper; GUI-only releasing docs
drzsdrtfg Aug 18, 2026
b5eefce
ci: semver tag-driven releases (remove b<N>/auto-push); manual versio…
drzsdrtfg Aug 18, 2026
5465c17
ci: preserve pre-release flag and notes when attaching binaries to a …
drzsdrtfg Aug 18, 2026
29b6b72
ci: upload only real package files (.zip/.tar.gz) to the release
drzsdrtfg Aug 18, 2026
8b2a092
ci: fix boolean publish gate (inputs.publish) so manual dispatch rele…
drzsdrtfg Aug 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
380 changes: 380 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,380 @@
# audio.cpp - release.yml
#
# Ported from llama.cpp's release workflow and stripped to the backends
# audio.cpp ships: CPU, CUDA, Vulkan, Metal (ROCm kept as best-effort,
# disabled like llama.cpp). Windows CUDA uses the GGML_BACKEND_DL model so the
# CUDA backend is shipped once as ggml-cuda.dll (thin cli/server/gguf shells)
# with the heavy CUDA runtime DLLs in a separate cudart...zip, and the release
# job publishes.
#
# Semantic-version, tag-driven releases. The workflow runs when a `v*` (semver)
# tag is pushed (drafting a Release and Publishing it) or when run manually
# from the Actions UI with an explicit version. Publishing attaches the built
# binaries to that version's GitHub Release. There is NO auto-release on every
# push to `main`.

name: Release

on:
workflow_dispatch:
inputs:
version:
description: 'Semantic version to release, e.g. 1.2.0 or v1.2.0 (used for manual runs; tag-triggered runs use the pushed tag).'
required: true
default: ''
type: string
publish:
description: 'Publish a GitHub Release after the build. Leave unchecked for a build-only dry run.'
required: false
default: false
type: boolean
push:
tags:
- 'v*'

env:
GH_TOKEN: ${{ github.token }}
BUILD_TARGETS: audiocpp_cli audiocpp_server audiocpp_gguf
VULKAN_VERSION: '1.4.357.0'
CMAKE_ARGS: "-DAUDIOCPP_DEPLOYMENT_BUILD=ON -DENGINE_ENABLE_LLAMAFILE=ON -DENGINE_ENABLE_CUDA_GRAPHS=ON"

# note: run this workflow one at a time for better cache reuse
concurrency:
group: release
queue: max

jobs:
check-release:
runs-on: ubuntu-latest
outputs:
should_release: ${{ steps.check.outputs.should_release }}
steps:
# The only triggers are a manually-run workflow or a pushed `v*` tag -
# both are intentional, so always proceed.
- id: check
run: echo "should_release=true" >> "$GITHUB_OUTPUT"

get-version:
runs-on: ubuntu-latest
outputs:
tag: ${{ steps.version.outputs.tag }}
needs: check-release
if: ${{ needs.check-release.outputs.should_release == 'true' }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Resolve release tag
id: version
run: |
if [[ "${{ github.ref_type }}" == "tag" ]]; then
TAG="${{ github.ref_name }}"
elif [[ -n "${{ inputs.version }}" ]]; then
TAG="${{ inputs.version }}"
else
echo "::error::No semver tag or version provided (push a v* tag, or run manually with a version)."
exit 1
fi
[[ "$TAG" == v* ]] || TAG="v${TAG}"
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"

macos-metal:
name: macOS (${{ matrix.build }})
needs: [check-release, get-version]
if: ${{ needs.check-release.outputs.should_release == 'true' }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- build: 'arm64'
arch: 'arm64'
os: macos-26
defines: '-DGGML_METAL=ON -DCMAKE_OSX_DEPLOYMENT_TARGET=13.3 -DENGINE_ENABLE_OPENMP=OFF -DGGML_OPENMP=OFF'
- build: 'x64'
arch: 'x64'
os: macos-15-intel
# Metal disabled on x64 (GitHub Intel runners have no usable GPU)
defines: '-DGGML_METAL=OFF -DCMAKE_OSX_DEPLOYMENT_TARGET=13.3 -DENGINE_ENABLE_OPENMP=OFF -DGGML_OPENMP=OFF'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Configure
run: |
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_RPATH='@loader_path' -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \
-DENGINE_ENABLE_CUDA=OFF -DENGINE_ENABLE_VULKAN=OFF \
${{ matrix.defines }} ${{ env.CMAKE_ARGS }}
- name: Build
run: cmake --build build --config Release --parallel "$(sysctl -n hw.logicalcpu)" --target ${{ env.BUILD_TARGETS }}
- name: Pack
run: |
cp LICENSE build/bin/ 2>/dev/null || true
tar -czvf audio-${{ needs.get-version.outputs.tag }}-bin-macos-${{ matrix.arch }}-metal.tar.gz -C build/bin .
- uses: actions/upload-artifact@v4
with:
name: audio-${{ needs.get-version.outputs.tag }}-bin-macos-${{ matrix.arch }}-metal
path: audio-${{ needs.get-version.outputs.tag }}-bin-macos-${{ matrix.arch }}-metal.tar.gz

linux-cpu:
name: Ubuntu x64 (CPU)
needs: [check-release, get-version]
if: ${{ needs.check-release.outputs.should_release == 'true' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install deps
run: sudo apt-get update && sudo apt-get install -y build-essential cmake make glslc libvulkan-dev spirv-headers
- name: Configure
run: |
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \
-DENGINE_ENABLE_CUDA=OFF -DENGINE_ENABLE_VULKAN=OFF ${{ env.CMAKE_ARGS }}
- name: Build
run: cmake --build build --config Release --parallel "$(nproc)" --target ${{ env.BUILD_TARGETS }}
- name: Pack
run: |
cp LICENSE build/bin/ 2>/dev/null || true
tar -czf audio-${{ needs.get-version.outputs.tag }}-bin-ubuntu-x64-cpu.tar.gz -C build/bin .
- uses: actions/upload-artifact@v4
with:
name: audio-${{ needs.get-version.outputs.tag }}-bin-ubuntu-x64-cpu
path: audio-${{ needs.get-version.outputs.tag }}-bin-ubuntu-x64-cpu.tar.gz

linux-vulkan:
name: Ubuntu x64 (Vulkan)
needs: [check-release, get-version]
if: ${{ needs.check-release.outputs.should_release == 'true' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install deps
run: sudo apt-get update && sudo apt-get install -y build-essential cmake make glslc libvulkan-dev spirv-headers
- name: Configure
run: |
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \
-DENGINE_ENABLE_CUDA=OFF -DENGINE_ENABLE_VULKAN=ON ${{ env.CMAKE_ARGS }}
- name: Build
run: cmake --build build --config Release --parallel "$(nproc)" --target ${{ env.BUILD_TARGETS }}
- name: Pack
run: |
cp LICENSE build/bin/ 2>/dev/null || true
tar -czf audio-${{ needs.get-version.outputs.tag }}-bin-ubuntu-x64-vulkan.tar.gz -C build/bin .
- uses: actions/upload-artifact@v4
with:
name: audio-${{ needs.get-version.outputs.tag }}-bin-ubuntu-x64-vulkan
path: audio-${{ needs.get-version.outputs.tag }}-bin-ubuntu-x64-vulkan.tar.gz

windows-cpu:
name: Windows x64 (CPU)
needs: [check-release, get-version]
if: ${{ needs.check-release.outputs.should_release == 'true' }}
runs-on: windows-2022
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Build
shell: pwsh
run: |
.\scripts\build_windows.ps1 -Preset windows-cpu-release -Target audiocpp_cli
.\scripts\build_windows.ps1 -Preset windows-cpu-release -Target audiocpp_server
.\scripts\build_windows.ps1 -Preset windows-cpu-release -Target audiocpp_gguf
- name: Pack
shell: pwsh
working-directory: build/windows-cpu-release/bin
run: |
cp ..\..\..\LICENSE . 2>$null
7z a -snl ..\..\..\audio-${{ needs.get-version.outputs.tag }}-bin-windows-x64-cpu.zip *
- uses: actions/upload-artifact@v4
with:
name: audio-${{ needs.get-version.outputs.tag }}-bin-windows-x64-cpu
path: audio-${{ needs.get-version.outputs.tag }}-bin-windows-x64-cpu.zip

windows-vulkan:
name: Windows x64 (Vulkan)
needs: [check-release, get-version]
if: ${{ needs.check-release.outputs.should_release == 'true' }}
runs-on: windows-2022
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Vulkan SDK
shell: pwsh
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: Build
shell: pwsh
run: |
.\scripts\build_windows.ps1 -Preset windows-vulkan-release -Target audiocpp_cli
.\scripts\build_windows.ps1 -Preset windows-vulkan-release -Target audiocpp_server
.\scripts\build_windows.ps1 -Preset windows-vulkan-release -Target audiocpp_gguf
- name: Pack
shell: pwsh
working-directory: build/windows-vulkan-release/bin
run: |
cp ..\..\..\LICENSE . 2>$null
7z a -snl ..\..\..\audio-${{ needs.get-version.outputs.tag }}-bin-windows-x64-vulkan.zip *
- uses: actions/upload-artifact@v4
with:
name: audio-${{ needs.get-version.outputs.tag }}-bin-windows-x64-vulkan
path: audio-${{ needs.get-version.outputs.tag }}-bin-windows-x64-vulkan.zip

windows-cuda:
name: 'Windows x64 (CUDA ${{ matrix.label }})'
needs: [check-release, get-version]
if: ${{ needs.check-release.outputs.should_release == 'true' }}
runs-on: windows-2022
strategy:
fail-fast: false
matrix:
include:
- cuda: '12.4.1'
label: '12.4'
cuda_archs: '70;75;80;86;89;90'
- cuda: '13.3.0'
label: '13.3'
cuda_archs: '75;80;86;89;90;120'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install CUDA build tools
uses: Jimver/cuda-toolkit@v0.2.36
with:
cuda: ${{ matrix.cuda }}
method: 'local'
- name: Configure + Build (OpenMP off)
shell: cmd
# Direct CMake (bypasses build_windows.ps1, which hard-requires OpenMP and
# asserts under the CUDA toolchain). OpenMP off matches llama.cpp's CUDA
# path. vcvarsall.bat puts cl.exe on PATH for nvcc.
#
# ENGINE_ENABLE_CPU_ALL_VARIANTS flips BUILD_SHARED_LIBS=ON +
# GGML_BACKEND_DL=ON (audio.cpp/CMakeLists.txt), building the CUDA backend
# once as ggml-cuda.dll and keeping cli/server/gguf as thin shells that
# load backends at runtime -- the same distribution model llama.cpp uses.
# CUDA kernels are no longer duplicated into 3 executables.
#
# CMAKE_CUDA_ARCHITECTURES must be pinned: audio.cpp defaults to
# "native" (the build host GPU), which is meaningless on GPU-less CI
# runners and yields an unreliable CUDA fatbin. Use fixed arch lists per
# toolkit so the released binaries carry correct kernels for the
# supported GPUs (RTX 20/30/40/50-series and datacenter-class). The
# value is quoted so the ';' separators survive cmd's tokenizer.
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 >nul
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release ^
-DENGINE_ENABLE_CUDA=ON -DENGINE_ENABLE_OPENMP=OFF -DGGML_OPENMP=OFF ^
-DENGINE_ENABLE_CUDA_GRAPHS=ON -DENGINE_ENABLE_VULKAN=OFF -DENGINE_ENABLE_METAL=OFF ^
-DENGINE_ENABLE_LLAMAFILE=ON -DENGINE_ENABLE_NATIVE_CPU=ON -DENGINE_BUILD_TESTS=OFF ^
-DENGINE_ENABLE_CPU_ALL_VARIANTS=ON ^
"-DCMAKE_CUDA_ARCHITECTURES=${{ matrix.cuda_archs }}" ^
-DAUDIOCPP_DEPLOYMENT_BUILD=ON -DCUDAToolkit_ROOT="%CUDA_PATH%"
cmake --build build --config Release -j %NUMBER_OF_PROCESSORS% --target ${{ env.BUILD_TARGETS }}
- name: Bundle CUDA runtime
shell: pwsh
# llama.cpp copies the runtime DLLs from every candidate dir without
# looking at robocopy's exit code: bin\x64 is a CUDA 13 layout, so on
# CUDA 12.x robocopy returns 16 for that missing dir, which is benign
# (llama's step ends on the successful 7z). Mirror that here -- copy
# from whichever dir exists and terminate on exit 0. The trailing guard
# only trips if NO cudart was copied at all (a broken/empty toolkit).
# cufft64_*.dll is included because engine_runtime links CUDA::cufft
# for its CUDA inverse-STFT kernel (CMakeLists.txt).
run: |
$dst = "build\bin\cudart"
New-Item -ItemType Directory -Force -Path $dst | Out-Null
$dlls = "cudart64_*.dll", "cublas64_*.dll", "cublasLt64_*.dll", "cufft64_*.dll"
robocopy "$env:CUDA_PATH\bin" $dst $dlls
robocopy "$env:CUDA_PATH\lib" $dst $dlls
robocopy "$env:CUDA_PATH\bin\x64" $dst $dlls
if (-not (Get-ChildItem -Path $dst -Filter 'cudart64_*.dll' -ErrorAction SilentlyContinue)) {
Write-Error "CUDA runtime DLLs were not found under $env:CUDA_PATH"
exit 1
}
exit 0
- name: Pack
shell: pwsh
working-directory: build/bin
# -x!cudart keeps the heavy CUDA runtime DLLs out of the bin zip so they
# are shipped exactly once (in the separate cudart...zip), matching
# llama.cpp.
run: |
cp ..\..\LICENSE . 2>$null
7z a -snl ..\..\audio-${{ needs.get-version.outputs.tag }}-bin-windows-x64-cuda${{ matrix.label }}.zip * -x!cudart
7z a -snl ..\..\audio-${{ needs.get-version.outputs.tag }}-cudart-windows-x64-cuda${{ matrix.label }}.zip cudart\*
- uses: actions/upload-artifact@v4
with:
name: audio-${{ needs.get-version.outputs.tag }}-bin-windows-x64-cuda${{ matrix.label }}
path: 'audio-${{ needs.get-version.outputs.tag }}-*cuda${{ matrix.label }}.zip'

# Best-effort ROCm builds. Kept OUT of the release `needs` and commented by
# default (llama.cpp ships its ROCm job disabled as well) because GitHub
# runners have no AMD GPU and HIP toolchain provisioning is heavy. Enable by
# uncommenting and pointing at a runner that can provide a ROCm/HIP runtime.
# linux-rocm:
# ...

release:
name: Create release
needs:
- check-release
- get-version
- macos-metal
- linux-cpu
- linux-vulkan
- windows-cpu
- windows-vulkan
- windows-cuda
if: ${{ needs.check-release.outputs.should_release == 'true' && (github.ref_type == 'tag' || inputs.publish) }}
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: assets
merge-multiple: true
- name: Create and push git tag
run: |
TAG="${{ needs.get-version.outputs.tag }}"
if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null 2>&1; then
echo "Tag ${TAG} already exists, skipping creation"
else
git tag "${TAG}"
git push origin "${TAG}"
fi
- name: Check for existing release
id: relstate
run: |
TAG="${{ needs.get-version.outputs.tag }}"
if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
echo "exists=true" >> "$GITHUB_OUTPUT"
else
echo "exists=false" >> "$GITHUB_OUTPUT"
fi
# Existing release (e.g. one the maintainer drafted and published):
# attach the built binaries only, preserving its pre-release flag and
# hand-written notes. --clobber allows rebuilding the same version.
- name: Upload binaries to existing release
if: ${{ steps.relstate.outputs.exists == 'true' }}
run: |
gh release upload "${{ needs.get-version.outputs.tag }}" assets/*.zip assets/*.tar.gz --clobber --repo "$GITHUB_REPOSITORY"
# Newly-created tag with no release yet: create the release w/ notes.
- name: Create release
if: ${{ steps.relstate.outputs.exists != 'true' }}
run: |
gh release create "${{ needs.get-version.outputs.tag }}" assets/*.zip assets/*.tar.gz --title "${{ needs.get-version.outputs.tag }}" --generate-notes --repo "$GITHUB_REPOSITORY"
Loading
Loading