new system ninjafile generation

This commit is contained in:
Noah Swerhun 2024-03-11 21:25:12 -05:00
parent 7865c73006
commit 8b16858109
9 changed files with 176 additions and 10 deletions

View file

5
src/file_writing/mod.rs Normal file
View file

@ -0,0 +1,5 @@
pub mod compile_commands;
pub mod ninja_file;
pub use compile_commands::*;
pub use ninja_file::*;

View file

@ -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<String, ContentGenerationError> {
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<String> = 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)
}

View file

@ -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),
}
}
}

View file

@ -1,4 +1,4 @@
use super::parsed_config_processing::*;
use super::*;
use crate::ngen_toml::*;
#[derive(Debug, Clone)]

View file

@ -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::*;

View file

@ -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)]

View file

@ -1,4 +1,4 @@
use super::parsed_config_processing::*;
use super::*;
use crate::ngen_toml::*;
#[derive(Debug, Clone)]