diff --git a/Cargo.lock b/Cargo.lock index e39a45a..e6b8505 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -86,6 +86,7 @@ version = "0.1.0" dependencies = [ "clap", "serde", + "strfmt", "toml", ] @@ -136,6 +137,12 @@ dependencies = [ "serde", ] +[[package]] +name = "strfmt" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a8348af2d9fc3258c8733b8d9d8db2e56f54b2363a4b5b81585c7875ed65e65" + [[package]] name = "syn" version = "2.0.52" diff --git a/Cargo.toml b/Cargo.toml index b10886e..fc74a0e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,4 +8,5 @@ edition = "2021" [dependencies] clap = { version = "4.5.1", features = ["derive", "std", "help", "usage"], default-features = false } serde = { version = "1.0.197", features = ["derive"] } +strfmt = "0.2.4" toml = "0.8.10" diff --git a/src/content_generation/error.rs b/src/content_generation/error.rs index fd497a8..3a45ac3 100644 --- a/src/content_generation/error.rs +++ b/src/content_generation/error.rs @@ -2,6 +2,7 @@ use std::fmt::Display; pub enum ErrorKind { NoSources, + FormatError, } pub struct Error { diff --git a/src/content_generation/ninja_file.rs b/src/content_generation/ninja_file.rs index 60d8a08..4c4229d 100644 --- a/src/content_generation/ninja_file.rs +++ b/src/content_generation/ninja_file.rs @@ -1,12 +1,14 @@ +use std::collections::HashMap; use std::fs::OpenOptions; use std::io::BufWriter; use std::io::Write; +use strfmt::strfmt; use super::*; use crate::parse_deser::*; use crate::Args; -pub fn gen_ninja_header(config: &Config, cmdline_args: &Args) -> Result { +fn gen_ninja_header(config: &Config, cmdline_args: &Args) -> Result { let mut ret = "".to_string(); ret.push_str(&format!( "## Generated by ngen @@ -52,7 +54,7 @@ build {0}: regen_ninjafile {1} || $builddir/compile_commands.json Ok(ret) } -pub fn gen_ninja_target(name: &str, target: &Target) -> Result { +fn gen_ninja_target(name: &str, target: &Target) -> Result { if target.sources.len() == 0 { return Err(Error { kind: ErrorKind::NoSources, @@ -66,23 +68,58 @@ pub fn gen_ninja_target(name: &str, target: &Target) -> Result { let linker_flags = target.linker_flags.join(" "); let linker_libs = target.linker_libs.join(" "); + let mut fmt_args = HashMap::new(); + fmt_args.insert("outfile".to_string(), "$out"); + fmt_args.insert("compiler".to_string(), target.compiler); + fmt_args.insert("compiler_flags".to_string(), &compiler_flags); + fmt_args.insert("linker".to_string(), target.compiler); + fmt_args.insert("object".to_string(), "$out"); + fmt_args.insert("objects".to_string(), "$in"); + fmt_args.insert("source".to_string(), "$in"); + fmt_args.insert("depfile".to_string(), "$dep"); + fmt_args.insert("linker_flags".to_string(), &linker_flags); + fmt_args.insert("linker_libs".to_string(), &linker_libs); + ret.push_str(&format!( "\ -# BEGIN TARGET {0} -rule cc_{0} +# BEGIN TARGET {name} +rule cc_{name} deps = gcc depfile = $dep - command = {1} {2} -MD -MF $dep -o $out -c $in + command = " + )); + match strfmt(target.opts.compile_cmd_fmt, &fmt_args) { + Ok(v) => ret.push_str(&v), + Err(e) => { + return Err(Error { + kind: ErrorKind::FormatError, + message: e.to_string(), + }); + } + } + ret.push_str(&format!( + " description = Building $in -> $out rule link_{name} - command = {3} {4} -o $out $in {5} + command = " + )); + match strfmt(target.opts.link_cmd_fmt, &fmt_args) { + Ok(v) => ret.push_str(&v), + Err(e) => { + return Err(Error { + kind: ErrorKind::FormatError, + message: e.to_string(), + }); + } + } + ret.push_str(&format!( + " description = Linking $out -build $builddir/{0}/obj: mkdir -build $builddir/{0}/dep: mkdir +build $builddir/{name}/obj: mkdir +build $builddir/{name}/dep: mkdir -", - name, target.compiler, compiler_flags, target.linker, linker_flags, linker_libs +" )); let mut object_list: Vec = Vec::new(); @@ -127,7 +164,6 @@ pub fn create_ninja_file_content( Ok(v) => ret.push_str(&v), Err(e) => match e.kind { ErrorKind::NoSources => eprintln!("WARNING: {e}. Skipping `{}`", name), - #[allow(unreachable_patterns)] _ => { return Err(e); } diff --git a/src/deser.rs b/src/deser.rs index 13fe916..9726a2b 100644 --- a/src/deser.rs +++ b/src/deser.rs @@ -21,6 +21,8 @@ pub struct DeserTargetOptions { pub inherit_from: Option, pub depend_on: Option>, pub default: Option, + pub compile_cmd_fmt: Option, + pub link_cmd_fmt: Option, } #[derive(Debug, Clone, Deserialize)] diff --git a/src/parse_deser/target_options.rs b/src/parse_deser/target_options.rs index 588180f..a209e7e 100644 --- a/src/parse_deser/target_options.rs +++ b/src/parse_deser/target_options.rs @@ -6,6 +6,8 @@ pub struct TargetOptions<'a> { pub inherit_from: &'a str, pub default: bool, pub depend_on: Vec<&'a str>, + pub compile_cmd_fmt: &'a str, + pub link_cmd_fmt: &'a str, } impl<'a> From<&'a DeserTargetOptions> for TargetOptions<'a> { @@ -30,6 +32,14 @@ impl<'a> From<&'a DeserTargetOptions> for TargetOptions<'a> { } } + if let Some(v) = &value.compile_cmd_fmt { + ret.compile_cmd_fmt = v; + } + + if let Some(v) = &value.link_cmd_fmt { + ret.link_cmd_fmt = v; + } + ret } } @@ -41,6 +51,9 @@ impl<'a> TargetOptions<'a> { inherit_from: "main", default: false, depend_on: vec![], + compile_cmd_fmt: + "{compiler} {compiler_flags} -MD -MF {depfile} -o {object} -c {source}", + link_cmd_fmt: "{linker} {linker_flags} -o {outfile} {objects} {linker_libs}", } } }