meteor_detect/build.rs
2025-04-05 23:37:03 +08:00

270 lines
8.3 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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::<u32>().ok()).unwrap_or(0);
let minor = version_parts.get(1).and_then(|s| s.parse::<u32>().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<String> {
// 尝试使用 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<String> {
// 尝试运行 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<String> {
// 创建一个临时目录
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 <opencv2/core.hpp>
#include <iostream>
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<String> {
// 尝试在常见位置查找 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<String> {
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
}