From 1bb39699f5cf08515126cecedc73158c18d805dd Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 21 Apr 2026 11:08:37 +0000 Subject: [PATCH] feat(A.1 #6): fail Windows build when tokenizers enters the dep graph Adds a build.rs guard that parses Cargo.lock and panics on Windows if the tokenizers crate ever appears in the workspace dependency tree, mirroring the MSVC C-runtime conflict that broke Whispering v7.11.0 when they linked whisper-rs-sys + tokenizers in the same binary. On non-Windows hosts the guard downgrades to a cargo:warning so cross-compilation or CI from Linux surfaces the issue before a Windows build attempt actually panics. No tokenizers crate is in the tree today; the guard is preemptive. If we ever legitimately need HF tokenizers on Windows, the escape hatch is an out-of-process sidecar (separate CRT). Co-authored-by: jars --- crates/transcription/Cargo.toml | 1 + crates/transcription/build.rs | 73 +++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 crates/transcription/build.rs diff --git a/crates/transcription/Cargo.toml b/crates/transcription/Cargo.toml index be094d7..6500e48 100644 --- a/crates/transcription/Cargo.toml +++ b/crates/transcription/Cargo.toml @@ -3,6 +3,7 @@ name = "kon-transcription" version = "0.1.0" edition = "2021" description = "Speech-to-text engine wrappers, model management, and inference concurrency for Kon" +build = "build.rs" [dependencies] kon-core = { path = "../core" } diff --git a/crates/transcription/build.rs b/crates/transcription/build.rs new file mode 100644 index 0000000..5d0d9dd --- /dev/null +++ b/crates/transcription/build.rs @@ -0,0 +1,73 @@ +//! Build-time guard for item #6 of the Whisper ecosystem pass. +//! +//! On Windows, linking `whisper-rs-sys` (MSVC C++ runtime) and the +//! `tokenizers` crate (which pulls a different MSVC CRT via its +//! onnxruntime + Rust-side dependencies) in the same binary has been a +//! repeated failure mode — most recently Whispering v7.11.0 shipped a +//! broken Windows build over exactly this conflict. Reference: +//! https://github.com/EpicenterHQ/epicenter/releases/tag/v7.11.0 +//! +//! The easiest defence is to refuse to compile at all if any part of the +//! workspace ever pulls `tokenizers` into the dependency graph on a +//! Windows target. If we ever legitimately need it we can reintroduce +//! it via a sidecar (isolated process, separate CRT) rather than +//! linking it into `kon_lib`. +//! +//! The check is advisory on non-Windows targets — it still prints a +//! cargo:warning if `tokenizers` appears, so the Windows failure isn't +//! a surprise at CI time when we build cross-platform from Linux. + +use std::env; +use std::fs; +use std::path::PathBuf; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + + let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default(); + let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| ".".into())); + + // Walk up to workspace root: crates/transcription/ -> crates/ -> root + let workspace_root = manifest_dir + .ancestors() + .find(|p| p.join("Cargo.lock").exists()) + .map(PathBuf::from); + + let Some(root) = workspace_root else { + // No lockfile yet (e.g. first-ever cargo run). Nothing to check. + return; + }; + + let lock_path = root.join("Cargo.lock"); + println!("cargo:rerun-if-changed={}", lock_path.display()); + + let lock = match fs::read_to_string(&lock_path) { + Ok(s) => s, + Err(_) => return, + }; + + let has_tokenizers = lock + .lines() + .any(|line| matches!(line.trim(), "name = \"tokenizers\"")); + + if !has_tokenizers { + return; + } + + if target_os == "windows" { + panic!( + "kon-transcription: the `tokenizers` crate appears in Cargo.lock and this is a \ + Windows build. Linking `whisper-rs-sys` + `tokenizers` in the same binary has \ + been a persistent MSVC C-runtime conflict (see Whispering v7.11.0). Route any \ + tokenizer usage through an out-of-process sidecar instead, or gate it off for \ + Windows. Brief item #6." + ); + } + + println!( + "cargo:warning=kon-transcription: `tokenizers` crate is in the dependency graph. \ + This build is non-Windows so the link will succeed, but Windows builds will panic \ + at build time per docs/whisper-ecosystem/brief.md item #6. Isolate tokenizer usage \ + in a sidecar before a Windows ship." + ); +}