new system ninjafile generation
This commit is contained in:
parent
7865c73006
commit
8b16858109
9 changed files with 176 additions and 10 deletions
0
src/file_writing/compile_commands.rs
Normal file
0
src/file_writing/compile_commands.rs
Normal file
5
src/file_writing/mod.rs
Normal file
5
src/file_writing/mod.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
pub mod compile_commands;
|
||||||
|
pub mod ninja_file;
|
||||||
|
|
||||||
|
pub use compile_commands::*;
|
||||||
|
pub use ninja_file::*;
|
120
src/file_writing/ninja_file.rs
Normal file
120
src/file_writing/ninja_file.rs
Normal 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)
|
||||||
|
}
|
47
src/main.rs
47
src/main.rs
|
@ -1,15 +1,17 @@
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use core::panic;
|
use core::panic;
|
||||||
use std::collections::HashMap;
|
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;
|
mod ngen_toml;
|
||||||
use ngen_toml::*;
|
use ngen_toml::*;
|
||||||
|
|
||||||
mod parsed_config_processing;
|
mod parsed_config_processing;
|
||||||
use parsed_config_processing::config_table::*;
|
use parsed_config_processing::*;
|
||||||
use parsed_config_processing::parsed_config_processing::*;
|
|
||||||
use parsed_config_processing::target::*;
|
mod file_writing;
|
||||||
|
use file_writing::*;
|
||||||
|
|
||||||
/// ngen is a build file generator for the ninja build system.
|
/// ngen is a build file generator for the ninja build system.
|
||||||
#[derive(Parser)]
|
#[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();
|
let mut targets: HashMap<&str, Target> = HashMap::new();
|
||||||
for (name, parsed_target) in all_parsed_targets {
|
for (name, parsed_target) in all_parsed_targets {
|
||||||
if let Some(_) = targets.get(name as &str) {
|
if let Some(_) = targets.get(name as &str) {
|
||||||
|
@ -74,6 +92,25 @@ fn main() {
|
||||||
Err(e) => panic!("{e}"),
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::parsed_config_processing::*;
|
use super::*;
|
||||||
use crate::ngen_toml::*;
|
use crate::ngen_toml::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
pub mod config_table;
|
pub mod config_table;
|
||||||
pub mod parsed_config_processing;
|
pub mod configuration_error;
|
||||||
pub mod target;
|
pub mod target;
|
||||||
pub mod target_options;
|
pub mod target_options;
|
||||||
|
|
||||||
|
pub use config_table::*;
|
||||||
|
pub use configuration_error::*;
|
||||||
|
pub use target::*;
|
||||||
|
pub use target_options::*;
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
use core::str;
|
use core::str;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use super::parsed_config_processing::*;
|
use super::*;
|
||||||
use super::target_options::*;
|
|
||||||
use crate::ngen_toml::*;
|
use crate::ngen_toml::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::parsed_config_processing::*;
|
use super::*;
|
||||||
use crate::ngen_toml::*;
|
use crate::ngen_toml::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
Loading…
Reference in a new issue