use std::env;
use std::path::PathBuf;
#[cfg(target_os = "linux")]
fn find_linux_cuda_root() -> Option<PathBuf> {
let mut candidates = vec![PathBuf::from("/usr/local/cuda")];
if let Ok(entries) = std::fs::read_dir("/usr/local") {
let mut versioned = entries
.flatten()
.map(|entry| entry.path())
.filter(|path| {
path.file_name()
.and_then(|name| name.to_str())
.is_some_and(|name| name.starts_with("cuda-"))
})
.collect::<Vec<_>>();
versioned.sort();
versioned.reverse();
candidates.extend(versioned);
}
candidates.into_iter().find(|root| root.exists())
}
#[cfg(not(target_os = "linux"))]
fn find_linux_cuda_root() -> Option<PathBuf> {
None
}
fn resolve_cuda_root() -> Option<PathBuf> {
if let Ok(cuda_path) = env::var("CUDA_PATH") {
return Some(PathBuf::from(cuda_path));
}
if let Some(root) = find_linux_cuda_root() {
println!(
"cargo:warning=CUDA_PATH is unset; using discovered CUDA root at {}",
root.display()
);
return Some(root);
}
None
}
fn resolve_nvcodec_dir(manifest_dir: &PathBuf) -> Option<PathBuf> {
let rave_root = manifest_dir.parent()?.parent()?;
let mut candidates = vec![
rave_root.join("third_party").join("nvcodec"),
];
if let Some(parent_third_party) = rave_root.parent() {
candidates.push(parent_third_party.join("nvcodec"));
}
candidates.into_iter().find(|dir| {
dir.exists() && dir.join("nvcuvid.lib").exists() && dir.join("nvencodeapi.lib").exists()
})
}
fn main() {
println!("cargo:rustc-check-cfg=cfg(rave_nvcodec_stub)");
println!("cargo:rerun-if-env-changed=CUDA_PATH");
println!("cargo:rerun-if-env-changed=FFMPEG_DIR");
println!("cargo:rerun-if-changed=build.rs");
let Some(cuda_root) = resolve_cuda_root() else {
if cfg!(target_os = "linux") {
println!(
"cargo:warning=CUDA toolkit not found (CUDA_PATH unset and /usr/local/cuda* missing); building rave-nvcodec in stub mode"
);
println!("cargo:rustc-cfg=rave_nvcodec_stub");
return;
}
panic!(
"CUDA_PATH env var must be set (e.g., C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v12.x)"
);
};
let cuda_lib_dir = if cfg!(target_os = "windows") {
cuda_root.join("lib").join("x64")
} else {
let wsl_style = cuda_root.join("targets").join("x86_64-linux").join("lib");
if wsl_style.exists() {
wsl_style
} else {
cuda_root.join("lib64")
}
};
if !cuda_lib_dir.exists() {
panic!(
"CRITICAL: CUDA library directory not found at {}",
cuda_lib_dir.display()
);
}
println!("cargo:rustc-link-search=native={}", cuda_lib_dir.display());
if cfg!(target_os = "linux") {
for extra in ["/usr/lib/wsl/lib", "/usr/local/lib/wsl-nvidia"] {
let p = PathBuf::from(extra);
if p.exists() {
println!("cargo:rustc-link-search=native={}", p.display());
}
}
}
let cuda_include_dir = cuda_root.join("include");
if !cuda_include_dir.exists() {
panic!(
"CRITICAL: CUDA include directory not found at {}",
cuda_include_dir.display()
);
}
println!("cargo:include={}", cuda_include_dir.display());
println!("cargo:rustc-link-lib=dylib=cuda");
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let nvcodec_dir = resolve_nvcodec_dir(&manifest_dir);
if cfg!(target_os = "windows") {
if let Some(nvcodec_dir) = nvcodec_dir {
println!("cargo:rustc-link-search=native={}", nvcodec_dir.display());
} else {
println!(
"cargo:warning=Video Codec SDK libs not found in expected nvcodec locations. Falling back to CUDA lib dir."
);
}
} else if let Some(nvcodec_dir) = nvcodec_dir {
println!("cargo:rustc-link-search=native={}", nvcodec_dir.display());
}
println!("cargo:rustc-link-lib=dylib=nvcuvid");
if cfg!(target_os = "windows") {
println!("cargo:rustc-link-lib=dylib=nvencodeapi");
} else {
println!("cargo:rustc-link-lib=dylib=nvidia-encode");
}
if let Ok(ffmpeg_dir) = env::var("FFMPEG_DIR") {
let ffmpeg_lib = PathBuf::from(&ffmpeg_dir).join("lib");
if ffmpeg_lib.exists() {
println!("cargo:rustc-link-search=native={}", ffmpeg_lib.display());
}
}
}