use std::env;
#[allow(clippy::too_many_lines)] fn main() {
println!("cargo:rerun-if-changed=build.rs");
let has_linalg = env::var("CARGO_FEATURE_LINALG").is_ok();
let has_linalg_system = env::var("CARGO_FEATURE_LINALG_SYSTEM").is_ok();
let has_blas_optimized = env::var("CARGO_FEATURE_BLAS_OPTIMIZED").is_ok();
if has_linalg || has_linalg_system || has_blas_optimized {
if cfg!(target_os = "windows") {
println!(
"cargo:warning=Windows LAPACK/BLAS support limited - use --no-default-features"
);
} else {
if cfg!(target_os = "linux") {
println!("cargo:rustc-link-search=native=/usr/lib");
println!("cargo:rustc-link-search=native=/usr/local/lib");
if cfg!(target_arch = "x86_64") {
println!("cargo:rustc-link-search=native=/usr/lib/x86_64-linux-gnu");
println!(
"cargo:rustc-link-search=native=/usr/lib/x86_64-linux-gnu/openblas-pthread"
);
println!("cargo:rustc-link-search=native=/usr/lib/x86_64-linux-gnu/blas");
println!("cargo:rustc-link-search=native=/usr/lib/x86_64-linux-gnu/lapack");
println!("cargo:rustc-link-search=native=/usr/lib64");
println!("cargo:rustc-link-search=native=/lib/x86_64-linux-gnu");
} else if cfg!(target_arch = "aarch64") {
println!("cargo:rustc-link-search=native=/usr/lib/aarch64-linux-gnu");
println!("cargo:rustc-link-search=native=/usr/lib/aarch64-linux-gnu/openblas-pthread");
println!("cargo:rustc-link-search=native=/usr/lib/aarch64-linux-gnu/blas");
println!("cargo:rustc-link-search=native=/usr/lib/aarch64-linux-gnu/lapack");
println!("cargo:rustc-link-search=native=/usr/lib64");
println!("cargo:rustc-link-search=native=/lib/aarch64-linux-gnu");
}
}
if cfg!(target_os = "linux") {
let _blas_lib = env::var("BLAS_LIB")
.or_else(|_| env::var("RUSTORCH_BLAS_LIB"))
.unwrap_or_else(|_| "openblas".to_string());
let _lapack_lib = env::var("LAPACK_LIB")
.or_else(|_| env::var("RUSTORCH_LAPACK_LIB"))
.unwrap_or_else(|_| "openblas".to_string());
let arch_paths = if cfg!(target_arch = "x86_64") {
vec!["/usr/lib/x86_64-linux-gnu", "/usr/lib64"]
} else if cfg!(target_arch = "aarch64") {
vec!["/usr/lib/aarch64-linux-gnu", "/usr/lib64"]
} else {
vec!["/usr/lib"]
};
let mut openblas_available = false;
let mut separate_blas_available = false;
let mut separate_lapack_available = false;
for path in &arch_paths {
if std::path::Path::new(&format!("{path}/libopenblas.so.0")).exists()
|| std::path::Path::new(&format!("{path}/libopenblas.so")).exists()
|| std::path::Path::new(&format!("{path}/libopenblas.a")).exists()
{
openblas_available = true;
}
if std::path::Path::new(&format!("{path}/libblas.so")).exists()
|| std::path::Path::new(&format!("{path}/libblas.a")).exists()
{
separate_blas_available = true;
}
if std::path::Path::new(&format!("{path}/liblapack.so")).exists()
|| std::path::Path::new(&format!("{path}/liblapack.a")).exists()
{
separate_lapack_available = true;
}
}
for common_path in &["/usr/lib", "/usr/local/lib", "/opt/local/lib"] {
if !openblas_available
&& (std::path::Path::new(&format!("{common_path}/libopenblas.so")).exists()
|| std::path::Path::new(&format!("{common_path}/libopenblas.a"))
.exists())
{
openblas_available = true;
}
if !separate_blas_available
&& (std::path::Path::new(&format!("{common_path}/libblas.so")).exists()
|| std::path::Path::new(&format!("{common_path}/libblas.a")).exists())
{
separate_blas_available = true;
}
if !separate_lapack_available
&& (std::path::Path::new(&format!("{common_path}/liblapack.so")).exists()
|| std::path::Path::new(&format!("{common_path}/liblapack.a")).exists())
{
separate_lapack_available = true;
}
}
if openblas_available {
println!("cargo:rustc-link-lib=openblas");
if separate_lapack_available {
println!("cargo:rustc-link-lib=lapack");
}
} else if separate_blas_available && separate_lapack_available {
println!("cargo:rustc-link-lib=lapack");
println!("cargo:rustc-link-lib=blas");
} else {
println!("cargo:rustc-link-lib=lapack");
println!("cargo:rustc-link-lib=blas");
}
} else if cfg!(target_os = "macos") {
let blas_lib = env::var("BLAS_LIB")
.or_else(|_| env::var("RUSTORCH_BLAS_LIB"))
.unwrap_or_else(|_| "framework".to_string());
let _lapack_lib = env::var("LAPACK_LIB")
.or_else(|_| env::var("RUSTORCH_LAPACK_LIB"))
.unwrap_or_else(|_| "framework".to_string());
let mut openblas_found = false;
if std::path::Path::new("/opt/homebrew/lib/libopenblas.dylib").exists() {
println!("cargo:rustc-link-search=native=/opt/homebrew/lib");
openblas_found = true;
}
if std::path::Path::new("/usr/local/lib/libopenblas.dylib").exists() {
println!("cargo:rustc-link-search=native=/usr/local/lib");
openblas_found = true;
}
if blas_lib == "openblas" && openblas_found {
println!("cargo:rustc-link-lib=openblas");
} else {
println!("cargo:rustc-link-lib=framework=Accelerate");
}
} else {
let common_paths = ["/usr/lib", "/usr/local/lib", "/opt/local/lib"];
let mut openblas_found = false;
let mut separate_libs_found = false;
for path in &common_paths {
if !openblas_found
&& (std::path::Path::new(&format!("{path}/libopenblas.so")).exists()
|| std::path::Path::new(&format!("{path}/libopenblas.a")).exists())
{
openblas_found = true;
}
if !separate_libs_found
&& std::path::Path::new(&format!("{path}/liblapack.so")).exists()
&& std::path::Path::new(&format!("{path}/libblas.so")).exists()
{
separate_libs_found = true;
}
}
if openblas_found {
println!("cargo:rustc-link-lib=openblas");
} else if separate_libs_found {
println!("cargo:rustc-link-lib=lapack");
println!("cargo:rustc-link-lib=blas");
} else {
println!("cargo:rustc-link-lib=lapack");
println!("cargo:rustc-link-lib=blas");
}
}
}
if cfg!(unix) {
if let Ok(lib_dir) = env::var("RUSTORCH_LIB_DIR") {
println!("cargo:rustc-link-search=native={lib_dir}");
}
}
}
#[cfg(feature = "cuda")]
{
let cuda_paths = [
"/usr/local/cuda/lib64",
"/opt/cuda/lib64",
"/usr/lib/x86_64-linux-gnu",
"/usr/local/cuda/lib",
];
let mut cuda_found = false;
let cuda_root = env::var("CUDA_ROOT")
.or_else(|_| env::var("CUDA_PATH"))
.or_else(|_| env::var("CUDA_HOME"));
if let Ok(cuda_root) = cuda_root {
let lib64_path = format!("{}/lib64", cuda_root);
let lib_path = format!("{}/lib", cuda_root);
if std::path::Path::new(&lib64_path).exists()
|| std::path::Path::new(&lib_path).exists()
{
println!("cargo:rustc-link-search=native={cuda_root}/lib64");
println!("cargo:rustc-link-search=native={cuda_root}/lib");
cuda_found = true;
}
} else {
for path in &cuda_paths {
if std::path::Path::new(path).exists() {
println!("cargo:rustc-link-search=native={}", path);
cuda_found = true;
break;
}
}
}
if cuda_found {
println!("cargo:rustc-link-lib=cudart");
println!("cargo:rustc-link-lib=cublas");
println!("cargo:rustc-link-lib=curand");
println!("cargo:rustc-link-lib=cusparse");
} else {
println!("cargo:warning=CUDA feature enabled but CUDA libraries not found. CUDA functionality will be disabled at runtime.");
}
}
#[cfg(feature = "opencl")]
{
let opencl_available = if cfg!(target_os = "macos") {
std::path::Path::new("/System/Library/Frameworks/OpenCL.framework").exists()
} else if cfg!(target_os = "linux") {
[
"/usr/lib/x86_64-linux-gnu/libOpenCL.so",
"/usr/lib/libOpenCL.so",
"/usr/local/lib/libOpenCL.so",
"/usr/lib64/libOpenCL.so",
]
.iter()
.any(|path| std::path::Path::new(path).exists())
} else {
false
};
if opencl_available {
if cfg!(target_os = "macos") {
println!("cargo:rustc-link-lib=framework=OpenCL");
} else {
println!("cargo:rustc-link-lib=OpenCL");
}
} else {
println!("cargo:warning=OpenCL feature enabled but OpenCL libraries not found. OpenCL functionality will be disabled at runtime.");
}
}
#[cfg(all(feature = "metal", target_os = "macos"))]
{
println!("cargo:rustc-link-lib=framework=Metal");
println!("cargo:rustc-link-lib=framework=MetalPerformanceShaders");
}
}