mod cmake;
mod custom;
mod make;
mod meson;
use crate::config::{BuildSystemKind, DependencySpec};
use crate::error::{BuildError, Result};
use std::path::{Path, PathBuf};
use std::process::Command;
pub use cmake::CMakeBuilder;
pub use custom::CustomBuilder;
pub use make::MakeBuilder;
pub use meson::MesonBuilder;
#[derive(Debug, Clone, Default)]
pub struct BuildOutput {
pub include_dirs: Vec<PathBuf>,
pub lib_dirs: Vec<PathBuf>,
pub libs: Vec<String>,
}
pub trait DepBuilder {
fn detect(src_dir: &Path) -> bool
where
Self: Sized;
fn name(&self) -> &'static str;
fn build(&self, src_dir: &Path, prefix: &Path) -> Result<BuildOutput>;
}
pub fn resolve_builder(
dep_name: &str,
kind: &BuildSystemKind,
src_dir: &Path,
spec: &DependencySpec,
) -> Result<Box<dyn DepBuilder>> {
let builder: Box<dyn DepBuilder> = match kind {
BuildSystemKind::Cmake => Box::new(CMakeBuilder),
BuildSystemKind::Meson => Box::new(MesonBuilder),
BuildSystemKind::Make => Box::new(MakeBuilder),
BuildSystemKind::Custom => Box::new(CustomBuilder::new(spec)),
BuildSystemKind::Auto => {
let candidates = detect_available(src_dir);
match candidates.as_slice() {
[] => {
return Err(BuildError::BuildSystemDetectionFailed(
src_dir.display().to_string(),
))
}
[only] => build_of(only, spec),
multiple => {
eprintln!(
"Error: '{}': found multiple build systems ({}), choosing '{}'. \
To change - specify build_system in smidr.toml.",
dep_name,
multiple
.iter()
.map(|k| format!("{:?}", k))
.collect::<Vec<_>>()
.join(", "),
format!("{:?}", multiple[0])
);
build_of(&multiple[0], spec)
}
}
}
};
println!("Package '{}': building with {}", dep_name, builder.name());
Ok(builder)
}
fn detect_available(src_dir: &Path) -> Vec<BuildSystemKind> {
let mut found = Vec::new();
if CMakeBuilder::detect(src_dir) {
found.push(BuildSystemKind::Cmake);
}
if MesonBuilder::detect(src_dir) {
found.push(BuildSystemKind::Meson);
}
if MakeBuilder::detect(src_dir) {
found.push(BuildSystemKind::Make);
}
found
}
fn build_of(kind: &BuildSystemKind, spec: &DependencySpec) -> Box<dyn DepBuilder> {
match kind {
BuildSystemKind::Cmake => Box::new(CMakeBuilder),
BuildSystemKind::Meson => Box::new(MesonBuilder),
BuildSystemKind::Make => Box::new(MakeBuilder),
BuildSystemKind::Custom => Box::new(CustomBuilder::new(spec)),
BuildSystemKind::Auto => unreachable!("Auto not resolved in build_of"),
}
}
fn run(cmd: &mut Command) -> Result<()> {
let cmd_str = format!("{:?}", cmd);
println!(" $ {}", cmd_str);
let status = cmd.status().map_err(BuildError::Io)?;
if !status.success() {
return Err(BuildError::CommandFailed {
cmd: cmd_str,
code: status.code(),
});
}
Ok(())
}
fn collect_from_prefix(prefix: &Path) -> BuildOutput {
let mut lib_dirs = Vec::new();
for candidate in ["lib", "lib64"] {
let p = prefix.join(candidate);
if p.exists() {
lib_dirs.push(p);
}
}
BuildOutput {
include_dirs: vec![prefix.join("include")],
lib_dirs,
libs: Vec::new(),
}
}