diff --git a/build/header.rs b/build/header.rs index 39d03417..612b9702 100644 --- a/build/header.rs +++ b/build/header.rs @@ -1,3 +1,4 @@ +use std::env; use std::fs::File; use std::io::{BufRead, BufReader}; use std::path::{Path, PathBuf}; @@ -104,34 +105,81 @@ impl IncludePath for Path { /// /// https://wiki.debian.org/Multiarch/Implementation pub fn get_multiarch_header_dir() -> Option { - let try_multiarch = Command::new("dpkg-architecture") - .args(["--query", "DEB_TARGET_MULTIARCH"]) - .output() - .inspect_err(|e| eprintln!("=== Failed to get DEB_TARGET_MULTIARCH: {e}")) - .ok() - .or_else(|| { - Command::new("cc") - .arg("-print-multiarch") - .output() - .inspect_err(|e| eprintln!("=== Failed to get -print-multiarch: {e}")) - .ok() - }) - .and_then(|output| String::from_utf8(output.stdout).ok()) - .map_or_else( - || { - eprintln!("=== Failed to get DEB_TARGET_MULTIARCH, trying common multiarch paths"); - vec![ - "x86_64-linux-gnu".to_string(), - "aarch64-linux-gnu".to_string(), - "arm-linux-gnueabihf".to_string(), - ] - }, - |multiarch| vec![multiarch.trim().to_string()], - ); + // When cross-compiling, try to derive the target's multiarch from Cargo's target triple + let target_multiarch = if let (Ok(arch), Ok(os), Ok(env)) = ( + env::var("CARGO_CFG_TARGET_ARCH"), + env::var("CARGO_CFG_TARGET_OS"), + env::var("CARGO_CFG_TARGET_ENV"), + ) { + if os == "linux" && env == "gnu" { + // Map Rust target arch to Debian multiarch + let multiarch_arch = match arch.as_str() { + "x86_64" => Some("x86_64"), + "aarch64" => Some("aarch64"), + "arm" | "armv7" => Some("arm"), + "i686" => Some("i386"), + _ => None, + }; + multiarch_arch.map(|a| format!("{}-linux-gnu", a)) + } else if os == "linux" && env == "gnueabihf" { + // armv7-unknown-linux-gnueabihf -> arm-linux-gnueabihf + Some("arm-linux-gnueabihf".to_string()) + } else { + None + } + } else { + None + }; + + let try_multiarch = if let Some(ref target_arch) = target_multiarch { + eprintln!("=== Detected target multiarch from Cargo target: {target_arch}"); + vec![target_arch.clone()] + } else { + // Fallback to detecting the host's multiarch + Command::new("dpkg-architecture") + .args(["--query", "DEB_TARGET_MULTIARCH"]) + .output() + .inspect_err(|e| eprintln!("=== Failed to get DEB_TARGET_MULTIARCH: {e}")) + .ok() + .or_else(|| { + Command::new("cc") + .arg("-print-multiarch") + .output() + .inspect_err(|e| eprintln!("=== Failed to get -print-multiarch: {e}")) + .ok() + }) + .and_then(|output| String::from_utf8(output.stdout).ok()) + .map_or_else( + || { + eprintln!("=== Failed to get DEB_TARGET_MULTIARCH, trying common multiarch paths"); + vec![ + "x86_64-linux-gnu".to_string(), + "aarch64-linux-gnu".to_string(), + "arm-linux-gnueabihf".to_string(), + ] + }, + |multiarch| vec![multiarch.trim().to_string()], + ) + }; eprintln!("=== Trying multiarch paths: {try_multiarch:?}"); + // Get PKG_CONFIG_SYSROOT_DIR if set (used in cross-compilation scenarios) + let sysroot = env::var_os("PKG_CONFIG_SYSROOT_DIR").map(PathBuf::from); + if let Some(ref sysroot_path) = sysroot { + eprintln!("=== PKG_CONFIG_SYSROOT_DIR is set: {}", sysroot_path.display()); + } + for multiarch in try_multiarch { + // Try with sysroot first (for cross-compilation) + if let Some(ref sysroot_path) = sysroot { + let header_dir = sysroot_path.join(format!("usr/include/{multiarch}/opencv4")); + eprintln!("=== Checking sysroot multiarch path: {}", header_dir.display()); + if header_dir.is_dir() { + return Some(header_dir); + } + } + // Fallback to host system paths let header_dir = PathBuf::from(format!("/usr/include/{multiarch}/opencv4")); if header_dir.is_dir() { return Some(header_dir);