From 2e40d02a01067a05d7a7e5080c9d1bd3cd059581 Mon Sep 17 00:00:00 2001 From: Zbigniew Herman Date: Tue, 26 May 2026 10:34:00 +0200 Subject: [PATCH 1/5] whisper-cpp 1.8.5: migrate to ggml-speech + expose metal feature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two ticket deliverables combined into one consistent port rewrite: QVAC-18992 — Migrate to use ggml speech branch ---------------------------------------------- whisper-cpp now consumes the system-installed ggml provided by the `ggml-speech` port (same shape as parakeet-cpp and tts-cpp), instead of building the bundled `qvac-ext-lib-whisper.cpp/ggml/` subdirectory. Driven by -DWHISPER_USE_SYSTEM_GGML=ON; whisper.cpp's top-level CMake then calls `find_package(ggml CONFIG REQUIRED)` and aliases the `ggml::ggml` target to its internal `ggml` target. The bundled ggml source tree still exists in the upstream tarball but is no longer walked at configure time. All backend wiring is delegated to ggml-speech: - GGML_METAL / GGML_VULKAN / GGML_OPENCL / GGML_CUDA - GGML_BACKEND_DL=ON on Android (dynamic-backend mode) - GGML_CPU_ALL_VARIANTS=ON / GGML_CPU_REPACK=ON on Android (per-arch CPU MODULE .so files) - GGML_VULKAN_DISABLE_COOPMAT[2]=ON on Android (Adreno NDK) - spirv-headers `-isystem` shim for Vulkan - Android NDK Vulkan-Headers download - libqvac-speech-ggml-* output filename prefix Side effects: - The Vulkan-Headers download block is gone from this portfile; ggml-speech handles it. android-vulkan-version.cmake deleted. - The MSVC `/I` vs GCC/Clang `-isystem` spirv-headers shim is gone from this portfile; ggml-speech handles it. - The DL_BACKENDS install-tree fiddling is gone; the libqvac-speech-ggml-*.so files are installed by ggml-speech into ${VCPKG_INSTALLED_DIR}//lib/, which the transcription-whispercpp addon already picks up via get_target_property(... LOCATION) on the ggml:: imported targets. - whisper-cpp + parakeet-cpp + tts-cpp now share the same backend binary set on every triplet (was: whisper-cpp brought a separate libqvac-ggml-* set, parakeet/tts brought libqvac-speech-ggml-*). Single source of truth. QVAC-19236 — Expose backend selection as features ------------------------------------------------- Add the `metal` feature (was unconditionally ON for macOS / OFF for iOS in the portfile) so all 3 GPU backends are now declarative: whisper-cpp[metal] -> ggml-speech[metal] (osx | ios) whisper-cpp[vulkan] -> ggml-speech[vulkan] (linux | windows | android) whisper-cpp[opencl] -> ggml-speech[opencl] (android) Each whisper-cpp feature simply propagates into the matching ggml-speech feature (with the platform guard kept). Consumers can express the full GPU matrix declaratively in their own vcpkg.json (the transcription-whispercpp addon does exactly this in a companion PR — selecting [metal] for osx only, since iOS Metal still has a separate XPC/MTLCompiler runtime crash being investigated; the iOS binary stays on the CPU backend by simply not selecting [metal]). Whisper-cpp REF --------------- Bumped to v1.8.5 = 738d2e9e (tetherto/qvac-ext-lib-whisper.cpp@master), which is the merge of #33 ("update to v1.8.5 and sync vendored whisper.cpp + ggml to ggml-org upstream"). Pure upstream sync — no tetherto-specific behavior change at the consumer level beyond the ggml-source switch above. Result ------ portfile.cmake: 150 -> ~55 lines (much closer to parakeet-cpp / tts-cpp shape). Total diff: -174 / +56. Version bump: 1.8.4.3#1 -> 1.8.5#0 (treating the version-string change + the ggml-source switch as a fresh baseline rather than a port-revision bump). Co-authored-by: Cursor Co-authored-by: Cursor --- .../whisper-cpp/android-vulkan-version.cmake | 36 ----- ...talldirs-before-add-subdirectory-src.patch | 50 ++++++ ports/whisper-cpp/portfile.cmake | 147 +++--------------- ports/whisper-cpp/vcpkg.json | 40 +++-- versions/baseline.json | 4 +- versions/w-/whisper-cpp.json | 5 + 6 files changed, 108 insertions(+), 174 deletions(-) delete mode 100644 ports/whisper-cpp/android-vulkan-version.cmake create mode 100644 ports/whisper-cpp/patches/0001-move-gnuinstalldirs-before-add-subdirectory-src.patch diff --git a/ports/whisper-cpp/android-vulkan-version.cmake b/ports/whisper-cpp/android-vulkan-version.cmake deleted file mode 100644 index dbfd5428..00000000 --- a/ports/whisper-cpp/android-vulkan-version.cmake +++ /dev/null @@ -1,36 +0,0 @@ -# Function to detect Vulkan version from NDK vulkan_core.h -function(detect_ndk_vulkan_version) - string(TOLOWER "${CMAKE_HOST_SYSTEM_NAME}" host_system_name_lower) - - # CMAKE_HOST_SYSTEM_PROCESSOR is unavailable here. Use a glob pattern to complete the folder instead. - file(GLOB host_dirs LIST_DIRECTORIES true "$ENV{ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/${host_system_name_lower}-*") - if(host_dirs) - list(GET host_dirs 0 host_dir) - get_filename_component(host_arch "${host_dir}" NAME) - set(vulkan_core_h "$ENV{ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/${host_arch}/sysroot/usr/include/vulkan/vulkan_core.h") - else() - message(FATAL "Could not find NDK host directory for ${host_system_name_lower}") - endif() - - if(NOT vulkan_core_h) - message(FATAL "vulkan_core.h not found, using default version") - endif() - - file(READ "${vulkan_core_h}" header_content) - string(REGEX MATCH "VK_HEADER_VERSION ([0-9]+)" version_match "${header_content}") - if(version_match) - set(header_version_3 "${CMAKE_MATCH_1}") - else() - message(FATAL "Could not extract VK_HEADER_VERSION from vulkan_core.h, using default: ${vulkan_version}") - endif() - - # Extract major.minor version from VK_HEADER_VERSION_COMPLETE for download URL - string(REGEX MATCH "VK_HEADER_VERSION_COMPLETE VK_MAKE_API_VERSION\\(([0-9]+), ([0-9]+), ([0-9]+)" version_match "${header_content}") - if(version_match) - set(major "${CMAKE_MATCH_2}") - set(minor "${CMAKE_MATCH_3}") - set(vulkan_version "${major}.${minor}.${header_version_3}" PARENT_SCOPE) - else() - message(FATAL "Could not extract major.minor version from vulkan_core.h, using default: ${vulkan_version}") - endif() -endfunction() \ No newline at end of file diff --git a/ports/whisper-cpp/patches/0001-move-gnuinstalldirs-before-add-subdirectory-src.patch b/ports/whisper-cpp/patches/0001-move-gnuinstalldirs-before-add-subdirectory-src.patch new file mode 100644 index 00000000..2b28d46c --- /dev/null +++ b/ports/whisper-cpp/patches/0001-move-gnuinstalldirs-before-add-subdirectory-src.patch @@ -0,0 +1,50 @@ +From: qvac-registry-vcpkg +Subject: [PATCH] CMake: include(GNUInstallDirs) before add_subdirectory(src) + +src/CMakeLists.txt uses `${CMAKE_INSTALL_INCLUDEDIR}` in line +`$` to populate +the imported target's INTERFACE_INCLUDE_DIRECTORIES via the exported +`whisper-targets.cmake`. The variable is only defined after +`include(GNUInstallDirs)` runs, which is currently *after* +`add_subdirectory(src)` in top-level CMakeLists.txt. As a result the +generator-expression expands to just `/whisper`, and downstream +`find_package(whisper)` consumers that rely on the install-tree +(`WHISPER_USE_SYSTEM_GGML=ON` paths in vcpkg ports such as +parakeet-cpp / tts-cpp / transcription-whispercpp addons) fail to +configure with: + + CMake Error in CMakeLists.txt: + Imported target "whisper::whisper" includes non-existent path + "/whisper" + in its INTERFACE_INCLUDE_DIRECTORIES. + +Move the `include(GNUInstallDirs)` call above `add_subdirectory(src)` +so the INSTALL_INTERFACE generator-expression evaluates to the +intended `include/whisper`. Does not change build-tree behavior +(BUILD_INTERFACE path unaffected) and does not move any other rule +that consumes `${CMAKE_INSTALL_*}` (those all stay after src/). + +Filed for upstream submission as a follow-up PR. +--- + CMakeLists.txt | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/CMakeLists.txt b/CMakeLists.txt +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -167,13 +167,14 @@ + endif() + # ... otherwise assume ggml is added by a parent CMakeLists.txt + endif() ++include(GNUInstallDirs) ++ + add_subdirectory(src) + + # + # install + # + +-include(GNUInstallDirs) + include(CMakePackageConfigHelpers) + + set(WHISPER_BUILD_NUMBER ${BUILD_NUMBER}) diff --git a/ports/whisper-cpp/portfile.cmake b/ports/whisper-cpp/portfile.cmake index b9c12a94..0ea22406 100644 --- a/ports/whisper-cpp/portfile.cmake +++ b/ports/whisper-cpp/portfile.cmake @@ -1,138 +1,36 @@ vcpkg_from_github( OUT_SOURCE_PATH SOURCE_PATH REPO tetherto/qvac-ext-lib-whisper.cpp - REF f3102199642e78bb2beee6b9e9537604009148b9 - SHA512 64b102677abae7825985c946b1103cdaefc3f0d0d64f54dbdc5b38ee38a92efd553d33ed5a9f7aa5e509b0292478d8a93dbc8fd54dae7811b84a41d07f4b1c5c + REF 738d2e9ee486f336127fe89bb5d51f63a5fbd2fa + SHA512 a00c585700df9090b4e809c6676d367d8ccca26bff76827cf0d5d00498ddac2e972a2ead371a59e6c1f2626738c5f06c01db01e7d3b4411de0de9de42f084a64 HEAD_REF master + PATCHES + patches/0001-move-gnuinstalldirs-before-add-subdirectory-src.patch ) -if (VCPKG_TARGET_IS_ANDROID) - # NDK only comes with C headers. - # Make sure C++ header exists, it will be used by ggml tensor library. - # Need to determine installed vulkan version and download correct headers - include(${CMAKE_CURRENT_LIST_DIR}/android-vulkan-version.cmake) - detect_ndk_vulkan_version() - message(STATUS "Using Vulkan C++ wrappers from version: ${vulkan_version}") - file(DOWNLOAD - "https://github.com/KhronosGroup/Vulkan-Headers/archive/refs/tags/v${vulkan_version}.tar.gz" - "${SOURCE_PATH}/vulkan-sdk-${vulkan_version}.tar.gz" - TLS_VERIFY ON - ) - - file(ARCHIVE_EXTRACT - INPUT "${SOURCE_PATH}/vulkan-sdk-${vulkan_version}.tar.gz" - DESTINATION "${SOURCE_PATH}" - ) - - # Copy the Vulkan headers to where the build system expects them - # The build system looks for vulkan/vulkan.hpp with include path pointing to ggml/src/ - file(COPY "${SOURCE_PATH}/Vulkan-Headers-${vulkan_version}/include/" - DESTINATION "${SOURCE_PATH}/ggml/src/") - - # Clean up the temporary extracted directory - file(REMOVE_RECURSE "${SOURCE_PATH}/Vulkan-Headers-${vulkan_version}") -endif() - -set(PLATFORM_OPTIONS) - -if (VCPKG_TARGET_IS_OSX) - list(APPEND PLATFORM_OPTIONS -DGGML_METAL=ON) -elseif (VCPKG_TARGET_IS_IOS) - # Intentionally NOT -DGGML_METAL=ON. iOS bare-kit builds were hitting - # a separate Metal/Compiler XPC crash during transcribe() on physical - # iPhone (XPC_ERROR_CONNECTION_INTERRUPTED / MTLCompiler peer-unloaded) - # that is being investigated independently of the OutputCallBackJs - # teardown UAF. Force the flag OFF so it overrides any upstream default - # and stays explicit in the build log; iOS falls back to the CPU - # backend until the Metal-side issue is fixed. - list(APPEND PLATFORM_OPTIONS -DGGML_METAL=OFF) -elseif("vulkan" IN_LIST FEATURES) - list(APPEND PLATFORM_OPTIONS -DGGML_VULKAN=ON) -else() - list(APPEND PLATFORM_OPTIONS -DGGML_VULKAN=OFF) -endif() - -# Android: ship the same dynamic-backend + CPU-variant recipe llama-cpp -# already uses on this triplet. GGML_BACKEND_DL=ON makes ggml load the -# backend implementations as separate .so files at runtime (one per -# backend, picked by the device caps), so a single APK ships all the -# variants and the consumer's binary only statically links the dispatcher. -# GGML_CPU_ALL_VARIANTS + GGML_CPU_REPACK gives one tuned CPU .so per -# microarch (armv8.0/armv8.2-fp16/armv8.2-fp16+dotprod/armv8.7-i8mm), and -# COOPMAT[2] are disabled because the Vulkan validation layer's coopmat -# extensions are unstable on Adreno NDK headers. -# OpenCL is gated behind the `opencl` feature so non-Adreno Android -# consumers don't pull in an unused backend. -# Android dynamic-backend mode: per-microarch CPU + GPU backends ship as -# MODULE .so files dlopen'd at runtime, while the dispatcher -# (libwhisper.a, libggml.a, libggml-base.a) stays static — same shape -# as the speech-stack uses for parakeet-cpp/tts-cpp. -# -# The bundled ggml in this port's REF pin carries two commits from -# QVAC-18993 that make the combo above work end-to-end on Android: -# eb63b2b7 ggml : allow GGML_BACKEND_DL with a static core -# (removes the FATAL_ERROR + flips PIC/GGML_BUILD on) -# 3683de4b ggml-backend : android per-arch CPU variant dlopen fallback -# (lets ggml_backend_load_best resolve libggml-cpu-android_armv*_*.so -# via Android's in-APK linker when there's no on-disk lib dir) -# Both will land on tetherto/master via whisper-cpp PR #26 (QVAC-18993); -# after that ships + a v1.8.4.3 tag is published, the port can re-point -# to tetherto + drop the temporary Zbig9000 pin above. -if(VCPKG_TARGET_IS_ANDROID) - set(DL_BACKENDS ON) - list(APPEND PLATFORM_OPTIONS - -DGGML_BACKEND_DL=ON - -DGGML_CPU_ALL_VARIANTS=ON - -DGGML_CPU_REPACK=ON - -DGGML_VULKAN_DISABLE_COOPMAT=ON - -DGGML_VULKAN_DISABLE_COOPMAT2=ON) - if("opencl" IN_LIST FEATURES) - list(APPEND PLATFORM_OPTIONS -DGGML_OPENCL=ON) - endif() -else() - set(DL_BACKENDS OFF) -endif() - -# spirv-headers include-shim: upstream ggml uses spv::* enums -# unconditionally in ggml-vulkan.cpp, and ggml-vulkan's CMakeLists.txt -# does not call find_package(SpirvHeaders), so the vcpkg-installed -# include prefix is not visible to it by default. -# -# Append to VCPKG_C_FLAGS / VCPKG_CXX_FLAGS (same shape as qvac-fabric's -# portfile, ref qvac-registry-vcpkg commit db03cfc8) so the include path -# is merged with the triplet-supplied flags (-fPIC, -stdlib=libc++ on -# Linux, etc.). The previous form passed -DCMAKE_CXX_FLAGS=... via -# vcpkg_cmake_configure OPTIONS, which is a CMake cache-variable -# override that clobbered the triplet flags wholesale and produced -# libstdc++/libc++ ABI mismatches at link time for consumers that -# target libc++. +# whisper-cpp consumes the system-installed ggml provided by the `ggml-speech` +# port (same shape as the `parakeet-cpp` and `tts-cpp` ports). Backend +# selection, Android dynamic-backend packaging, Vulkan-Headers download, +# spirv-headers include shim, per-arch CPU variants and the +# libqvac-speech-ggml-* filename prefix are all owned by `ggml-speech`; this +# port only carries whisper-specific build options and links against the +# installed ggml via `find_package(ggml)` (gated by WHISPER_USE_SYSTEM_GGML). # -# MSVC's cl.exe does not understand `-isystem` (it treats the flag as a -# positional source file argument and tries to compile the include -# path), so use `/I` there and the GCC/Clang `-isystem` form elsewhere. -if("vulkan" IN_LIST FEATURES) - if(VCPKG_TARGET_IS_WINDOWS AND NOT VCPKG_TARGET_IS_MINGW) - string(APPEND VCPKG_C_FLAGS " /I${CURRENT_INSTALLED_DIR}/include") - string(APPEND VCPKG_CXX_FLAGS " /I${CURRENT_INSTALLED_DIR}/include") - else() - string(APPEND VCPKG_C_FLAGS " -isystem ${CURRENT_INSTALLED_DIR}/include") - string(APPEND VCPKG_CXX_FLAGS " -isystem ${CURRENT_INSTALLED_DIR}/include") - endif() -endif() +# Per-feature wiring lives in vcpkg.json: +# whisper-cpp[metal] -> ggml-speech[metal] (osx | ios) +# whisper-cpp[vulkan] -> ggml-speech[vulkan] (linux | windows | android) +# whisper-cpp[opencl] -> ggml-speech[opencl] (android) +# so consumers express the full GPU matrix declaratively. vcpkg_cmake_configure( SOURCE_PATH "${SOURCE_PATH}" DISABLE_PARALLEL_CONFIGURE OPTIONS - -DGGML_CCACHE=OFF - -DGGML_OPENMP=OFF - -DGGML_NATIVE=OFF + -DWHISPER_USE_SYSTEM_GGML=ON -DWHISPER_BUILD_TESTS=OFF -DWHISPER_BUILD_EXAMPLES=OFF -DWHISPER_BUILD_SERVER=OFF -DBUILD_SHARED_LIBS=OFF - -DGGML_BUILD_NUMBER=1 - ${PLATFORM_OPTIONS} ) vcpkg_cmake_install() @@ -149,13 +47,12 @@ vcpkg_copy_pdbs() file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include") file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/share") -if (NOT DL_BACKENDS AND VCPKG_LIBRARY_LINKAGE MATCHES "static") - # On dynamic-backend Android the ggml backend .so files live in bin/ - # alongside the static dispatcher; wiping bin/ here would silently - # ship a runtime that loads no backends. Only wipe for true - # static-only triplets. +# whisper-cpp itself produces no shared libraries when BUILD_SHARED_LIBS=OFF. +# The ggml backend .so files (Android dynamic-backend mode) are installed by +# the ggml-speech port into ${VCPKG_INSTALLED_DIR}//lib/, not by us. +if (VCPKG_LIBRARY_LINKAGE MATCHES "static") file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/bin") file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/bin") endif() -vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE") \ No newline at end of file +vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/LICENSE") diff --git a/ports/whisper-cpp/vcpkg.json b/ports/whisper-cpp/vcpkg.json index 6da0b0e0..6a58bca4 100644 --- a/ports/whisper-cpp/vcpkg.json +++ b/ports/whisper-cpp/vcpkg.json @@ -1,11 +1,16 @@ { "name": "whisper-cpp", - "version": "1.8.4.3", - "port-version": 1, + "version": "1.8.5", + "port-version": 0, "description": "High-performance inference of OpenAI's Whisper automatic speech recognition (ASR) model", "homepage": "https://github.com/tetherto/qvac-ext-lib-whisper.cpp", "license": "MIT", "dependencies": [ + { + "name": "ggml-speech", + "default-features": false, + "version>=": "2026-04-09#4" + }, { "name": "vcpkg-cmake", "host": true @@ -16,25 +21,38 @@ } ], "features": { + "metal": { + "description": "Enable Metal GPU acceleration (Apple-only; targets macOS and iOS via the ggml-metal backend in ggml-speech). No extra package dependencies — Metal.framework is provided by the platform SDK.", + "supports": "osx | ios", + "dependencies": [ + { + "name": "ggml-speech", + "default-features": false, + "features": [ "metal" ], + "platform": "osx | ios" + } + ] + }, "opencl": { - "description": "Enable OpenCL GPU acceleration (Android-only; targets Adreno via the ggml-opencl backend).", + "description": "Enable OpenCL GPU acceleration (Android-only; targets Adreno via the ggml-opencl backend in ggml-speech).", + "supports": "android", "dependencies": [ { - "name": "opencl", + "name": "ggml-speech", + "default-features": false, + "features": [ "opencl" ], "platform": "android" } ] }, "vulkan": { - "description": "Enable Vulkan GPU acceleration", + "description": "Enable Vulkan GPU acceleration (Linux/Windows/Android; macOS/iOS use the metal feature instead).", + "supports": "!osx & !ios", "dependencies": [ { - "name": "spirv-headers", - "platform": "!osx & !ios", - "version>=": "1.4.341.0" - }, - { - "name": "vulkan", + "name": "ggml-speech", + "default-features": false, + "features": [ "vulkan" ], "platform": "!osx & !ios" } ] diff --git a/versions/baseline.json b/versions/baseline.json index b5a616ce..9a1febaa 100644 --- a/versions/baseline.json +++ b/versions/baseline.json @@ -121,8 +121,8 @@ "port-version": 0 }, "whisper-cpp": { - "baseline": "1.8.4.3", - "port-version": 1 + "baseline": "1.8.5", + "port-version": 0 }, "xnnpack": { "baseline": "onnxruntime", diff --git a/versions/w-/whisper-cpp.json b/versions/w-/whisper-cpp.json index 7e2603ba..5af4994a 100644 --- a/versions/w-/whisper-cpp.json +++ b/versions/w-/whisper-cpp.json @@ -1,5 +1,10 @@ { "versions": [ + { + "git-tree": "12ad35577dacb47f26c8476f140f975d032b433b", + "version": "1.8.5", + "port-version": 0 + }, { "git-tree": "da082dc2ca2d01f5915431d1321924cea221b350", "version": "1.8.4.3", From dff317c8e68e2fa052119eb90e4b3dba01a47f37 Mon Sep 17 00:00:00 2001 From: Zbigniew Herman Date: Wed, 27 May 2026 14:21:25 +0200 Subject: [PATCH 2/5] ggml-speech: bump to 2026-05-27#0 (PR #13 merged on speech) Picks up tetherto/qvac-ext-ggml@speech HEAD c9126afc (merge commit of qvac-ext-ggml PR #13: "QVAC-18992: merge ggml-org @ 19eac6f0 (v0.10.2) into speech"). The merge brings in: c9126afc Merge pull request #13 from Zbig9000/QVAC-18992-merge-ggml-from-whisper-cpp e31785e4 fix(metal): restore lost 'typedef struct {' before ggml_metal_kargs_supertonic_depthwise_1d (caught by qvac CI Apple prebuild matrix via an overlay on tetherto/qvac#2270) d39c0d29 metal: stride-aware src indexing in kernel_pad_f32 / kernel_pad_reflect_1d_f32 (fixes Mac M2 PAD test failure) 166c4e12 Merge ggml-org @ 19eac6f0 into speech (sync to v0.10.2) PR #13 also brings in PR #11 (GustavoA1604 Android per-arch CPU dlopen fallback), which was already wired through port-version 4 via the GGML_CPU_ALL_VARIANTS=ON + GGML_CPU_REPACK=ON shape introduced in port-version 3 -- no port-side change needed for that. Build changes vs port-version 4: * Add patches/0001-ggml-vulkan-find-spirv-headers.patch wiring SPIRV-Headers into ggml-vulkan. The v0.10.2 sync added an unconditional #include in src/ggml-vulkan/ggml-vulkan.cpp, but the upstream ggml-vulkan CMakeLists.txt never finds spirv-headers nor wires its include dir into the ggml-vulkan target. Patch finds the package and links it when available, gated on the "vulkan" feature. * Add spirv-headers as a dependency of the "vulkan" feature so the patched find_package(SPIRV-Headers QUIET) actually resolves to a vcpkg-installed package. Validated end-to-end through tetherto/qvac#2270's full CI matrix: - 9/9 prebuild triplets (linux-x64/arm64, win32-x64, darwin-arm64/x64, android-arm64, ios-arm64 + 2 simulators) - 107/107 C++ addon tests on linux-x64 - 5/5 platform integration test suites - iOS + Android E2E on AWS Device Farm Co-authored-by: Cursor --- .../0001-ggml-vulkan-find-spirv-headers.patch | 24 ++++++++++ ports/ggml-speech/portfile.cmake | 45 +++++++++++++------ ports/ggml-speech/vcpkg.json | 11 +++-- versions/baseline.json | 4 +- versions/g-/ggml-speech.json | 5 +++ 5 files changed, 69 insertions(+), 20 deletions(-) create mode 100644 ports/ggml-speech/patches/0001-ggml-vulkan-find-spirv-headers.patch diff --git a/ports/ggml-speech/patches/0001-ggml-vulkan-find-spirv-headers.patch b/ports/ggml-speech/patches/0001-ggml-vulkan-find-spirv-headers.patch new file mode 100644 index 00000000..7906d497 --- /dev/null +++ b/ports/ggml-speech/patches/0001-ggml-vulkan-find-spirv-headers.patch @@ -0,0 +1,24 @@ +diff --git a/src/ggml-vulkan/CMakeLists.txt b/src/ggml-vulkan/CMakeLists.txt +index 715a263a..3d92ac5d 100644 +--- a/src/ggml-vulkan/CMakeLists.txt ++++ b/src/ggml-vulkan/CMakeLists.txt +@@ -7,6 +7,7 @@ if (POLICY CMP0147) + endif() + + find_package(Vulkan COMPONENTS glslc REQUIRED) ++find_package(SPIRV-Headers QUIET) + + if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + # Parallel build object files +@@ -87,6 +88,11 @@ if (Vulkan_FOUND) + ) + + target_link_libraries(ggml-vulkan PRIVATE Vulkan::Vulkan) ++ ++ if (TARGET SPIRV-Headers::SPIRV-Headers) ++ target_link_libraries(ggml-vulkan PRIVATE SPIRV-Headers::SPIRV-Headers) ++ endif() ++ + target_include_directories(ggml-vulkan PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + + # Workaround to the "can't dereference invalidated vector iterator" bug in clang-cl debug build diff --git a/ports/ggml-speech/portfile.cmake b/ports/ggml-speech/portfile.cmake index c34efbe1..a9d97fda 100644 --- a/ports/ggml-speech/portfile.cmake +++ b/ports/ggml-speech/portfile.cmake @@ -1,22 +1,25 @@ -# ggml-speech: tetherto/qvac-ext-ggml@speech, including the iOS Metal -# NULL-safety hardening from -# https://github.com/tetherto/qvac-ext-ggml/pull/10 (PR-10's 3 commits -# f21ff9a0 + b7dc01c7 + 0f54d9f7) now merged into the speech branch -# as PR-10 merge 08d39f0c (`Merge pull request #10 from -# ishanvohra2/fix/metal-ios-null-propagation`). +# ggml-speech: tetherto/qvac-ext-ggml@speech HEAD c9126afc, the merge +# commit of PR #13 ("QVAC-18992: merge ggml-org @ 19eac6f0 (v0.10.2) +# into speech"). The merge brings in: # -# The Android backend stack still uses the GGML_CPU_ALL_VARIANTS=ON -# + GGML_CPU_REPACK=ON shape introduced in port-version 3 (per-arch -# CPU dlopen variants on top of the Vulkan / OpenCL MODULE .so files); -# only the Apple Metal path changes versus port-version 3, courtesy -# of PR-10's NULL-safety hardening on `ggml_metal_device_init` / -# `ggml_metal_buffer_init` etc. +# c9126afc Merge pull request #13 from Zbig9000/QVAC-18992-merge-ggml-from-whisper-cpp +# e31785e4 fix(metal): restore lost 'typedef struct {' before +# ggml_metal_kargs_supertonic_depthwise_1d (the ggml-org +# v0.10.2 sync in 166c4e12 dropped the typedef header; +# caught by qvac CI Apple prebuild matrix via an overlay +# on tetherto/qvac#2270) +# d39c0d29 metal: stride-aware src indexing in kernel_pad_f32 / +# kernel_pad_reflect_1d_f32 (fixes Mac M2 PAD test failure) +# 166c4e12 Merge ggml-org @ 19eac6f0 into speech (sync to v0.10.2) +# +# The Android CPU dlopen fallback (GustavoA1604 #11) carried over from +# port-version 4 (08d39f0c) is unchanged. vcpkg_from_github( OUT_SOURCE_PATH SOURCE_PATH REPO tetherto/qvac-ext-ggml - REF 08d39f0c - SHA512 0e681f60ba0ad49b1cebda914ee065c0b29f301617970b968054089830029153f1be28012dfe2ced9c1014fe8605647ca68208544e9564b5d5f1c68dfd1e82e9 + REF c9126afc96145cc93892029b953f7de5abc09728 + SHA512 e24b4bfb48a2be01d4703badee0aecb8772c5e35e76348e9de2ea693288bd23d84d1fb7c626dd63736f76bfcc442433522621998977661cf602ec90289f596a0 HEAD_REF speech ) @@ -105,6 +108,20 @@ if(VCPKG_TARGET_IS_ANDROID) ) endif() +# PR #13 (v0.10.2 sync) introduces an unconditional +# `#include ` in src/ggml-vulkan/ggml-vulkan.cpp, +# but the upstream ggml-vulkan CMakeLists.txt never finds spirv-headers nor +# wires its include dir into the ggml-vulkan target. Apply a small patch +# so it does (and depend on spirv-headers in vcpkg.json's vulkan feature). +# TODO: push the equivalent fix upstream and drop this patch. +if("vulkan" IN_LIST FEATURES) + vcpkg_apply_patches( + SOURCE_PATH "${SOURCE_PATH}" + PATCHES + "${CMAKE_CURRENT_LIST_DIR}/patches/0001-ggml-vulkan-find-spirv-headers.patch" + ) +endif() + vcpkg_cmake_configure( SOURCE_PATH "${SOURCE_PATH}" OPTIONS diff --git a/ports/ggml-speech/vcpkg.json b/ports/ggml-speech/vcpkg.json index a031ec48..b80bdcbc 100644 --- a/ports/ggml-speech/vcpkg.json +++ b/ports/ggml-speech/vcpkg.json @@ -1,8 +1,8 @@ { "name": "ggml-speech", - "version-date": "2026-04-09", - "port-version": 4, - "description": "Speech-stack flavour of ggml from tetherto/qvac-ext-ggml@speech, including the iOS Metal NULL-safety hardening from PR #10. Library filenames are prefixed libqvac-speech-ggml-* so they coexist with libqvac-ggml-* (fabric/llm) and libqvac-diffusion-ggml-* on the same Android device. Mutually exclusive with the regular ggml port in the same triplet -- pick one per build.", + "version-date": "2026-05-27", + "port-version": 0, + "description": "Speech-stack flavour of ggml from tetherto/qvac-ext-ggml@speech, including the ggml-org v0.10.2 sync (PR #13), the iOS Metal NULL-safety hardening from PR #10, GustavoA1604's Android per-arch CPU dlopen fallback (PR #11), and the Mac M2 PAD test fix. Library filenames are prefixed libqvac-speech-ggml-* so they coexist with libqvac-ggml-* (fabric/llm) and libqvac-diffusion-ggml-* on the same Android device. Mutually exclusive with the regular ggml port in the same triplet -- pick one per build.", "homepage": "https://github.com/tetherto/qvac-ext-ggml/tree/speech", "license": "MIT", "dependencies": [ @@ -46,7 +46,10 @@ ] }, "vulkan": { - "description": "Enable Vulkan GPU backend" + "description": "Enable Vulkan GPU backend", + "dependencies": [ + "spirv-headers" + ] } } } diff --git a/versions/baseline.json b/versions/baseline.json index 9a1febaa..e9558e5d 100644 --- a/versions/baseline.json +++ b/versions/baseline.json @@ -21,8 +21,8 @@ "port-version": 8 }, "ggml-speech": { - "baseline": "2026-04-09", - "port-version": 4 + "baseline": "2026-05-27", + "port-version": 0 }, "intgemm": { "baseline": "1.0.0", diff --git a/versions/g-/ggml-speech.json b/versions/g-/ggml-speech.json index 8a962a5d..0330c50e 100644 --- a/versions/g-/ggml-speech.json +++ b/versions/g-/ggml-speech.json @@ -1,5 +1,10 @@ { "versions": [ + { + "git-tree": "7026556d3d35cfc30ee9d27998520f9d00eedc70", + "version-date": "2026-05-27", + "port-version": 0 + }, { "git-tree": "b9dab610a65a30450a9779870879a864efe3308a", "version-date": "2026-04-09", From 2af24340076c9b99f5f0307e044171732e944b40 Mon Sep 17 00:00:00 2001 From: Zbigniew Herman Date: Wed, 27 May 2026 15:15:13 +0200 Subject: [PATCH 3/5] tts-cpp + parakeet-cpp: bump port-version against ggml-speech 2026-05-27 ggml-speech bumped to 2026-05-27#0 in this PR will auto-apply via baseline to every consumer port that has version>= on it. tts-cpp and parakeet-cpp must declare they have been validated against the new ggml-speech to keep the registry self-consistent. tts-cpp: 2026-05-20 -> 2026-05-20#1 - version>=ggml-speech bumped to 2026-05-27 (was 2026-04-09#4) parakeet-cpp: 2026-05-20#2 -> 2026-05-20#3 - version>=ggml-speech bumped to 2026-05-27 (was 2026-04-09#3) Local validation (x64-linux, vulkan feature) against this registry tree: - tts-ggml addon: vcpkg resolves clean, build links clean, 35 C++ unit tests pass, 61 JS unit tests pass - transcription-parakeet addon: vcpkg resolves clean, build links clean, 32 C++ unit tests pass, 17 JS unit tests pass Co-authored-by: Cursor --- ports/parakeet-cpp/vcpkg.json | 4 ++-- ports/tts-cpp/vcpkg.json | 4 ++-- versions/baseline.json | 4 ++-- versions/p-/parakeet-cpp.json | 5 +++++ versions/t-/tts-cpp.json | 5 +++++ 5 files changed, 16 insertions(+), 6 deletions(-) diff --git a/ports/parakeet-cpp/vcpkg.json b/ports/parakeet-cpp/vcpkg.json index 07b64b12..569a4ec9 100644 --- a/ports/parakeet-cpp/vcpkg.json +++ b/ports/parakeet-cpp/vcpkg.json @@ -1,14 +1,14 @@ { "name": "parakeet-cpp", "version-date": "2026-05-26", - "port-version": 0, + "port-version": 1, "description": "Parakeet (NVIDIA FastConformer ASR + Sortformer diarization) inference in pure C++/ggml. Ships CTC, TDT, EOU and Sortformer engines under one Engine umbrella, plus the cross-engine StreamEvent API (VadStateChanged / EndOfTurn). Sourced from tetherto/qvac-ext-lib-whisper.cpp's parakeet-cpp/ subfolder; consumes the ggml-speech port.", "homepage": "https://github.com/tetherto/qvac-ext-lib-whisper.cpp/tree/master/parakeet-cpp", "license": "MIT", "dependencies": [ { "name": "ggml-speech", - "version>=": "2026-04-09#3" + "version>=": "2026-05-27" }, { "name": "vcpkg-cmake", diff --git a/ports/tts-cpp/vcpkg.json b/ports/tts-cpp/vcpkg.json index a86d8848..a11e195d 100644 --- a/ports/tts-cpp/vcpkg.json +++ b/ports/tts-cpp/vcpkg.json @@ -1,14 +1,14 @@ { "name": "tts-cpp", "version-date": "2026-05-20", - "port-version": 1, + "port-version": 2, "description": "Text-to-speech inference in pure C++/ggml. Ships Resemble Chatterbox (Turbo + Multilingual variants) and Supertonic engines under a unified Engine API. Sourced from tetherto/qvac-ext-lib-whisper.cpp's tts-cpp/ subfolder (including the Android dynamic backend selection landed in PR #29); consumes the ggml-speech port.", "homepage": "https://github.com/tetherto/qvac-ext-lib-whisper.cpp/tree/master/tts-cpp", "license": "MIT", "dependencies": [ { "name": "ggml-speech", - "version>=": "2026-04-09#4" + "version>=": "2026-05-27" }, { "name": "vcpkg-cmake", diff --git a/versions/baseline.json b/versions/baseline.json index e9558e5d..51529d62 100644 --- a/versions/baseline.json +++ b/versions/baseline.json @@ -54,7 +54,7 @@ }, "parakeet-cpp": { "baseline": "2026-05-26", - "port-version": 0 + "port-version": 1 }, "protobuf": { "baseline": "onnxruntime", @@ -106,7 +106,7 @@ }, "tts-cpp": { "baseline": "2026-05-20", - "port-version": 1 + "port-version": 2 }, "vcpkg-cmake": { "baseline": "2024-04-23", diff --git a/versions/p-/parakeet-cpp.json b/versions/p-/parakeet-cpp.json index 417453e7..c5fad88a 100644 --- a/versions/p-/parakeet-cpp.json +++ b/versions/p-/parakeet-cpp.json @@ -1,5 +1,10 @@ { "versions": [ + { + "git-tree": "774279adb2469e31d61ceee8551203c191b37ff1", + "version-date": "2026-05-26", + "port-version": 1 + }, { "git-tree": "30bed642026cdc31de09b0834c274335905bef1f", "version-date": "2026-05-26", diff --git a/versions/t-/tts-cpp.json b/versions/t-/tts-cpp.json index c92fe663..daab2f2f 100644 --- a/versions/t-/tts-cpp.json +++ b/versions/t-/tts-cpp.json @@ -1,5 +1,10 @@ { "versions": [ + { + "git-tree": "c298d02d3aafbc2cbd9b510b4d03da3a30262ad6", + "version-date": "2026-05-20", + "port-version": 2 + }, { "git-tree": "110697fcafeb5d1175f9b014df8aed4b69936f71", "version-date": "2026-05-20", From 74ca045f11393f6aa9e6a055d196f48768e12c71 Mon Sep 17 00:00:00 2001 From: Zbigniew Herman Date: Wed, 27 May 2026 15:27:42 +0200 Subject: [PATCH 4/5] whisper-cpp: bump version>=ggml-speech to 2026-05-27 The version>= constraint on ggml-speech was still 2026-04-09#4 (carried over from before the system-ggml migration). whisper-cpp@1.8.5 only works against the new ggml-speech@2026-05-27 (v0.10.2 vendored sources, new symbol set, spirv-headers Vulkan wiring), so the constraint must reflect that minimum. In practice the resolver always picked 2026-05-27 because that is the baseline value, so this is metadata-only and not a behavior change for either the addon CI run or the local file:// validation. It is the correct declaration so a future consumer with a stale baseline cannot combine whisper-cpp@1.8.5 with the old ggml-speech. Co-authored-by: Cursor --- ports/whisper-cpp/vcpkg.json | 2 +- versions/w-/whisper-cpp.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ports/whisper-cpp/vcpkg.json b/ports/whisper-cpp/vcpkg.json index 6a58bca4..9acb98af 100644 --- a/ports/whisper-cpp/vcpkg.json +++ b/ports/whisper-cpp/vcpkg.json @@ -9,7 +9,7 @@ { "name": "ggml-speech", "default-features": false, - "version>=": "2026-04-09#4" + "version>=": "2026-05-27" }, { "name": "vcpkg-cmake", diff --git a/versions/w-/whisper-cpp.json b/versions/w-/whisper-cpp.json index 5af4994a..948bdd84 100644 --- a/versions/w-/whisper-cpp.json +++ b/versions/w-/whisper-cpp.json @@ -1,7 +1,7 @@ { "versions": [ { - "git-tree": "12ad35577dacb47f26c8476f140f975d032b433b", + "git-tree": "d18888f5989f0e1a1fa2725b81ae6058d9576baf", "version": "1.8.5", "port-version": 0 }, From eb698a66d85679c361c7bfed43615708a66b9991 Mon Sep 17 00:00:00 2001 From: Zbigniew Herman Date: Wed, 27 May 2026 15:44:18 +0200 Subject: [PATCH 5/5] ggml-speech: pin spirv-headers vulkan dep to version>=1.4.341.0 Without a version>= constraint, the resolved spirv-headers version depends entirely on the consumer's microsoft/vcpkg baseline. Pin to 1.4.341.0 to match the convention already used by qvac-fabric (the other speech-stack port that depends on spirv-headers via vulkan), keep both ports resolvable from the same SPIRV-Headers version when they coexist in a consumer manifest, and ensure consumers with an older baseline still pick up a known-good SPIRV-Headers. Local validation on x64-linux: vcpkg upgrades spirv-headers from the addon's baseline 1.4.304.1 to the required 1.4.341.0 cleanly, the ggml-vulkan patch builds against the new headers, the full transcription-whispercpp addon builds + 107/107 cpp tests + 30/30 unit tests pass. Co-authored-by: Cursor --- ports/ggml-speech/vcpkg.json | 5 ++++- versions/g-/ggml-speech.json | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ports/ggml-speech/vcpkg.json b/ports/ggml-speech/vcpkg.json index b80bdcbc..19544792 100644 --- a/ports/ggml-speech/vcpkg.json +++ b/ports/ggml-speech/vcpkg.json @@ -48,7 +48,10 @@ "vulkan": { "description": "Enable Vulkan GPU backend", "dependencies": [ - "spirv-headers" + { + "name": "spirv-headers", + "version>=": "1.4.341.0" + } ] } } diff --git a/versions/g-/ggml-speech.json b/versions/g-/ggml-speech.json index 0330c50e..6ede4042 100644 --- a/versions/g-/ggml-speech.json +++ b/versions/g-/ggml-speech.json @@ -1,7 +1,7 @@ { "versions": [ { - "git-tree": "7026556d3d35cfc30ee9d27998520f9d00eedc70", + "git-tree": "c201f7740ecf959862a91f3ae3bc5b718d98388f", "version-date": "2026-05-27", "port-version": 0 },