fn main() { // espeak-rs-sys builds espeak-ng from source but misses linking sonic // and the speechPlayer audio_object symbols. piper-rs only uses // espeak-ng for phonemization (never audio output), so stub implementations // satisfy the linker without providing real functionality. let out_dir = std::env::var("OUT_DIR").unwrap(); let stubs_c = format!("{}/tts_stubs.c", out_dir); let stubs_o = format!("{}/tts_stubs.o", out_dir); let stubs_a = format!("{}/libtts_stubs.a", out_dir); std::fs::write( &stubs_c, r#" #include typedef void* sonicStream; sonicStream sonicCreateStream(int sampleRate, int channels) { return NULL; } void sonicDestroyStream(sonicStream s) {} void sonicSetSpeed(sonicStream s, float speed) {} float sonicGetSpeed(sonicStream s) { return 1.0f; } void sonicWriteShortToStream(sonicStream s, const short *samples, int n) {} int sonicReadShortFromStream(sonicStream s, short *samples, int n) { return 0; } void sonicFlushStream(sonicStream s) {} typedef void* audio_object_t; int audio_object_open(audio_object_t o) { return 0; } int audio_object_write(audio_object_t o, const void *buf, size_t n) { return (int)n; } int audio_object_close(audio_object_t o) { return 0; } int audio_object_flush(audio_object_t o) { return 0; } int audio_object_drain(audio_object_t o) { return 0; } const char* audio_object_strerror(audio_object_t o, int err) { return "stub"; } audio_object_t create_audio_device_object(void* d, const char* device) { return NULL; } "#, ) .expect("write stubs"); // cc -c let status = std::process::Command::new("cc") .args(["-c", &stubs_c, "-o", &stubs_o]) .status() .expect("run cc"); assert!(status.success(), "cc -c failed"); // ar rcs let status = std::process::Command::new("ar") .args(["rcs", &stubs_a, &stubs_o]) .status() .expect("run ar"); assert!(status.success(), "ar rcs failed"); println!("cargo:rustc-link-search=native={}", out_dir); println!("cargo:rustc-link-lib=static=tts_stubs"); }