meteor_detect/build.rs

286 lines
9.0 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() {
// 检测当前是否在树莓派或其他支持GPIO的Linux平台上
let supports_gpio = detect_gpio_support();
// 设置环境变量告诉lib.rs是否有实际的GPIO支持
// 注意这只影响PLATFORM_SUPPORTS_GPIO的值不影响依赖的启用
if supports_gpio {
// 设置编译器配置lib.rs会使用它
println!("cargo:rustc-env=HAS_GPIO_SUPPORT=true");
println!("cargo:warning=GPIO support detected, PLATFORM_SUPPORTS_GPIO will be true");
} else if cfg!(target_os = "linux") {
// 特殊情况Linux但没有GPIO支持
println!("cargo:rustc-env=HAS_GPIO_SUPPORT=false");
println!("cargo:warning=Running on Linux but no GPIO support detected, PLATFORM_SUPPORTS_GPIO will be false");
} else {
println!("cargo:rustc-env=HAS_GPIO_SUPPORT=false");
println!("cargo:warning=No GPIO support detected, PLATFORM_SUPPORTS_GPIO will be false");
}
// 通过包含的 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_gpio_support() -> 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: 检查是否存在/dev/gpiochip*设备
if Path::new("/dev/gpiochip0").exists() ||
fs::read_dir("/dev").ok()
.map(|entries| entries.filter_map(Result::ok)
.any(|entry| entry.file_name()
.to_string_lossy()
.starts_with("gpiochip")))
.unwrap_or(false) {
return true;
}
// 方法4: 检查是否存在/sys/class/gpio目录
if Path::new("/sys/class/gpio").exists() {
return true;
}
// 方法5: 检查是否安装了librpgpio库树莓派特有
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") {
Some(true)
} else {
None
}
} else {
None
}
});
if lib_check.is_some() {
return true;
}
// 回退到检查核心文件路径查找
if let Ok(model) = fs::read_to_string("/sys/firmware/devicetree/base/model") {
if model.contains("Raspberry Pi") {
return true;
}
}
// 如果还没确定,检查是否在环境变量中强制启用
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
}