use super::*;
pub fn cmake_build_type() -> Option<String> {
env::var("CMKABE_CMAKE_BUILD_TYPE").ok()
}
pub fn cmake_build_dir() -> Option<String> {
env::var("CMKABE_CMAKE_BUILD_DIR").ok()
}
pub fn cmake_prefix_subdirs() -> Vec<PathBuf> {
_cmake_env_dirs("CMKABE_PREFIX_SUBDIRS")
}
pub fn cmake_bin_dirs() -> Vec<PathBuf> {
_cmake_env_dirs("CMKABE_BIN_DIRS")
}
pub fn cmake_lib_dirs() -> Vec<PathBuf> {
_cmake_env_dirs("CMKABE_LIB_DIRS")
}
pub fn cmake_include_dirs() -> Vec<PathBuf> {
_cmake_env_dirs("CMKABE_INCLUDE_DIRS")
}
pub fn set_link_search(link_kind: Option<SearchKind>) {
for dir in cmake_lib_dirs() {
rustc::link_search(link_kind, dir);
}
}
fn _cmake_env_dirs(key: &str) -> Vec<PathBuf> {
if let Ok(dirs) = env::var(key) {
env::split_paths(&dirs)
.filter_map(|dir| {
dir.to_str().and_then(|dir| {
let dir = dir.trim();
if !dir.is_empty() {
Some(PathBuf::from(dir))
} else {
None
}
})
})
.collect()
} else {
Vec::new()
}
}
#[derive(Clone, Default)]
pub struct MakeBuilder {
target: String,
args: Vec<String>,
skipped: bool,
}
impl MakeBuilder {
const SPLIT_CHARS: &'static [char] = &[' ', '\t', ';', ','];
pub fn with_cmake_targets<I>(cmake_targets: I) -> Self
where
I: IntoIterator,
I::Item: AsRef<str>,
{
let mut builder = Self::default();
let mut filter_out = Vec::<&str>::new();
let completed_projects = env::var("CMKABE_COMPLETED_PROJECTS").ok();
if let Some(ref s) = completed_projects {
s.split(Self::SPLIT_CHARS)
.filter(|&s| !s.is_empty())
.for_each(|x| filter_out.push(x));
}
let mut arg = "CMAKE_TARGETS=".to_owned();
builder.skipped = true;
cmake_targets.into_iter().for_each(|x| {
let s = x.as_ref();
if !filter_out.contains(&s) {
if builder.skipped {
builder.skipped = false;
} else {
arg.push(' ');
}
arg.push_str(s);
}
});
builder.arg("cmake".to_owned());
builder.arg(arg);
builder
}
pub fn arg(&mut self, arg: impl Into<String>) -> &mut Self {
self.args.push(arg.into());
self
}
pub fn args<A>(&mut self, args: A) -> &mut Self
where
A: IntoIterator,
A::Item: Into<String>,
{
self.args.extend(args.into_iter().map(|x| x.into()));
self
}
pub fn build(&self) -> io::Result<()> {
if self.skipped {
return Ok(());
}
let root = cargo::workspace_dir();
let target = if self.target.is_empty() {
"cmake-build".to_owned()
} else if self.target.starts_with("cmake-") {
self.target.clone()
} else {
format!("cmake-{}", &self.target)
};
let mut args = vec![target];
args.extend(self.args.iter().cloned());
if let Ok(vars) = env::var("CMKABE_MAKE_BUILD_VARS") {
let mut key = String::new();
for name in vars.split(Self::SPLIT_CHARS).filter(|&s| !s.is_empty()) {
key.clear();
key.push_str("CMKABE_");
key.push_str(name);
args.push(format!("{}={}", name, env::var(&key).unwrap_or_default()));
}
} else {
let (triple, _linker) = cargo::triple_with_linker();
args.push(format!("TARGET={}", triple));
}
rerun_if_changed(root.join("CMakeLists.txt"));
match duct::cmd("make", args)
.stdout_to_stderr()
.unchecked()
.dir(root)
.run()?
.status
.code()
.unwrap_or(1)
{
0 => Ok(()),
status => Err(io::Error::other(format!(
"CMake build failed with error code: {status}"
))),
}
}
}