---
name: Build script (Windows tokenizers guard)
type: architecture-map-page
slice: 03-audio-transcription
last_verified: 2026/05/09
---

# Build script (Windows tokenizers guard)

> **Where you are:** [Architecture map](../README.md) → [Audio + Transcription](README.md) → Build script

**Plain English summary.** `lumotia-transcription/build.rs` reads `Cargo.lock` and refuses to compile on Windows if the `tokenizers` crate ever lands in the workspace dependency graph. Linking `whisper-rs-sys` and `tokenizers` together has been a repeated MSVC C-runtime conflict (Whispering v7.11.0 shipped a broken Windows build over exactly this). On non-Windows the check is a `cargo:warning`, not a fatal error, so the failure surfaces at CI build time rather than waiting for a Windows ship.

## At a glance

- Crate: `lumotia-transcription`
- Path: `crates/transcription/build.rs`
- LOC: 73
- External deps: stdlib only (`std::env`, `std::fs`).
- Internal callers: cargo invokes this automatically because `Cargo.toml` declares `build = "build.rs"`.

Public surface: none (build scripts have no callable surface).

## What's in here

```rust
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 { 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!(
            "lumotia-transcription: the `tokenizers` crate appears in Cargo.lock and this is a \
             Windows build. ..."
        );
    }

    println!(
        "cargo:warning=lumotia-transcription: `tokenizers` crate is in the dependency graph. \
         This build is non-Windows so the link will succeed, but Windows builds will panic ..."
    );
}
```

## Data flow

```
cargo invoke
  └─ build.rs
      ├─ rerun-if-changed=build.rs
      ├─ ancestors().find(Cargo.lock) → workspace root
      ├─ rerun-if-changed=Cargo.lock
      ├─ scan for `name = "tokenizers"`
      └─ if found:
            target_os == windows? → panic!("brief item #6")
            else → cargo:warning
```

## Watch-outs

- **`rerun-if-changed=Cargo.lock` is the trigger.** Adding tokenizers without changing this crate's source still re-runs the script the next build because the lockfile changed.
- **The string match is brittle on purpose.** Looking for the literal `name = "tokenizers"` line in `Cargo.lock` is what TOML pretty-prints. A future cargo version that emits the lockfile differently could miss this. Mitigation: keep the test simple and review on cargo upgrade.
- **The non-Windows path is a warning, not an error.** A CI matrix job on Linux will pass with a yellow message; Windows will fail at build. Fine for a desktop project that ships from Linux first; surprising if anyone ever assumes "Linux green = ready to ship".
- **Brief item #6 reference.** The panic message points at `docs/whisper-ecosystem/brief.md` item #6. Do not lose that pointer in any rewrite — the failure mode is non-obvious without the historical context.
- **`workspace_root` walk falls back gracefully.** If no `Cargo.lock` is found in any ancestor (first-ever cargo run), the script returns early. Subsequent builds will pick up the lock.
- **No way to override.** A maintainer who *wants* to ship `tokenizers` on Windows must delete this `build.rs`, or carry a sidecar process that links tokenizers in its own binary. There is no escape hatch env var.

## See also

- [Transcription whisper](transcription-whisper.md) — `whisper-rs-sys` is the link target this guard protects.
- [Cargo features](cargo-features.md) — same brief-item #6 family of decisions.
- `docs/whisper-ecosystem/brief.md` — the full incident background.
