# transcribe library.
#
# Sources are listed explicitly. Per-family code lives under arch/<fam>/;
# shared scaffolding (loader, mel frontend, tokenizer, load-common,
# backend classification, flash-policy, ...) lives alongside the
# dispatcher at the top level of src/.
#
# Backend libraries (Metal, Vulkan, ...) are compiled into ggml by the
# top-level CMake via GGML_METAL / GGML_VULKAN. This target discovers
# them at runtime via the ggml device registry; no per-backend compile
# defs are needed on libtranscribe itself.
add_library(transcribe
transcribe.cpp
transcribe-loader.cpp
transcribe-arch.cpp
transcribe-meta.cpp
transcribe-kaldi-fbank.cpp
transcribe-mel.cpp
transcribe-model.cpp
transcribe-tokenizer.cpp
transcribe-unicode.cpp
transcribe-unicode-data.cpp
transcribe-debug.cpp
transcribe-flash-policy.cpp
transcribe-backend.cpp
transcribe-load-common.cpp
transcribe-weights-util.cpp
transcribe-bin-loader.cpp
transcribe-batch-util.cpp
conformer/conformer.cpp
sanm/sanm.cpp
causal_lm/causal_lm.cpp
granite_conformer/shaw_attn.cpp
arch/parakeet/model.cpp
arch/parakeet/capabilities.cpp
arch/parakeet/weights.cpp
arch/parakeet/encoder.cpp
arch/parakeet/decoder.cpp
arch/cohere/model.cpp
arch/cohere/capabilities.cpp
arch/cohere/weights.cpp
arch/cohere/encoder.cpp
arch/cohere/decoder.cpp
arch/canary/model.cpp
arch/canary/capabilities.cpp
arch/canary/weights.cpp
arch/canary/encoder.cpp
arch/canary/decoder.cpp
arch/qwen3_asr/model.cpp
arch/qwen3_asr/capabilities.cpp
arch/qwen3_asr/weights.cpp
arch/qwen3_asr/encoder.cpp
arch/qwen3_asr/decoder.cpp
arch/voxtral/model.cpp
arch/voxtral/capabilities.cpp
arch/voxtral/weights.cpp
arch/voxtral/encoder.cpp
arch/voxtral/decoder.cpp
arch/voxtral_realtime/model.cpp
arch/voxtral_realtime/capabilities.cpp
arch/voxtral_realtime/weights.cpp
arch/voxtral_realtime/encoder.cpp
arch/voxtral_realtime/decoder.cpp
arch/canary_qwen/model.cpp
arch/canary_qwen/capabilities.cpp
arch/canary_qwen/weights.cpp
arch/canary_qwen/encoder.cpp
arch/canary_qwen/decoder.cpp
arch/whisper/model.cpp
arch/whisper/capabilities.cpp
arch/whisper/weights.cpp
arch/whisper/encoder.cpp
arch/whisper/decoder.cpp
arch/whisper/bin_load.cpp
arch/whisper/public.cpp
arch/moonshine/model.cpp
arch/moonshine/capabilities.cpp
arch/moonshine/weights.cpp
arch/moonshine/encoder.cpp
arch/moonshine/decoder.cpp
arch/moonshine_streaming/model.cpp
arch/moonshine_streaming/capabilities.cpp
arch/moonshine_streaming/weights.cpp
arch/moonshine_streaming/encoder.cpp
arch/moonshine_streaming/decoder.cpp
arch/sensevoice/model.cpp
arch/sensevoice/capabilities.cpp
arch/sensevoice/weights.cpp
arch/sensevoice/encoder.cpp
arch/funasr_nano/model.cpp
arch/funasr_nano/capabilities.cpp
arch/funasr_nano/weights.cpp
arch/funasr_nano/encoder.cpp
arch/funasr_nano/decoder.cpp
arch/funasr_nano/adaptor.cpp
arch/gigaam/model.cpp
arch/gigaam/capabilities.cpp
arch/gigaam/weights.cpp
arch/gigaam/encoder.cpp
arch/gigaam/decoder.cpp
arch/gigaam/mel.cpp
arch/granite/model.cpp
arch/granite/capabilities.cpp
arch/granite/weights.cpp
arch/granite/encoder.cpp
arch/granite/projector.cpp
arch/granite/decoder.cpp
arch/granite_nar/model.cpp
arch/granite_nar/capabilities.cpp
arch/granite_nar/weights.cpp
arch/granite_nar/encoder.cpp
arch/granite_nar/projector.cpp
arch/granite_nar/decoder.cpp
arch/medasr/model.cpp
arch/medasr/capabilities.cpp
arch/medasr/weights.cpp
arch/medasr/encoder.cpp
# Vendored miniz (src/third_party/miniz, see its UPSTREAM file): the
# deflate compressor behind Whisper's compression-ratio heuristic. Compiled
# into libtranscribe itself so the static/shared artifact is self-contained
# (no external zlib to find, link, or stage). Trim flags + warning
# suppression are set below.
third_party/miniz/miniz.c
)
# The parakeet host decoder's matmul fallback (linear()) parallelizes its
# large output projection across rows. Compile ONLY this TU with OpenMP so
# the `#pragma omp parallel for` in linear() activates; libgomp is already
# linked transitively via ggml. Scoped to one TU and numerically identical
# (rows summed in the same order). The primary out_w path is the ggml graph
# in joint_step; this row-parallelism covers the host fallback and the
# remaining host-side matmuls.
#
# Gated on TRANSCRIBE_USE_OPENMP so official provider wheels (which pass it OFF,
# alongside GGML_OPENMP=OFF) do not link an OpenMP runtime into this TU. When
# off, the `#pragma omp` is an ignored no-op and linear() runs serially — the
# same path taken when OpenMP simply is not found.
if(TRANSCRIBE_USE_OPENMP)
find_package(OpenMP QUIET)
if(OpenMP_CXX_FOUND)
set_source_files_properties(arch/parakeet/decoder.cpp PROPERTIES
COMPILE_OPTIONS "${OpenMP_CXX_FLAGS}")
target_link_libraries(transcribe PRIVATE OpenMP::OpenMP_CXX)
endif()
endif()
target_include_directories(transcribe
PUBLIC
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/include>
PRIVATE
# Internal headers (transcribe-loader.h, transcribe-arch.h) live
# alongside the .cpp files. PRIVATE so they never escape into the
# public include path.
${CMAKE_CURRENT_SOURCE_DIR}
)
target_compile_definitions(transcribe
PRIVATE
TRANSCRIBE_BUILD
# Git commit stamped at configure time; surfaced by
# transcribe_version_commit(). Falls back to "unknown" in the source
# (see transcribe.cpp) when the build tree has no git metadata.
TRANSCRIBE_COMMIT="${TRANSCRIBE_BUILD_COMMIT}"
)
if(TRANSCRIBE_GGML_BACKEND_DL)
target_compile_definitions(transcribe PRIVATE TRANSCRIBE_GGML_BACKEND_DL)
if(CMAKE_DL_LIBS)
target_link_libraries(transcribe PRIVATE ${CMAKE_DL_LIBS})
endif()
endif()
# Static posture: tell transcribe.h to drop the Windows __declspec(dllimport/
# export) decoration. PUBLIC so it reaches both this archive's own TUs and any
# CMake consumer linking `transcribe` (C++ tests/examples) — without it a static
# MSVC consumer that includes transcribe.h links against __imp_* thunks the
# archive never provides (LNK2019). Bindgen/Python FFIs carry no __declspec and
# are unaffected. No-op off Windows/MSVC (the header guard is _WIN32-only).
if(NOT TRANSCRIBE_BUILD_SHARED)
target_compile_definitions(transcribe PUBLIC TRANSCRIBE_STATIC)
endif()
# ggml is the runtime substrate. Linked PRIVATE because the public header
# stays ggml-free (callers never include <ggml.h>).
target_link_libraries(transcribe
PRIVATE
ggml
)
# BLAS for the host decoder (cblas_sgemv in decoder.cpp). On Apple we
# link Accelerate directly; elsewhere we probe for OpenBLAS / MKL /
# BLIS via find_package(BLAS). When no BLAS is found the decoder falls
# back to a scalar loop (~14x slower but functionally correct).
# Apple Accelerate is a system framework (always present, nothing to vendor),
# so it stays on unconditionally even for wheels. The non-Apple system-BLAS
# probe is gated on TRANSCRIBE_USE_SYSTEM_BLAS: official provider wheels pass it
# OFF so wheel-repair tools never vendor OpenBLAS/MKL/BLIS where it would fight
# another BLAS/OpenMP runtime in the host process.
if(APPLE)
target_link_libraries(transcribe PRIVATE "-framework Accelerate")
target_compile_definitions(transcribe PRIVATE TRANSCRIBE_HAS_BLAS=1)
elseif(TRANSCRIBE_USE_SYSTEM_BLAS)
# BLA_VENDOR can be set by the user to prefer a specific BLAS
# (e.g. -DBLA_VENDOR=OpenBLAS). find_package probes the system.
find_package(BLAS QUIET)
if(BLAS_FOUND)
# find_package(BLAS) may find a Fortran-only BLAS (e.g. libblas3
# on Debian/Ubuntu) that lacks the cblas C wrappers. Verify that
# cblas.h exists before enabling; otherwise the build compiles
# cblas_sgemv calls but the linker can't resolve them.
include(CheckIncludeFile)
check_include_file(cblas.h HAVE_CBLAS_H)
if(HAVE_CBLAS_H)
target_link_libraries(transcribe PRIVATE ${BLAS_LIBRARIES})
target_compile_definitions(transcribe PRIVATE TRANSCRIBE_HAS_BLAS=1)
message(STATUS "transcribe: BLAS found — decoder will use cblas_sgemv")
else()
message(STATUS "transcribe: BLAS found but cblas.h missing — decoder uses scalar fallback (install libopenblas-dev)")
endif()
else()
message(STATUS "transcribe: no BLAS found — decoder uses scalar fallback")
endif()
else()
message(STATUS "transcribe: TRANSCRIBE_USE_SYSTEM_BLAS=OFF — decoder uses scalar fallback (official-wheel posture; no system BLAS vendored)")
endif()
set_target_properties(transcribe PROPERTIES
OUTPUT_NAME transcribe
POSITION_INDEPENDENT_CODE ON
# Versions the shared lib (libtranscribe.0.1.0.dylib + libtranscribe.0.dylib
# symlink). Ignored for the static archive. SOVERSION is the major only;
# pre-1.0 the real compatibility backstop is the binding's exact
# version/header-hash check, not the SONAME.
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
)
# miniz (vendored, src/third_party/miniz) provides the deflate compressor for
# Whisper's temperature-fallback compression_ratio metric (HF
# generation_whisper.py:_retrieve_compression_ratio uses
# len(token_bytes) / len(deflate(token_bytes)) to detect decoder token-id
# loops). Replaces system zlib so there is no find_package(ZLIB) / vcpkg
# dependency and nothing extra to stage into the install link manifest.
#
# Trim flags reach both miniz.c and its only consumer (arch/whisper/model.cpp),
# so they are PRIVATE on the target, not per-source:
# NO_INFLATE_APIS compress-only (this also makes miniz.h auto-define
# MINIZ_NO_ARCHIVE_APIS, so ZIP is off too — defining the
# latter here as well would clash with that and warn).
# NO_STDIO no file I/O NO_TIME no wall-clock
# NO_ZLIB_COMPATIBLE_NAMES don't export global compress/crc32/Z_OK/... that
# could collide with a real zlib downstream; call
# sites use the mz_-prefixed native API instead.
target_compile_definitions(transcribe PRIVATE
MINIZ_NO_INFLATE_APIS
MINIZ_NO_STDIO
MINIZ_NO_TIME
MINIZ_NO_ZLIB_COMPATIBLE_NAMES
)
# miniz is third-party C; its style trips our -Wshadow/-Wpedantic/-Wextra set.
# Silence warnings for this one translation unit only (-w / MSVC /w wins over
# the project flags transcribe_apply_warnings appends to the whole target).
if(MSVC)
set_source_files_properties(third_party/miniz/miniz.c PROPERTIES COMPILE_OPTIONS "/w")
else()
set_source_files_properties(third_party/miniz/miniz.c PROPERTIES COMPILE_OPTIONS "-w")
endif()
if(WIN32)
# Windows toolchains hide M_PI and friends behind _USE_MATH_DEFINES
# (used by the mel frontends and Whisper's bin loader). MSVC and MinGW
# both honor it — MinGW's strict-C++17 mode hides M_PI the same way.
target_compile_definitions(transcribe PRIVATE _USE_MATH_DEFINES)
endif()
transcribe_apply_warnings(transcribe)