ci(release): ship the C-API shared library and header (#25) (#29) #7
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: release | |
| # Pre-built parakeet-cli bundles for every release (issue #21). | |
| # | |
| # One self-contained binary per (platform, backend) pair, packaged with the | |
| # LICENSE and README. BUILD_SHARED_LIBS=OFF folds the ggml backends into the | |
| # binary (the docker images keep them shared; a download-and-run bundle should | |
| # not need a lib directory). GGML_NATIVE=OFF keeps the binaries portable | |
| # across CPUs, same as the docker images and ci.yml. | |
| # | |
| # Variants: | |
| # linux x64: cpu, vulkan, cuda arm64: cpu | |
| # macos arm64: metal x64: cpu (cross-compiled on the arm | |
| # runner; GitHub is retiring Intel ones) | |
| # windows x64: cpu, vulkan, cuda | |
| # | |
| # CUDA notes (same reasoning as docker.yml): GGML_CUDA_NO_VMM=ON because the | |
| # build runners have no GPU driver to link libcuda against. Linux uses the | |
| # CUDA 13 apt repo so Blackwell (sm_120) is covered; the cudart/cublas | |
| # runtime libraries are bundled into the tarball next to the binary, which | |
| # carries an $ORIGIN rpath. Windows ships them as a separate cudart zip | |
| # (llama.cpp convention) so users who already have the toolkit skip a large | |
| # download. | |
| # | |
| # Triggers: pushing a v* tag builds everything and attaches the bundles to | |
| # the GitHub release for that tag (creating a draft release if none exists | |
| # yet, so creating the release before or after pushing the tag both work). | |
| # workflow_dispatch builds the same bundles and leaves them as workflow | |
| # artifacts, useful for testing changes to this file. | |
| on: | |
| push: | |
| tags: ['v*'] | |
| branches: [feat/release-binaries] # TEMP: matrix validation, remove before merge | |
| workflow_dispatch: | |
| defaults: | |
| run: | |
| shell: bash | |
| jobs: | |
| # --------------------------------------------------------------------------- | |
| # linux: cpu (x64 + arm64, native runners), vulkan (LunarG SDK), cuda | |
| # (CUDA 13 apt repo). cpu/vulkan build on ubuntu-22.04 for a wider glibc | |
| # range; cuda needs the ubuntu2404 CUDA repo. | |
| # --------------------------------------------------------------------------- | |
| build-linux: | |
| runs-on: ${{ matrix.runner }} | |
| timeout-minutes: 180 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - backend: cpu | |
| arch: x64 | |
| runner: ubuntu-22.04 | |
| cmake_args: "" | |
| cuda_archs: "" | |
| - backend: cpu | |
| arch: arm64 | |
| runner: ubuntu-22.04-arm | |
| cmake_args: "" | |
| cuda_archs: "" | |
| - backend: vulkan | |
| arch: x64 | |
| runner: ubuntu-22.04 | |
| cmake_args: "-DPARAKEET_GGML_VULKAN=ON" | |
| cuda_archs: "" | |
| - backend: cuda | |
| arch: x64 | |
| runner: ubuntu-24.04 | |
| # No CMAKE_CUDA_ARCHITECTURES: ggml's curated default applies, | |
| # the same list llama.cpp releases ship (PTX for the datacenter | |
| # gens, real code for 86/89/120a, plus 121a for GB10 on CUDA 13). | |
| cmake_args: "-DPARAKEET_GGML_CUDA=ON -DGGML_CUDA_NO_VMM=ON" | |
| cuda_archs: "" | |
| steps: | |
| - name: Checkout (with submodules) | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Determine version | |
| id: ver | |
| run: | | |
| if [ "${GITHUB_REF_TYPE}" = "tag" ]; then | |
| echo "version=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "version=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Install Vulkan SDK (LunarG) | |
| if: matrix.backend == 'vulkan' | |
| run: | | |
| wget -qO- https://packages.lunarg.com/lunarg-signing-key-pub.asc \ | |
| | sudo tee /etc/apt/trusted.gpg.d/lunarg.asc >/dev/null | |
| sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-jammy.list \ | |
| https://packages.lunarg.com/vulkan/lunarg-vulkan-jammy.list | |
| sudo apt-get update | |
| sudo apt-get install -y vulkan-sdk | |
| - name: Install CUDA toolkit 13 | |
| if: matrix.backend == 'cuda' | |
| run: | | |
| wget -q https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/x86_64/cuda-keyring_1.1-1_all.deb | |
| sudo dpkg -i cuda-keyring_1.1-1_all.deb | |
| sudo apt-get update | |
| sudo apt-get install -y cuda-toolkit-13-0 | |
| echo "/usr/local/cuda/bin" >> "$GITHUB_PATH" | |
| - name: Configure | |
| env: | |
| CUDA_ARCHS: ${{ matrix.cuda_archs }} | |
| run: | | |
| EXTRA="" | |
| if [ "${{ matrix.backend }}" = "cuda" ]; then | |
| # $ORIGIN rpath so the bundled cudart/cublas next to the binary | |
| # are found without LD_LIBRARY_PATH. | |
| EXTRA="-DCMAKE_BUILD_RPATH=\$ORIGIN" | |
| fi | |
| cmake -B build \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DGGML_NATIVE=OFF \ | |
| -DBUILD_SHARED_LIBS=OFF \ | |
| -DPARAKEET_BUILD_CLI=ON \ | |
| -DPARAKEET_BUILD_TESTS=OFF \ | |
| ${{ matrix.cmake_args }} \ | |
| ${CUDA_ARCHS:+"-DCMAKE_CUDA_ARCHITECTURES=${CUDA_ARCHS}"} \ | |
| ${EXTRA:+"$EXTRA"} | |
| - name: Build | |
| run: cmake --build build -j"$(getconf _NPROCESSORS_ONLN)" | |
| - name: Smoke test (usage banner) | |
| # The CLI exits nonzero when invoked bare; capture first so set -e | |
| # only judges the grep. | |
| run: | | |
| out=$(./build/examples/cli/parakeet-cli 2>&1 || true) | |
| grep -qi usage <<<"$out" | |
| - name: Package | |
| id: pack | |
| run: | | |
| BUNDLE="parakeet-${{ steps.ver.outputs.version }}-bin-linux-${{ matrix.backend }}-${{ matrix.arch }}" | |
| mkdir "$BUNDLE" | |
| cp build/examples/cli/parakeet-cli LICENSE README.md "$BUNDLE"/ | |
| if [ "${{ matrix.backend }}" = "cuda" ]; then | |
| cp -P /usr/local/cuda/targets/x86_64-linux/lib/libcudart.so* \ | |
| /usr/local/cuda/targets/x86_64-linux/lib/libcublas.so* \ | |
| /usr/local/cuda/targets/x86_64-linux/lib/libcublasLt.so* \ | |
| "$BUNDLE"/ | |
| fi | |
| tar -czf "$BUNDLE.tar.gz" "$BUNDLE" | |
| echo "bundle=$BUNDLE" >> "$GITHUB_OUTPUT" | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ steps.pack.outputs.bundle }} | |
| path: ${{ steps.pack.outputs.bundle }}.tar.gz | |
| if-no-files-found: error | |
| # Shared C-API lib (issue #25): a separate build so the CLI bundle above | |
| # stays a single self-contained binary. PARAKEET_SHARED=ON folds ggml into | |
| # libparakeet.so the same way it is folded into the CLI. | |
| - name: Configure (shared C-API lib) | |
| env: | |
| CUDA_ARCHS: ${{ matrix.cuda_archs }} | |
| run: | | |
| EXTRA="" | |
| if [ "${{ matrix.backend }}" = "cuda" ]; then | |
| EXTRA="-DCMAKE_BUILD_RPATH=\$ORIGIN" | |
| fi | |
| cmake -B build-shared \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DGGML_NATIVE=OFF \ | |
| -DBUILD_SHARED_LIBS=OFF \ | |
| -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ | |
| -DPARAKEET_SHARED=ON \ | |
| -DPARAKEET_BUILD_CLI=OFF \ | |
| -DPARAKEET_BUILD_TESTS=OFF \ | |
| ${{ matrix.cmake_args }} \ | |
| ${CUDA_ARCHS:+"-DCMAKE_CUDA_ARCHITECTURES=${CUDA_ARCHS}"} \ | |
| ${EXTRA:+"$EXTRA"} | |
| - name: Build (shared C-API lib) | |
| run: cmake --build build-shared -j"$(getconf _NPROCESSORS_ONLN)" | |
| - name: Package (shared C-API lib) | |
| id: pack_lib | |
| run: | | |
| BUNDLE="parakeet-${{ steps.ver.outputs.version }}-lib-linux-${{ matrix.backend }}-${{ matrix.arch }}" | |
| mkdir "$BUNDLE" | |
| cp build-shared/libparakeet.so include/parakeet_capi.h LICENSE README.md "$BUNDLE"/ | |
| if [ "${{ matrix.backend }}" = "cuda" ]; then | |
| cp -P /usr/local/cuda/targets/x86_64-linux/lib/libcudart.so* \ | |
| /usr/local/cuda/targets/x86_64-linux/lib/libcublas.so* \ | |
| /usr/local/cuda/targets/x86_64-linux/lib/libcublasLt.so* \ | |
| "$BUNDLE"/ | |
| fi | |
| tar -czf "$BUNDLE.tar.gz" "$BUNDLE" | |
| echo "bundle=$BUNDLE" >> "$GITHUB_OUTPUT" | |
| - name: Upload shared C-API lib artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ steps.pack_lib.outputs.bundle }} | |
| path: ${{ steps.pack_lib.outputs.bundle }}.tar.gz | |
| if-no-files-found: error | |
| # --------------------------------------------------------------------------- | |
| # macos: metal on arm64 (the metallib is embedded in the binary, nothing to | |
| # ship alongside), plus a cpu-only x64 build cross-compiled on the same | |
| # arm64 runner. | |
| # --------------------------------------------------------------------------- | |
| build-macos: | |
| runs-on: macos-14 | |
| timeout-minutes: 120 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - backend: metal | |
| arch: arm64 | |
| cmake_args: "-DPARAKEET_GGML_METAL=ON -DGGML_METAL_EMBED_LIBRARY=ON" | |
| - backend: cpu | |
| arch: x64 | |
| cmake_args: "-DCMAKE_OSX_ARCHITECTURES=x86_64" | |
| steps: | |
| - name: Checkout (with submodules) | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Determine version | |
| id: ver | |
| run: | | |
| if [ "${GITHUB_REF_TYPE}" = "tag" ]; then | |
| echo "version=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "version=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Configure | |
| run: | | |
| cmake -B build \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DGGML_NATIVE=OFF \ | |
| -DBUILD_SHARED_LIBS=OFF \ | |
| -DPARAKEET_BUILD_CLI=ON \ | |
| -DPARAKEET_BUILD_TESTS=OFF \ | |
| ${{ matrix.cmake_args }} | |
| - name: Build | |
| run: cmake --build build -j"$(getconf _NPROCESSORS_ONLN)" | |
| - name: Smoke test (usage banner) | |
| # The x64 binary needs Rosetta; only smoke test the native build. | |
| if: matrix.arch == 'arm64' | |
| run: | | |
| out=$(./build/examples/cli/parakeet-cli 2>&1 || true) | |
| grep -qi usage <<<"$out" | |
| - name: Package | |
| id: pack | |
| run: | | |
| BUNDLE="parakeet-${{ steps.ver.outputs.version }}-bin-macos-${{ matrix.backend }}-${{ matrix.arch }}" | |
| mkdir "$BUNDLE" | |
| cp build/examples/cli/parakeet-cli LICENSE README.md "$BUNDLE"/ | |
| tar -czf "$BUNDLE.tar.gz" "$BUNDLE" | |
| echo "bundle=$BUNDLE" >> "$GITHUB_OUTPUT" | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ steps.pack.outputs.bundle }} | |
| path: ${{ steps.pack.outputs.bundle }}.tar.gz | |
| if-no-files-found: error | |
| # Shared C-API lib (issue #25). Separate build, same reasoning as linux. | |
| - name: Configure (shared C-API lib) | |
| run: | | |
| cmake -B build-shared \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DGGML_NATIVE=OFF \ | |
| -DBUILD_SHARED_LIBS=OFF \ | |
| -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ | |
| -DPARAKEET_SHARED=ON \ | |
| -DPARAKEET_BUILD_CLI=OFF \ | |
| -DPARAKEET_BUILD_TESTS=OFF \ | |
| ${{ matrix.cmake_args }} | |
| - name: Build (shared C-API lib) | |
| run: cmake --build build-shared -j"$(getconf _NPROCESSORS_ONLN)" | |
| - name: Package (shared C-API lib) | |
| id: pack_lib | |
| run: | | |
| BUNDLE="parakeet-${{ steps.ver.outputs.version }}-lib-macos-${{ matrix.backend }}-${{ matrix.arch }}" | |
| mkdir "$BUNDLE" | |
| cp build-shared/libparakeet.dylib include/parakeet_capi.h LICENSE README.md "$BUNDLE"/ | |
| tar -czf "$BUNDLE.tar.gz" "$BUNDLE" | |
| echo "bundle=$BUNDLE" >> "$GITHUB_OUTPUT" | |
| - name: Upload shared C-API lib artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ steps.pack_lib.outputs.bundle }} | |
| path: ${{ steps.pack_lib.outputs.bundle }}.tar.gz | |
| if-no-files-found: error | |
| # --------------------------------------------------------------------------- | |
| # windows: MSVC via Ninja (ilammy/msvc-dev-cmd provides the cl environment, | |
| # which also lets nvcc use cl without the Visual Studio CUDA integration). | |
| # The ggml patches are applied explicitly under Git Bash first: CMake's | |
| # find_program(bash) can pick up the stub WSL bash.exe in System32, which | |
| # would skip the patches with only a warning. | |
| # --------------------------------------------------------------------------- | |
| build-windows: | |
| runs-on: windows-2022 | |
| timeout-minutes: 300 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - backend: cpu | |
| cmake_args: "" | |
| cuda_archs: "" | |
| - backend: vulkan | |
| cmake_args: "-DPARAKEET_GGML_VULKAN=ON" | |
| cuda_archs: "" | |
| - backend: cuda | |
| # CUDA 12.8: sm_120 support starts there (CUDA 13 is not in the | |
| # cuda-toolkit action yet). No CMAKE_CUDA_ARCHITECTURES: ggml's | |
| # curated default applies, same as the llama.cpp releases. | |
| cmake_args: "-DPARAKEET_GGML_CUDA=ON -DGGML_CUDA_NO_VMM=ON" | |
| cuda_archs: "" | |
| env: | |
| VULKAN_VERSION: 1.4.321.1 | |
| steps: | |
| - name: Checkout (with submodules) | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Determine version | |
| id: ver | |
| run: | | |
| if [ "${GITHUB_REF_TYPE}" = "tag" ]; then | |
| echo "version=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "version=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Apply ggml patches (Git Bash) | |
| run: bash scripts/apply_ggml_patches.sh | |
| - name: Install Vulkan SDK | |
| if: matrix.backend == 'vulkan' | |
| shell: pwsh | |
| run: | | |
| curl.exe -L -o vulkan-sdk.exe "https://sdk.lunarg.com/sdk/download/$env:VULKAN_VERSION/windows/vulkansdk-windows-X64-$env:VULKAN_VERSION.exe" | |
| Start-Process -Wait -FilePath .\vulkan-sdk.exe -ArgumentList '--accept-licenses','--default-answer','--confirm-command','install' | |
| "VULKAN_SDK=C:\VulkanSDK\$env:VULKAN_VERSION" | Out-File -Append $env:GITHUB_ENV | |
| "C:\VulkanSDK\$env:VULKAN_VERSION\Bin" | Out-File -Append $env:GITHUB_PATH | |
| - name: Install CUDA toolkit | |
| if: matrix.backend == 'cuda' | |
| uses: Jimver/cuda-toolkit@v0.2.21 | |
| with: | |
| cuda: '12.8.0' | |
| method: network | |
| sub-packages: '["nvcc", "cudart", "cublas", "cublas_dev", "thrust"]' | |
| use-github-cache: true | |
| - name: MSVC environment | |
| uses: ilammy/msvc-dev-cmd@v1 | |
| - name: Configure | |
| env: | |
| CUDA_ARCHS: ${{ matrix.cuda_archs }} | |
| run: | | |
| cmake -B build -G Ninja \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DGGML_NATIVE=OFF \ | |
| -DBUILD_SHARED_LIBS=OFF \ | |
| -DPARAKEET_BUILD_CLI=ON \ | |
| -DPARAKEET_BUILD_TESTS=OFF \ | |
| ${{ matrix.cmake_args }} \ | |
| ${CUDA_ARCHS:+"-DCMAKE_CUDA_ARCHITECTURES=${CUDA_ARCHS}"} | |
| - name: Build | |
| run: cmake --build build -j | |
| - name: Smoke test (usage banner) | |
| # The vulkan binary needs vulkan-1.dll, which the SDK install provides | |
| # on the runner; cpu and cuda load on a bare machine. | |
| run: | | |
| out=$(./build/examples/cli/parakeet-cli.exe 2>&1 || true) | |
| grep -qi usage <<<"$out" | |
| - name: Package | |
| id: pack | |
| shell: pwsh | |
| run: | | |
| $bundle = "parakeet-${{ steps.ver.outputs.version }}-bin-win-${{ matrix.backend }}-x64" | |
| New-Item -ItemType Directory -Path $bundle | Out-Null | |
| Copy-Item build/examples/cli/parakeet-cli.exe,LICENSE,README.md $bundle/ | |
| Compress-Archive -Path $bundle -DestinationPath "$bundle.zip" | |
| "bundle=$bundle" | Out-File -Append $env:GITHUB_OUTPUT | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ steps.pack.outputs.bundle }} | |
| path: ${{ steps.pack.outputs.bundle }}.zip | |
| if-no-files-found: error | |
| # Shared C-API lib (issue #25). Separate build, same reasoning as linux. | |
| # WINDOWS_EXPORT_ALL_SYMBOLS (set in CMakeLists) makes the DLL export its | |
| # extern "C" entry points so ctypes/dlopen can find them. | |
| - name: Configure (shared C-API lib) | |
| env: | |
| CUDA_ARCHS: ${{ matrix.cuda_archs }} | |
| run: | | |
| cmake -B build-shared -G Ninja \ | |
| -DCMAKE_BUILD_TYPE=Release \ | |
| -DGGML_NATIVE=OFF \ | |
| -DBUILD_SHARED_LIBS=OFF \ | |
| -DCMAKE_POSITION_INDEPENDENT_CODE=ON \ | |
| -DPARAKEET_SHARED=ON \ | |
| -DPARAKEET_BUILD_CLI=OFF \ | |
| -DPARAKEET_BUILD_TESTS=OFF \ | |
| ${{ matrix.cmake_args }} \ | |
| ${CUDA_ARCHS:+"-DCMAKE_CUDA_ARCHITECTURES=${CUDA_ARCHS}"} | |
| - name: Build (shared C-API lib) | |
| run: cmake --build build-shared -j | |
| - name: Package (shared C-API lib) | |
| id: pack_lib | |
| shell: pwsh | |
| run: | | |
| $bundle = "parakeet-${{ steps.ver.outputs.version }}-lib-win-${{ matrix.backend }}-x64" | |
| New-Item -ItemType Directory -Path $bundle | Out-Null | |
| Copy-Item build-shared/parakeet.dll,include/parakeet_capi.h,LICENSE,README.md $bundle/ | |
| Compress-Archive -Path $bundle -DestinationPath "$bundle.zip" | |
| "bundle=$bundle" | Out-File -Append $env:GITHUB_OUTPUT | |
| - name: Upload shared C-API lib artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ steps.pack_lib.outputs.bundle }} | |
| path: ${{ steps.pack_lib.outputs.bundle }}.zip | |
| if-no-files-found: error | |
| - name: Package CUDA runtime DLLs | |
| if: matrix.backend == 'cuda' | |
| shell: pwsh | |
| run: | | |
| $name = "cudart-parakeet-bin-win-cuda-x64" | |
| New-Item -ItemType Directory -Path $name | Out-Null | |
| Copy-Item "$env:CUDA_PATH\bin\cudart64*.dll","$env:CUDA_PATH\bin\cublas64*.dll","$env:CUDA_PATH\bin\cublasLt64*.dll" $name/ | |
| Compress-Archive -Path $name -DestinationPath "$name.zip" | |
| - name: Upload CUDA runtime artifact | |
| if: matrix.backend == 'cuda' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: cudart-parakeet-bin-win-cuda-x64 | |
| path: cudart-parakeet-bin-win-cuda-x64.zip | |
| if-no-files-found: error | |
| # --------------------------------------------------------------------------- | |
| # release: attach every bundle to the GitHub release for the tag. Creates a | |
| # draft release if none exists yet, so the usual create-release-with-notes | |
| # flow keeps working whether it happens before or after the tag push. | |
| # --------------------------------------------------------------------------- | |
| release: | |
| if: github.ref_type == 'tag' | |
| needs: [build-linux, build-macos, build-windows] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: dist | |
| merge-multiple: true | |
| - name: Upload assets to the release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| TAG: ${{ github.ref_name }} | |
| run: | | |
| if ! gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then | |
| gh release create "$TAG" --repo "$GITHUB_REPOSITORY" --draft --verify-tag \ | |
| --title "$TAG" --notes "Pre-built binaries for $TAG" | |
| fi | |
| gh release upload "$TAG" --repo "$GITHUB_REPOSITORY" --clobber dist/* |