From 8b1685810956f59d85546a3609d346aad74329f2 Mon Sep 17 00:00:00 2001 From: Noah Swerhun Date: Mon, 11 Mar 2024 21:25:12 -0500 Subject: [PATCH] new system ninjafile generation --- src/file_writing/compile_commands.rs | 0 src/file_writing/mod.rs | 5 + src/file_writing/ninja_file.rs | 120 ++++++++++++++++++ src/main.rs | 47 ++++++- src/parsed_config_processing/config_table.rs | 2 +- ...g_processing.rs => configuration_error.rs} | 0 src/parsed_config_processing/mod.rs | 7 +- src/parsed_config_processing/target.rs | 3 +- .../target_options.rs | 2 +- 9 files changed, 176 insertions(+), 10 deletions(-) create mode 100644 src/file_writing/compile_commands.rs create mode 100644 src/file_writing/mod.rs create mode 100644 src/file_writing/ninja_file.rs rename src/parsed_config_processing/{parsed_config_processing.rs => configuration_error.rs} (100%) diff --git a/src/file_writing/compile_commands.rs b/src/file_writing/compile_commands.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/file_writing/mod.rs b/src/file_writing/mod.rs new file mode 100644 index 0000000..9ad1f1a --- /dev/null +++ b/src/file_writing/mod.rs @@ -0,0 +1,5 @@ +pub mod compile_commands; +pub mod ninja_file; + +pub use compile_commands::*; +pub use ninja_file::*; diff --git a/src/file_writing/ninja_file.rs b/src/file_writing/ninja_file.rs new file mode 100644 index 0000000..55a16be --- /dev/null +++ b/src/file_writing/ninja_file.rs @@ -0,0 +1,120 @@ +use std::fmt::Display; + +use crate::parsed_config_processing::*; +use crate::Args; + +pub struct ContentGenerationError { + pub message: String, +} + +impl Display for ContentGenerationError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "content generation error: {}", self.message) + } +} + +pub fn gen_ninja_header(config: &ConfigTable, cmdline_args: &Args) -> String { + let mut ret = "".to_string(); + ret.push_str(&format!( + "## Generated by ngen +## Do not modify by hand + +builddir = {0} + +rule mkdir + command = mkdir -p $out + description = Creating directory $out + +rule regen_ninjafile + command = ngen -c $in -o $out + generator = 1 + description = Regenerating $out + +", + config.build_dir + )); + if config.compile_commands { + ret.push_str(&format!( + "\ +rule regen_compile_commands + command = ngen -c $in --write-compile-commands $out + description = Regenerating $out + +build $builddir: mkdir + +build $builddir/compile_commands.json: regen_compile_commands {1} || $builddir + pool = console + +build {0}: regen_ninjafile {1} || $builddir/compile_commands.json + pool = console +", + cmdline_args.output_file, cmdline_args.config_file + )); + } else { + ret.push_str(&format!( + "build {}: regen_ninjafile {}\n pool = console\n", + cmdline_args.output_file, cmdline_args.config_file + )); + } + ret +} + +pub fn gen_ninja_target(name: &str, target: &Target) -> Result { + if target.sources.len() == 0 { + return Err(ContentGenerationError { + message: format!("target `{}` has no sources", name), + }); + } + + let mut ret = "\n".to_string(); + + let compiler_flags = target.compiler_flags.join(" "); + let linker_flags = target.linker_flags.join(" "); + let linker_libs = target.linker_libs.join(" "); + + ret.push_str(&format!( + "\ +# BEGIN TARGET {0} +rule cc_{0} + deps = gcc + depfile = $dep + command = {1} {2} -MD -MF $dep -o $out -c $in + description = Building $in -> $out +rule link_{name} + command = {3} {4} -o $out $in {5} + description = Linking $out + +build $builddir/{0}/obj: mkdir +build $builddir/{0}/dep: mkdir + +", + name, target.compiler, compiler_flags, target.linker, linker_flags, linker_libs + )); + let mut object_list: Vec = Vec::new(); + + for source in &target.sources { + let new_file = source.replace("/", "-"); + let obj_name = format!("$builddir/{}/obj/{}.o", name, new_file); + let dep_name = format!("$builddir/{}/dep/{}.o.d", name, new_file); + ret.push_str(&format!( + "build {}: cc_{} {}\n dep = {}\n", + obj_name, name, source, dep_name + )); + object_list.push(obj_name); + } + + ret.push_str(&format!( + "\nbuild $builddir/{0}/{1}: link_{0} ", + name, target.outfile + )); + ret.push_str(&object_list.join(" ")); + ret.push_str(&format!( + " || $builddir/{0}/obj $builddir/{0}/dep\nbuild {0}: phony $builddir/{0}/{1}\n", + name, target.outfile + )); + if target.opts.default { + ret.push_str(&format!("\ndefault {}\n", name)); + } + ret.push_str(&format!("# END TARGET {}\n", name)); + Ok(ret) +} diff --git a/src/main.rs b/src/main.rs index 8505867..7cee5b4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,15 +1,17 @@ use clap::Parser; use core::panic; use std::collections::HashMap; -use std::fs::read_to_string; +use std::fs::{read_to_string, OpenOptions}; +use std::io::{BufWriter, Write}; mod ngen_toml; use ngen_toml::*; mod parsed_config_processing; -use parsed_config_processing::config_table::*; -use parsed_config_processing::parsed_config_processing::*; -use parsed_config_processing::target::*; +use parsed_config_processing::*; + +mod file_writing; +use file_writing::*; /// ngen is a build file generator for the ninja build system. #[derive(Parser)] @@ -55,6 +57,22 @@ fn main() { ), } + let mut sources_found = false; + for target in all_parsed_targets.values() { + if let Some(_) = target.sources { + sources_found = true; + break; + } + } + if !sources_found { + panic!( + "{}", + ConfigurationError { + message: "no targets have any sources, nothing to do. Exiting".to_string() + } + ); + } + let mut targets: HashMap<&str, Target> = HashMap::new(); for (name, parsed_target) in all_parsed_targets { if let Some(_) = targets.get(name as &str) { @@ -74,6 +92,25 @@ fn main() { Err(e) => panic!("{e}"), } } + let ninjafile = OpenOptions::new() + .write(true) + .truncate(true) + .create(true) + .open(&args.output_file) + .unwrap_or_else(|e| panic!("error opening ninja file `{}`: {e}", args.output_file)); - println!("{:#?}", targets); + let mut ninjafile_writer = BufWriter::new(ninjafile); + ninjafile_writer + .write(&gen_ninja_header(&config_table, &args).as_bytes()) + .unwrap_or_else(|e| panic!("error writing to ninja file `{}`: {e}", args.output_file)); + for (name, target) in &targets { + match gen_ninja_target(name, target) { + Ok(v) => { + ninjafile_writer.write(&v.as_bytes()).unwrap_or_else(|e| { + panic!("error writing to ninja file `{}`: {e}", args.output_file) + }); + } + Err(e) => eprintln!("WARNING: {e}. `{}` will NOT be generated", name), + } + } } diff --git a/src/parsed_config_processing/config_table.rs b/src/parsed_config_processing/config_table.rs index 270b7c2..a06856b 100644 --- a/src/parsed_config_processing/config_table.rs +++ b/src/parsed_config_processing/config_table.rs @@ -1,4 +1,4 @@ -use super::parsed_config_processing::*; +use super::*; use crate::ngen_toml::*; #[derive(Debug, Clone)] diff --git a/src/parsed_config_processing/parsed_config_processing.rs b/src/parsed_config_processing/configuration_error.rs similarity index 100% rename from src/parsed_config_processing/parsed_config_processing.rs rename to src/parsed_config_processing/configuration_error.rs diff --git a/src/parsed_config_processing/mod.rs b/src/parsed_config_processing/mod.rs index d1ee3fd..9053796 100644 --- a/src/parsed_config_processing/mod.rs +++ b/src/parsed_config_processing/mod.rs @@ -1,4 +1,9 @@ pub mod config_table; -pub mod parsed_config_processing; +pub mod configuration_error; pub mod target; pub mod target_options; + +pub use config_table::*; +pub use configuration_error::*; +pub use target::*; +pub use target_options::*; diff --git a/src/parsed_config_processing/target.rs b/src/parsed_config_processing/target.rs index 3763f41..f17d15c 100644 --- a/src/parsed_config_processing/target.rs +++ b/src/parsed_config_processing/target.rs @@ -1,8 +1,7 @@ use core::str; use std::collections::HashMap; -use super::parsed_config_processing::*; -use super::target_options::*; +use super::*; use crate::ngen_toml::*; #[derive(Debug, Clone)] diff --git a/src/parsed_config_processing/target_options.rs b/src/parsed_config_processing/target_options.rs index c6b7a44..f487a80 100644 --- a/src/parsed_config_processing/target_options.rs +++ b/src/parsed_config_processing/target_options.rs @@ -1,4 +1,4 @@ -use super::parsed_config_processing::*; +use super::*; use crate::ngen_toml::*; #[derive(Debug, Clone)]