use std::process::Command; use std::env; use std::fs; use std::path::Path; fn main() { // 检测当前是否在树莓派上 let is_raspberry_pi = detect_raspberry_pi(); // 自动启用GPIO功能(仅当是树莓派时) if is_raspberry_pi { println!("cargo:rustc-cfg=feature=\"gpio\""); println!("cargo:warning=Raspberry Pi detected, enabling gpio feature"); } else { println!("cargo:warning=Not running on Raspberry Pi, gpio feature NOT enabled"); } // 通过包含的 OpenCV 库检测版本 let opencv_version = detect_opencv_version(); println!("cargo:rustc-env=OPENCV_VERSION={}", opencv_version); // 解析版本 let version_parts: Vec<&str> = opencv_version.split('.').collect(); let major = version_parts.get(0).and_then(|s| s.parse::().ok()).unwrap_or(0); let minor = version_parts.get(1).and_then(|s| s.parse::().ok()).unwrap_or(0); // 如果版本 >= 4.11.0,启用特性 if major > 4 || (major == 4 && minor >= 11) { println!("cargo:rustc-cfg=feature=\"opencv-4-11-plus\""); println!("cargo:warning=Detected OpenCV {} >= 4.11.0, enabling opencv-4-11-plus feature", opencv_version); } else { println!("cargo:warning=Detected OpenCV {}, opencv-4-11-plus feature NOT enabled", opencv_version); } } fn detect_raspberry_pi() -> bool { // 方法1: 检查是否是Linux系统(必要条件) let is_linux = env::consts::OS == "linux"; if !is_linux { return false; } // 方法2: 检查/proc/cpuinfo是否包含Raspberry Pi的特征 if let Ok(cpuinfo) = fs::read_to_string("/proc/cpuinfo") { if cpuinfo.contains("Raspberry Pi") || cpuinfo.contains("BCM2708") || cpuinfo.contains("BCM2709") || cpuinfo.contains("BCM2710") || cpuinfo.contains("BCM2711") || cpuinfo.contains("BCM2835") || cpuinfo.contains("BCM2836") || cpuinfo.contains("BCM2837") || cpuinfo.contains("BCM2838") { return true; } } // 方法3: 检查树莓派特有的设备树模型文件 if let Ok(model) = fs::read_to_string("/sys/firmware/devicetree/base/model") { if model.contains("Raspberry Pi") { return true; } } // 方法4: 检查是否存在树莓派特有的库 let lib_check = Command::new("ldconfig") .args(["-p"]) .output() .ok() .and_then(|output| { if output.status.success() { let libraries = String::from_utf8_lossy(&output.stdout); if libraries.contains("librpgpio") || libraries.contains("libraspberrypi") { Some(true) } else { None } } else { None } }); if lib_check.is_some() { return true; } // 方法5: 检查树莓派特有的配置文件 if Path::new("/boot/config.txt").exists() || Path::new("/boot/firmware/config.txt").exists() { // 这个文件在大多数树莓派系统上存在 return true; } // 检查是否在CARGO_FEATURE_GPIO环境变量中强制启用 // 这允许用户手动启用GPIO功能(覆盖自动检测) if env::var("CARGO_FEATURE_GPIO").is_ok() { return true; } // 否则默认为false false } fn detect_opencv_version() -> String { // 方法 1: 尝试使用 pkg-config if let Some(version) = try_pkg_config() { return version; } // 方法 2: 尝试使用 opencv_version 命令 if let Some(version) = try_opencv_version_command() { return version; } // 方法 3: 尝试编译并运行一个小程序来检测版本 if let Some(version) = try_compile_check() { return version; } // 方法 4: 检查 OpenCV 头文件 if let Some(version) = try_header_check() { return version; } // 回退到默认版本 let default_version = "4.0.0".to_string(); println!("cargo:warning=Could not detect OpenCV version, assuming {}", default_version); default_version } fn try_pkg_config() -> Option { // 尝试使用 pkg-config 来获取 OpenCV 版本 let output = Command::new("pkg-config") .args(["--modversion", "opencv4"]) .output() .ok()?; if output.status.success() { let version = String::from_utf8(output.stdout).ok()?; let version = version.trim().to_string(); if !version.is_empty() { return Some(version); } } // 尝试 opencv 包(旧版本) let output = Command::new("pkg-config") .args(["--modversion", "opencv"]) .output() .ok()?; if output.status.success() { let version = String::from_utf8(output.stdout).ok()?; let version = version.trim().to_string(); if !version.is_empty() { return Some(version); } } None } fn try_opencv_version_command() -> Option { // 尝试运行 opencv_version 命令 let output = Command::new("opencv_version") .output() .ok()?; if output.status.success() { let version = String::from_utf8(output.stdout).ok()?; let version = version.trim().to_string(); if !version.is_empty() { return Some(version); } } None } fn try_compile_check() -> Option { // 创建一个临时目录 let out_dir = env::var("OUT_DIR").ok()?; let temp_file = format!("{}/version_check.cpp", out_dir); let temp_exe = format!("{}/version_check", out_dir); // 写入一个简单的 C++ 程序来打印 OpenCV 版本 std::fs::write(&temp_file, r#" #include #include int main() { std::cout << CV_VERSION << std::endl; return 0; } "#).ok()?; // 尝试编译 let status = Command::new("c++") .args([&temp_file, "-o", &temp_exe, "-lopencv_core"]) .status() .ok()?; if !status.success() { return None; } // 运行程序获取版本 let output = Command::new(&temp_exe) .output() .ok()?; if output.status.success() { let version = String::from_utf8(output.stdout).ok()?; let version = version.trim().to_string(); if !version.is_empty() { return Some(version); } } None } fn try_header_check() -> Option { // 尝试在常见位置查找 OpenCV 头文件 let paths = [ "/usr/include/opencv4/opencv2/core/version.hpp", "/usr/local/include/opencv4/opencv2/core/version.hpp", "/usr/include/opencv2/core/version.hpp", "/usr/local/include/opencv2/core/version.hpp", "/opt/homebrew/include/opencv4/opencv2/core/version.hpp", "/opt/homebrew/include/opencv2/core/version.hpp", ]; for path in paths.iter() { if let Ok(content) = std::fs::read_to_string(path) { // 查找版本定义 #define CV_VERSION_MAJOR 4 let mut major = None; let mut minor = None; let mut patch = None; for line in content.lines() { if let Some(value) = extract_define(line, "CV_VERSION_MAJOR") { major = Some(value); } else if let Some(value) = extract_define(line, "CV_VERSION_MINOR") { minor = Some(value); } else if let Some(value) = extract_define(line, "CV_VERSION_REVISION") { patch = Some(value); } if major.is_some() && minor.is_some() && patch.is_some() { return Some(format!("{}.{}.{}", major.unwrap(), minor.unwrap(), patch.unwrap())); } } } } None } fn extract_define(line: &str, define_name: &str) -> Option { let line = line.trim(); if line.starts_with("#define") && line.contains(define_name) { let parts: Vec<&str> = line.split_whitespace().collect(); if parts.len() >= 3 && parts[1] == define_name { return Some(parts[2].to_string()); } } None }