From ea93697686cdc7df5610f5fbbf4a93664a45f754 Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Mon, 27 Jul 2026 03:30:22 +0000 Subject: [PATCH] backend(audio-cpp): register the backend with CI and the gallery Adds the five Linux matrix entries (cpu amd64/arm64 sharing a tag-suffix so the manifest merge fires, cuda 12, cuda 13, vulkan), the path-filter case that keeps later PRs touching backend/cpp/audio-cpp/ from getting zero CI jobs, the bump-bot entry pointing at the AUDIO_CPP_VERSION pin in the backend Makefile, the gallery meta plus its -development variant and the image entries for every variant, and the Makefile docker-build wiring. The matrix entries carry base-image only, with no builder-base-image, unlike the llama-cpp and privacy-filter blocks they sit next to. The prebuilt quay.io/go-skynet/ci-cache:base-grpc-* images ship a from-source gRPC whose protobuf v26 depends on abseil, and this backend's sentencepiece is built with SPM_PROTOBUF_PROVIDER=package, so it sees real abseil's absl::lts_20240116:: internal alongside its own vendored plain absl::internal and every absl::internal:: reference becomes ambiguous. Building against base-grpc-amd64 fails at sentencepiece-static.dir/error.cc.o with "reference to 'internal' is ambiguous". Dockerfile.audio-cpp installs apt's gRPC/protobuf 3.21.12 itself, which is also the pair every unit and end-to-end run of this backend has been verified against, and the CUDA toolkit therefore has to come from base-image. No Darwin matrix entry and no metal gallery entries: the Metal build needs scripts/build/audio-cpp-darwin.sh, a backends/audio-cpp-darwin make target and a routing step in backend_build_darwin.yml, none of which exist yet, so an entry added now would be routed to build-darwin-go-backend and look for backend/go/audio-cpp/. The inferBackendPathDarwin case and the DARWIN_BESPOKE_BUILDERS membership are in place, inert, so that adding the entry later is a one-line change that cannot be claimed by the generic Go path. Assisted-by: Claude:claude-opus-5 [Claude Code] Signed-off-by: Ettore Di Giacinto --- .github/backend-matrix.yml | 94 +++++++++++++++++++++++++++++ .github/workflows/bump_deps.yaml | 4 ++ Makefile | 10 ++- backend/index.yaml | 78 ++++++++++++++++++++++++ scripts/lib/backend-filter.mjs | 25 +++++++- scripts/lib/backend-filter_test.mjs | 46 +++++++++++++- 6 files changed, 253 insertions(+), 4 deletions(-) diff --git a/.github/backend-matrix.yml b/.github/backend-matrix.yml index e72d26902..337c71ce2 100644 --- a/.github/backend-matrix.yml +++ b/.github/backend-matrix.yml @@ -3037,6 +3037,100 @@ include: dockerfile: "./backend/Dockerfile.privacy-filter" context: "./" ubuntu-version: '2404' + # audio-cpp: 0xShug0/audio.cpp, a multi-family ggml audio engine (TTS, ASR, + # VAD, diarization, source separation, music generation). + # + # These entries deliberately carry NO builder-base-image, unlike the + # privacy-filter and llama-cpp blocks above. The prebuilt + # quay.io/go-skynet/ci-cache:base-grpc-* images ship a from-source gRPC whose + # protobuf is v26, and protobuf has depended on abseil since v22. audio.cpp + # links sentencepiece with SPM_PROTOBUF_PROVIDER=package (needed to stop + # sentencepiece's vendored protobuf 3.14 from colliding with the 3.21 the + # generated backend.pb.cc is built against, which broke every nested-message + # parse), so sentencepiece then sees real abseil's + # `absl::lts_20240116::internal` alongside its own vendored plain + # `absl::internal` and every `absl::internal::` reference becomes ambiguous. + # Verified, not theorised: building against base-grpc-amd64 fails at + # sentencepiece-static.dir/error.cc.o with "reference to 'internal' is + # ambiguous". Dockerfile.audio-cpp therefore installs Ubuntu Noble's apt + # gRPC/protobuf 3.21.12 itself and has a single `builder` stage, so the + # BUILDER_BASE_IMAGE / BUILDER_TARGET / SKIP_DRIVERS build-args are never + # consumed. Same reason CUDA needs its toolkit in base-image rather than in a + # builder image: this is the ds4 shape, not the llama-cpp one. + # + # No ROCm entry: upstream has no HIP configuration. No CUDA arm64 or L4T + # entry: upstream documents and validates CUDA on x86 only. Darwin/Metal + # lands with scripts/build/audio-cpp-darwin.sh, which does not exist yet. + - build-type: '' + cuda-major-version: "" + cuda-minor-version: "" + platforms: 'linux/amd64' + platform-tag: 'amd64' + tag-latest: 'auto' + tag-suffix: '-cpu-audio-cpp' + runs-on: 'ubuntu-latest' + base-image: "ubuntu:24.04" + skip-drivers: 'true' + backend: "audio-cpp" + dockerfile: "./backend/Dockerfile.audio-cpp" + context: "./" + ubuntu-version: '2404' + - build-type: '' + cuda-major-version: "" + cuda-minor-version: "" + platforms: 'linux/arm64' + platform-tag: 'arm64' + tag-latest: 'auto' + tag-suffix: '-cpu-audio-cpp' + runs-on: 'ubuntu-24.04-arm' + base-image: "ubuntu:24.04" + skip-drivers: 'true' + backend: "audio-cpp" + dockerfile: "./backend/Dockerfile.audio-cpp" + context: "./" + ubuntu-version: '2404' + - build-type: 'cublas' + cuda-major-version: "12" + cuda-minor-version: "8" + platforms: 'linux/amd64' + tag-latest: 'auto' + tag-suffix: '-gpu-nvidia-cuda-12-audio-cpp' + runs-on: 'ubuntu-latest' + base-image: "nvidia/cuda:12.8.1-devel-ubuntu24.04" + skip-drivers: 'true' + backend: "audio-cpp" + dockerfile: "./backend/Dockerfile.audio-cpp" + context: "./" + ubuntu-version: '2404' + - build-type: 'cublas' + cuda-major-version: "13" + cuda-minor-version: "0" + platforms: 'linux/amd64' + tag-latest: 'auto' + tag-suffix: '-gpu-nvidia-cuda-13-audio-cpp' + runs-on: 'ubuntu-latest' + base-image: "nvidia/cuda:13.0.0-devel-ubuntu24.04" + skip-drivers: 'true' + backend: "audio-cpp" + dockerfile: "./backend/Dockerfile.audio-cpp" + context: "./" + ubuntu-version: '2404' + # Vulkan: ubuntu:24.04 plus apt's libvulkan-dev + glslc, installed by + # Dockerfile.audio-cpp when BUILD_TYPE=vulkan. arm64 vulkan is a one-line add + # once amd64 is proven in CI. + - build-type: 'vulkan' + cuda-major-version: "" + cuda-minor-version: "" + platforms: 'linux/amd64' + tag-latest: 'auto' + tag-suffix: '-gpu-vulkan-audio-cpp' + runs-on: 'ubuntu-latest' + base-image: "ubuntu:24.04" + skip-drivers: 'false' + backend: "audio-cpp" + dockerfile: "./backend/Dockerfile.audio-cpp" + context: "./" + ubuntu-version: '2404' - build-type: '' cuda-major-version: "" cuda-minor-version: "" diff --git a/.github/workflows/bump_deps.yaml b/.github/workflows/bump_deps.yaml index b5dc8c31d..b3f6b670a 100644 --- a/.github/workflows/bump_deps.yaml +++ b/.github/workflows/bump_deps.yaml @@ -30,6 +30,10 @@ jobs: variable: "DS4_VERSION" branch: "main" file: "backend/cpp/ds4/Makefile" + - repository: "0xShug0/audio.cpp" + variable: "AUDIO_CPP_VERSION" + branch: "main" + file: "backend/cpp/audio-cpp/Makefile" - repository: "meituan-longcat/LongCat-Video" variable: "LONGCAT_VIDEO_VERSION" branch: "main" diff --git a/Makefile b/Makefile index 6ac015876..5e8a948cd 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # Disable parallel execution for backend builds -.NOTPARALLEL: backends/diffusers backends/llama-cpp backends/turboquant backends/bonsai backends/outetts backends/piper backends/stablediffusion-ggml backends/whisper backends/crispasr backends/parakeet-cpp backends/moss-transcribe-cpp backends/faster-whisper backends/silero-vad backends/local-store backends/cloud-proxy backends/huggingface backends/rfdetr backends/rfdetr-cpp backends/insightface backends/speaker-recognition backends/kitten-tts backends/kokoro backends/chatterbox backends/llama-cpp-darwin backends/neutts build-darwin-python-backend build-darwin-go-backend backends/mlx backends/diffuser-darwin backends/mlx-vlm backends/mlx-audio backends/mlx-distributed backends/stablediffusion-ggml-darwin backends/vllm backends/vllm-omni backends/longcat-video backends/sglang backends/moonshine backends/pocket-tts backends/qwen-tts backends/faster-qwen3-tts backends/qwen-asr backends/nemo backends/voxcpm backends/whisperx backends/ace-step backends/acestep-cpp backends/fish-speech backends/voxtral backends/opus backends/trl backends/llama-cpp-quantization backends/kokoros backends/sam3-cpp backends/qwen3-tts-cpp backends/moss-tts-cpp backends/magpie-tts-cpp backends/omnivoice-cpp backends/vibevoice-cpp backends/localvqe backends/tinygrad backends/sherpa-onnx backends/ds4 backends/ds4-darwin backends/liquid-audio backends/supertonic backends/depth-anything-cpp backends/privacy-filter backends/privacy-filter-darwin +.NOTPARALLEL: backends/diffusers backends/llama-cpp backends/turboquant backends/bonsai backends/outetts backends/piper backends/stablediffusion-ggml backends/whisper backends/crispasr backends/parakeet-cpp backends/moss-transcribe-cpp backends/faster-whisper backends/silero-vad backends/local-store backends/cloud-proxy backends/huggingface backends/rfdetr backends/rfdetr-cpp backends/insightface backends/speaker-recognition backends/kitten-tts backends/kokoro backends/chatterbox backends/llama-cpp-darwin backends/neutts build-darwin-python-backend build-darwin-go-backend backends/mlx backends/diffuser-darwin backends/mlx-vlm backends/mlx-audio backends/mlx-distributed backends/stablediffusion-ggml-darwin backends/vllm backends/vllm-omni backends/longcat-video backends/sglang backends/moonshine backends/pocket-tts backends/qwen-tts backends/faster-qwen3-tts backends/qwen-asr backends/nemo backends/voxcpm backends/whisperx backends/ace-step backends/acestep-cpp backends/fish-speech backends/voxtral backends/opus backends/trl backends/llama-cpp-quantization backends/kokoros backends/sam3-cpp backends/qwen3-tts-cpp backends/moss-tts-cpp backends/magpie-tts-cpp backends/omnivoice-cpp backends/vibevoice-cpp backends/localvqe backends/tinygrad backends/sherpa-onnx backends/ds4 backends/ds4-darwin backends/liquid-audio backends/supertonic backends/depth-anything-cpp backends/privacy-filter backends/privacy-filter-darwin backends/audio-cpp GOCMD=go GOTEST=$(GOCMD) test @@ -1240,6 +1240,11 @@ BACKEND_DS4 = ds4|ds4|.|false|false # openai-privacy-filter PII/NER token classifier) — the TokenClassify RPC for # the PII redactor tier, on stock ggml with no llama.cpp carry-patches. BACKEND_PRIVACY_FILTER = privacy-filter|privacy-filter|.|false|false +# audio-cpp wraps 0xShug0/audio.cpp, a multi-family ggml audio inference engine +# (TTS, ASR, VAD, diarization, source separation, music generation). Builds +# against apt gRPC/protobuf rather than a prebuilt base-grpc image; the reason +# is on the audio-cpp block in .github/backend-matrix.yml. +BACKEND_AUDIO_CPP = audio-cpp|audio-cpp|.|false|false # Golang backends BACKEND_PIPER = piper|golang|.|false|true @@ -1340,6 +1345,7 @@ $(eval $(call generate-docker-build-target,$(BACKEND_TURBOQUANT))) $(eval $(call generate-docker-build-target,$(BACKEND_BONSAI))) $(eval $(call generate-docker-build-target,$(BACKEND_DS4))) $(eval $(call generate-docker-build-target,$(BACKEND_PRIVACY_FILTER))) +$(eval $(call generate-docker-build-target,$(BACKEND_AUDIO_CPP))) $(eval $(call generate-docker-build-target,$(BACKEND_PIPER))) $(eval $(call generate-docker-build-target,$(BACKEND_LOCAL_STORE))) $(eval $(call generate-docker-build-target,$(BACKEND_CLOUD_PROXY))) @@ -1405,7 +1411,7 @@ $(eval $(call generate-docker-build-target,$(BACKEND_SUPERTONIC))) docker-save-%: backend-images docker save local-ai-backend:$* -o backend-images/$*.tar -docker-build-backends: docker-build-llama-cpp docker-build-ik-llama-cpp docker-build-turboquant docker-build-bonsai docker-build-ds4 docker-build-rerankers docker-build-vllm docker-build-vllm-omni docker-build-longcat-video docker-build-sglang docker-build-transformers docker-build-outetts docker-build-diffusers docker-build-kokoro docker-build-faster-whisper docker-build-crispasr docker-build-coqui docker-build-chatterbox docker-build-vibevoice docker-build-liquid-audio docker-build-moonshine docker-build-pocket-tts docker-build-qwen-tts docker-build-fish-speech docker-build-faster-qwen3-tts docker-build-qwen-asr docker-build-nemo docker-build-voxcpm docker-build-whisperx docker-build-ace-step docker-build-acestep-cpp docker-build-voxtral docker-build-mlx-distributed docker-build-trl docker-build-llama-cpp-quantization docker-build-tinygrad docker-build-kokoros docker-build-sam3-cpp docker-build-rfdetr-cpp docker-build-qwen3-tts-cpp docker-build-moss-tts-cpp docker-build-magpie-tts-cpp docker-build-omnivoice-cpp docker-build-vibevoice-cpp docker-build-localvqe docker-build-insightface docker-build-speaker-recognition docker-build-sherpa-onnx docker-build-cloud-proxy docker-build-supertonic docker-build-depth-anything-cpp docker-build-moss-transcribe-cpp docker-build-privacy-filter +docker-build-backends: docker-build-llama-cpp docker-build-ik-llama-cpp docker-build-turboquant docker-build-bonsai docker-build-ds4 docker-build-rerankers docker-build-vllm docker-build-vllm-omni docker-build-longcat-video docker-build-sglang docker-build-transformers docker-build-outetts docker-build-diffusers docker-build-kokoro docker-build-faster-whisper docker-build-crispasr docker-build-coqui docker-build-chatterbox docker-build-vibevoice docker-build-liquid-audio docker-build-moonshine docker-build-pocket-tts docker-build-qwen-tts docker-build-fish-speech docker-build-faster-qwen3-tts docker-build-qwen-asr docker-build-nemo docker-build-voxcpm docker-build-whisperx docker-build-ace-step docker-build-acestep-cpp docker-build-voxtral docker-build-mlx-distributed docker-build-trl docker-build-llama-cpp-quantization docker-build-tinygrad docker-build-kokoros docker-build-sam3-cpp docker-build-rfdetr-cpp docker-build-qwen3-tts-cpp docker-build-moss-tts-cpp docker-build-magpie-tts-cpp docker-build-omnivoice-cpp docker-build-vibevoice-cpp docker-build-localvqe docker-build-insightface docker-build-speaker-recognition docker-build-sherpa-onnx docker-build-cloud-proxy docker-build-supertonic docker-build-depth-anything-cpp docker-build-moss-transcribe-cpp docker-build-privacy-filter docker-build-audio-cpp ######################################################## ### Mock Backend for E2E Tests diff --git a/backend/index.yaml b/backend/index.yaml index bf898e40e..5dac94d10 100644 --- a/backend/index.yaml +++ b/backend/index.yaml @@ -129,6 +129,35 @@ nvidia-l4t-cuda-13: "cuda13-nvidia-l4t-arm64-ds4" metal: "metal-ds4" metal-darwin-arm64: "metal-ds4" +- &audiocpp + name: "audio-cpp" + alias: "audio-cpp" + license: apache-2.0 + description: | + 0xShug0/audio.cpp - a ggml audio inference framework covering text to + speech, voice cloning, transcription, forced alignment, voice activity + detection, speaker diarization, source separation, voice conversion and + music generation, across 30+ model families. Consumes audio.cpp-native + GGUF packages from huggingface.co/audio-cpp/audio.cpp-gguf. + urls: + - https://github.com/0xShug0/audio.cpp + - https://huggingface.co/audio-cpp/audio.cpp-gguf + tags: + - TTS + - text-to-speech + - audio-transcription + - CPU + - CUDA + - Vulkan + # No metal/metal-darwin-arm64 key: there is no Darwin matrix entry for + # audio-cpp yet, and pointing a capability at a tag CI never builds hands the + # user a pull failure instead of the CPU fallback below. + capabilities: + default: "cpu-audio-cpp" + nvidia: "cuda12-audio-cpp" + nvidia-cuda-12: "cuda12-audio-cpp" + nvidia-cuda-13: "cuda13-audio-cpp" + vulkan: "vulkan-audio-cpp" - &whispercpp name: "whisper" alias: "whisper" @@ -1919,6 +1948,14 @@ nvidia-l4t-cuda-13: "cuda13-nvidia-l4t-arm64-ds4-development" metal: "metal-ds4-development" metal-darwin-arm64: "metal-ds4-development" +- !!merge <<: *audiocpp + name: "audio-cpp-development" + capabilities: + default: "cpu-audio-cpp-development" + nvidia: "cuda12-audio-cpp-development" + nvidia-cuda-12: "cuda12-audio-cpp-development" + nvidia-cuda-13: "cuda13-audio-cpp-development" + vulkan: "vulkan-audio-cpp-development" - !!merge <<: *stablediffusionggml name: "stablediffusion-ggml-development" capabilities: @@ -6573,3 +6610,44 @@ uri: "quay.io/go-skynet/local-ai-backends:master-metal-darwin-arm64-supertonic" mirrors: - localai/localai-backends:master-metal-darwin-arm64-supertonic +## audio-cpp +- !!merge <<: *audiocpp + name: "cpu-audio-cpp" + uri: "quay.io/go-skynet/local-ai-backends:latest-cpu-audio-cpp" + mirrors: + - localai/localai-backends:latest-cpu-audio-cpp +- !!merge <<: *audiocpp + name: "cpu-audio-cpp-development" + uri: "quay.io/go-skynet/local-ai-backends:master-cpu-audio-cpp" + mirrors: + - localai/localai-backends:master-cpu-audio-cpp +- !!merge <<: *audiocpp + name: "cuda12-audio-cpp" + uri: "quay.io/go-skynet/local-ai-backends:latest-gpu-nvidia-cuda-12-audio-cpp" + mirrors: + - localai/localai-backends:latest-gpu-nvidia-cuda-12-audio-cpp +- !!merge <<: *audiocpp + name: "cuda12-audio-cpp-development" + uri: "quay.io/go-skynet/local-ai-backends:master-gpu-nvidia-cuda-12-audio-cpp" + mirrors: + - localai/localai-backends:master-gpu-nvidia-cuda-12-audio-cpp +- !!merge <<: *audiocpp + name: "cuda13-audio-cpp" + uri: "quay.io/go-skynet/local-ai-backends:latest-gpu-nvidia-cuda-13-audio-cpp" + mirrors: + - localai/localai-backends:latest-gpu-nvidia-cuda-13-audio-cpp +- !!merge <<: *audiocpp + name: "cuda13-audio-cpp-development" + uri: "quay.io/go-skynet/local-ai-backends:master-gpu-nvidia-cuda-13-audio-cpp" + mirrors: + - localai/localai-backends:master-gpu-nvidia-cuda-13-audio-cpp +- !!merge <<: *audiocpp + name: "vulkan-audio-cpp" + uri: "quay.io/go-skynet/local-ai-backends:latest-gpu-vulkan-audio-cpp" + mirrors: + - localai/localai-backends:latest-gpu-vulkan-audio-cpp +- !!merge <<: *audiocpp + name: "vulkan-audio-cpp-development" + uri: "quay.io/go-skynet/local-ai-backends:master-gpu-vulkan-audio-cpp" + mirrors: + - localai/localai-backends:master-gpu-vulkan-audio-cpp diff --git a/scripts/lib/backend-filter.mjs b/scripts/lib/backend-filter.mjs index 50edd1726..4745b38b6 100644 --- a/scripts/lib/backend-filter.mjs +++ b/scripts/lib/backend-filter.mjs @@ -75,6 +75,9 @@ export function inferBackendPath(item) { if (item.dockerfile.endsWith("ds4")) { return `backend/cpp/ds4/`; } + if (item.dockerfile.endsWith("audio-cpp")) { + return `backend/cpp/audio-cpp/`; + } if (item.dockerfile.endsWith("llama-cpp")) { return `backend/cpp/llama-cpp/`; } @@ -98,6 +101,16 @@ export function inferBackendPathDarwin(item) { if (item.backend === "privacy-filter") { return `backend/cpp/privacy-filter/`; } + // audio-cpp is C++ too. There is no Darwin matrix entry for it yet: the + // Metal build needs scripts/build/audio-cpp-darwin.sh and a + // `backends/audio-cpp-darwin` make target, neither of which exists, so this + // case (and the DARWIN_BESPOKE_BUILDERS membership below) is inert today. It + // is here so that adding the entry is a one-line change that cannot + // accidentally route a C++ backend through the generic + // build-darwin-go-backend path, which would look for backend/go/audio-cpp/. + if (item.backend === "audio-cpp") { + return `backend/cpp/audio-cpp/`; + } if (!item.lang) { return `backend/python/${item.backend}/`; } @@ -139,7 +152,17 @@ const isDarwinPython = item => !item.lang; // backend_build_darwin.yml routes llama-cpp, ds4 and privacy-filter to their // own bespoke make targets; every other lang=go entry goes through // `make build-darwin-go-backend` -> scripts/build/golang-darwin.sh. -const DARWIN_BESPOKE_BUILDERS = new Set(["llama-cpp", "ds4", "privacy-filter"]); +// +// audio-cpp is listed ahead of its Darwin matrix entry (see +// inferBackendPathDarwin): it is a C++/ggml backend that will need the same +// bespoke treatment, and listing it here now means the entry, when it lands, +// cannot be silently claimed by the generic Go path. +const DARWIN_BESPOKE_BUILDERS = new Set([ + "llama-cpp", + "ds4", + "privacy-filter", + "audio-cpp", +]); const isDarwinGenericGo = item => !!item.lang && !DARWIN_BESPOKE_BUILDERS.has(item.backend); diff --git a/scripts/lib/backend-filter_test.mjs b/scripts/lib/backend-filter_test.mjs index 0d99e1e10..ac9b5ccc7 100644 --- a/scripts/lib/backend-filter_test.mjs +++ b/scripts/lib/backend-filter_test.mjs @@ -8,7 +8,7 @@ import test from "node:test"; import assert from "node:assert/strict"; -import { filterMatrix } from "./backend-filter.mjs"; +import { filterMatrix, inferBackendPathDarwin } from "./backend-filter.mjs"; // A representative slice of .github/backend-matrix.yml: one entry per build // path that the filter treats differently. Kept inline rather than parsed from @@ -51,6 +51,12 @@ const includes = [ "tag-suffix": "-turboquant", "base-image": "ubuntu:24.04", }, + { + backend: "audio-cpp", + dockerfile: "./backend/Dockerfile.audio-cpp", + "tag-suffix": "-cpu-audio-cpp", + "base-image": "ubuntu:24.04", + }, ]; const includesDarwin = [ @@ -194,6 +200,44 @@ test("turboquant still retriggers on llama-cpp source changes", () => { assert.deepEqual(names(filtered), ["llama-cpp", "turboquant"]); }); +// --------------------------------------------------------------------------- +// audio-cpp: a C++ backend whose Dockerfile suffix is its only Linux marker +// --------------------------------------------------------------------------- + +test("audio-cpp source changes rebuild audio-cpp and nothing else", () => { + // Without an inferBackendPath case, Dockerfile.audio-cpp resolves to null and + // filterMatrix drops every audio-cpp entry, so a PR touching only this + // backend would get zero CI jobs and look green for the wrong reason. + const { filtered, filteredDarwin, changedBackends } = run([ + "backend/cpp/audio-cpp/grpc-server.cpp", + ]); + + assert.deepEqual(names(filtered), ["audio-cpp"]); + assert.deepEqual(filteredDarwin, []); + assert.deepEqual([...changedBackends], ["audio-cpp"]); +}); + +test("Dockerfile.audio-cpp rebuilds only audio-cpp", () => { + const { filtered } = run(["backend/Dockerfile.audio-cpp"]); + + assert.deepEqual(names(filtered), ["audio-cpp"]); +}); + +test("audio-cpp resolves to its C++ sources on Darwin, not backend/go", () => { + // There is no Darwin matrix entry yet (the Metal build script does not + // exist), so this pins the function directly. lang=go on a Darwin entry only + // selects the runner and toolchain; routing audio-cpp by that field would + // point at backend/go/audio-cpp/, which does not exist. + assert.equal( + inferBackendPathDarwin({ + backend: "audio-cpp", + lang: "go", + "tag-suffix": "-metal-darwin-arm64-audio-cpp", + }), + "backend/cpp/audio-cpp/", + ); +}); + // --------------------------------------------------------------------------- // pkg/ subtrees linked into every Go backend binary // ---------------------------------------------------------------------------