pub mod android_ndk;
pub mod linux;
pub mod mingw;
pub mod msvc;
pub mod ohos;
pub mod xcode;
use std::path::PathBuf;
use anyhow::Result;
pub trait Toolchain {
fn name(&self) -> &str;
fn is_available(&self) -> bool;
fn path(&self) -> Option<PathBuf>;
fn cmake_variables(&self) -> Vec<(String, String)>;
fn validate(&self) -> Result<()>;
}
pub fn find_executable(name: &str) -> Option<PathBuf> {
which::which(name).ok()
}
pub fn find_executable_any(names: &[&str]) -> Option<PathBuf> {
for name in names {
if let Some(path) = find_executable(name) {
return Some(path);
}
}
None
}
pub fn get_env_path(name: &str) -> Option<PathBuf> {
std::env::var(name).ok().map(PathBuf::from)
}
pub fn is_valid_directory(path: &PathBuf) -> bool {
path.exists() && path.is_dir()
}
pub fn is_valid_file(path: &PathBuf) -> bool {
path.exists() && path.is_file()
}
#[derive(Debug, Clone, PartialEq)]
pub enum CompilerType {
Gcc,
Clang,
Msvc,
Other(String),
}
impl std::fmt::Display for CompilerType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CompilerType::Gcc => write!(f, "gcc"),
CompilerType::Clang => write!(f, "clang"),
CompilerType::Msvc => write!(f, "msvc"),
CompilerType::Other(name) => write!(f, "{}", name),
}
}
}
#[derive(Debug, Clone)]
pub struct CompilerInfo {
pub compiler_type: CompilerType,
pub cc: PathBuf,
pub cxx: PathBuf,
pub version: String,
}
impl CompilerInfo {
pub fn cmake_variables(&self) -> Vec<(String, String)> {
vec![
("CMAKE_C_COMPILER".to_string(), self.cc.display().to_string()),
(
"CMAKE_CXX_COMPILER".to_string(),
self.cxx.display().to_string(),
),
]
}
}
pub fn detect_default_compiler() -> Option<CompilerInfo> {
if let (Some(cc), Some(cxx)) = (find_executable("clang"), find_executable("clang++")) {
let version = get_compiler_version(&cc).unwrap_or_else(|| "unknown".to_string());
return Some(CompilerInfo {
compiler_type: CompilerType::Clang,
cc,
cxx,
version,
});
}
if let (Some(cc), Some(cxx)) = (find_executable("gcc"), find_executable("g++")) {
let version = get_compiler_version(&cc).unwrap_or_else(|| "unknown".to_string());
return Some(CompilerInfo {
compiler_type: CompilerType::Gcc,
cc,
cxx,
version,
});
}
if let (Some(cc), Some(cxx)) = (find_executable("cc"), find_executable("c++")) {
let version = get_compiler_version(&cc).unwrap_or_else(|| "unknown".to_string());
return Some(CompilerInfo {
compiler_type: CompilerType::Other("cc".to_string()),
cc,
cxx,
version,
});
}
None
}
fn get_compiler_version(compiler: &PathBuf) -> Option<String> {
let output = std::process::Command::new(compiler)
.arg("--version")
.output()
.ok()?;
let stdout = String::from_utf8_lossy(&output.stdout);
stdout.lines().next().map(|s| s.to_string())
}