From 749d66bb8c36f2dd79ad966cb58b8e9bb171ab70 Mon Sep 17 00:00:00 2001 From: Alexey Shabalin Date: Tue, 28 Jul 2026 13:40:49 +0300 Subject: [PATCH] rust: support linking a prebuilt install via TRANSCRIBE_DIR Setting TRANSCRIBE_DIR (OPENSSL_DIR-style) to an install prefix produced by cmake --install of a TRANSCRIBE_INSTALL=ON build skips the vendored source build entirely: the link line is emitted from that prefix's lib*/transcribe-link.json through the existing find_manifest / emit_link_lines path, so static and shared prefixes both work with no new link logic. Cargo features are inert on this path (the prebuilt already fixed its configuration; the manifest records it). Unset, the source build is byte-identical to before. --- bindings/rust/sys/README.md | 21 +++++++++++++++++++ bindings/rust/sys/build.rs | 41 +++++++++++++++++++++++++++++++------ docs/bindings.md | 5 ++++- 3 files changed, 60 insertions(+), 7 deletions(-) diff --git a/bindings/rust/sys/README.md b/bindings/rust/sys/README.md index ee516317..181fe6cf 100644 --- a/bindings/rust/sys/README.md +++ b/bindings/rust/sys/README.md @@ -61,6 +61,27 @@ $env:CARGO_TARGET_DIR = "C:\tc-target" cargo build --features vulkan ``` +## Linking a prebuilt install + +Set `TRANSCRIBE_DIR` (OPENSSL_DIR-style) to skip the source build and link an +existing install prefix instead: + +```bash +cmake -B build -DTRANSCRIBE_INSTALL=ON [-DTRANSCRIBE_BUILD_SHARED=ON ...] +cmake --build build +cmake --install build --prefix /opt/transcribe +TRANSCRIBE_DIR=/opt/transcribe cargo build +``` + +The prefix must contain the installed `lib*/transcribe-link.json` manifest; +the link line is reconstructed from it exactly as in a source build. Cargo +features (`shared`, `vulkan`, ...) do not apply on this path — the prebuilt +already fixed its configuration, and the manifest records it (including +static vs shared). For a shared-library prefix, running consumer binaries +may additionally need the prefix's lib dir on the loader path (e.g. +`LD_LIBRARY_PATH=$TRANSCRIBE_DIR/lib`): the rpath the build emits does not +propagate to downstream binaries. + ## Build-flag escape hatch The features above cover the common, tested configurations. Anything else CMake diff --git a/bindings/rust/sys/build.rs b/bindings/rust/sys/build.rs index 8611200d..1030f6e1 100644 --- a/bindings/rust/sys/build.rs +++ b/bindings/rust/sys/build.rs @@ -1,11 +1,17 @@ //! Build script for `transcribe-cpp-sys`. //! -//! Source build is the primary (and currently only) path: the `cmake` crate -//! drives the vendored C++ tree with `TRANSCRIBE_INSTALL=ON`, and the link -//! line is reconstructed from NOTHING but the installed -//! `lib/transcribe-link.json` manifest — the same artifact the `link_smoke` -//! CI lane compiles a toy C consumer against. No per-platform link lists are -//! hardcoded here (the whisper-rs drift class this avoids). +//! Source build is the primary path: the `cmake` crate drives the vendored +//! C++ tree with `TRANSCRIBE_INSTALL=ON`, and the link line is reconstructed +//! from NOTHING but the installed `lib/transcribe-link.json` manifest — the +//! same artifact the `link_smoke` CI lane compiles a toy C consumer against. +//! No per-platform link lists are hardcoded here (the whisper-rs drift class +//! this avoids). +//! +//! Prebuilt path: setting TRANSCRIBE_DIR (OPENSSL_DIR-style) to an install +//! prefix produced by `cmake --install` of a TRANSCRIBE_INSTALL=ON build +//! skips the source build entirely and links against that prefix's manifest +//! instead. Cargo features are inert there: the prebuilt already decided its +//! configuration (static/shared, backends), and the manifest records it. //! //! Cargo features map directly to CMake options: //! `shared` -> TRANSCRIBE_BUILD_SHARED=ON (default: static) @@ -83,6 +89,29 @@ fn main() { println!("cargo:rerun-if-changed={}", root.join(p).display()); } + // Prebuilt path: TRANSCRIBE_DIR points at an existing install prefix (a + // `cmake --install` tree from a TRANSCRIBE_INSTALL=ON configure). Skip the + // source build and emit the link line from that prefix's manifest; the + // manifest records the install's own posture (static/shared, backends), so + // the Cargo features below never apply here. + println!("cargo:rerun-if-env-changed=TRANSCRIBE_DIR"); + if let Some(dir) = env::var_os("TRANSCRIBE_DIR") { + let prefix = PathBuf::from(dir); + let manifest = find_manifest(&prefix).unwrap_or_else(|| { + panic!( + "TRANSCRIBE_DIR is set but no lib/transcribe-link.json (or lib64/) exists \ + under {}. It must point at an install prefix of this library, produced by \ + `cmake -B build -DTRANSCRIBE_INSTALL=ON && cmake --build build && \ + cmake --install build --prefix `. Unset TRANSCRIBE_DIR to build \ + the vendored sources instead.", + prefix.display() + ) + }); + println!("cargo:rerun-if-changed={}", manifest.display()); + emit_link_lines(&prefix, &manifest); + return; + } + // `dynamic-backends` (loadable backend modules) requires a shared library, // so it implies `shared`. The Cargo manifest already encodes that implication // (`dynamic-backends = ["shared"]`), but treat it as load-bearing here too. diff --git a/docs/bindings.md b/docs/bindings.md index 3c7b1176..00c2f513 100644 --- a/docs/bindings.md +++ b/docs/bindings.md @@ -39,7 +39,10 @@ binding's generated files: `GGML_BACKEND_DL` installs — `module_dir`, the directory to hand to `transcribe_init_backends()`. Proven per push by the link-smoke CI lane, which compiles a toy C consumer from nothing but this manifest in both - static and shared postures. + static and shared postures. The Rust `-sys` crate consumes it from two + sources: its own vendored source build (the default), or — with the + `TRANSCRIBE_DIR` env var pointing at an installed prefix — a prebuilt + tree, skipping the source build entirely. ## Result text pointers: copy at the FFI boundary