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 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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::parsed_config_processing::*;
|
||||
use super::*;
|
||||
use crate::ngen_toml::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
@ -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::*;
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::parsed_config_processing::*;
|
||||
use super::*;
|
||||
use crate::ngen_toml::*;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
Loading…
Reference in a new issue