groundwork laid (not functional yet)
This commit is contained in:
parent
abec4c2ba0
commit
001a9735ee
6 changed files with 370 additions and 267 deletions
|
@ -1,47 +0,0 @@
|
||||||
use toml::{Table, Value};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Config {
|
|
||||||
pub build_dir: String,
|
|
||||||
pub compile_commands: bool,
|
|
||||||
pub compile_commands_target: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Config {
|
|
||||||
pub fn get_default() -> Self {
|
|
||||||
Config {
|
|
||||||
build_dir: String::from("build"),
|
|
||||||
compile_commands: false,
|
|
||||||
compile_commands_target: String::from(""),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn set(&mut self, table: &Table) {
|
|
||||||
for k in table.keys() {
|
|
||||||
match &*k.to_owned() {
|
|
||||||
"build_dir" => {
|
|
||||||
if let Value::String(s) = table.get(k).unwrap() {
|
|
||||||
self.build_dir = s.to_owned();
|
|
||||||
} else {
|
|
||||||
panic!("error parsing config table: {k} invalid type, must be a string.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"compile_commands" => {
|
|
||||||
if let Value::Boolean(b) = table.get(k).unwrap() {
|
|
||||||
//eprintln!("warn: config.compile_commands has no functionality (yet)");
|
|
||||||
self.compile_commands = *b;
|
|
||||||
} else {
|
|
||||||
panic!("error parsing config table: {k} invalid type, must be a boolean.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"compile_commands_target" => {
|
|
||||||
if let Value::String(s) = table.get(k).unwrap() {
|
|
||||||
self.compile_commands_target = s.to_owned();
|
|
||||||
} else {
|
|
||||||
panic!("error parsing config table: {k} invalid type, must be a string.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => panic!("error parsing config table: unrecognized key {k}."),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
106
src/config_file_parsing.rs
Normal file
106
src/config_file_parsing.rs
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use toml::{Table, Value};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ConfigFileError<'a> {
|
||||||
|
pub key_path: String,
|
||||||
|
pub message: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ConfigFileError<'_> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"config file error: key {}: {}.",
|
||||||
|
self.key_path, self.message
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_key_as_str<'a>(
|
||||||
|
table: &'a Table,
|
||||||
|
key: &str,
|
||||||
|
key_path: String,
|
||||||
|
) -> Result<Option<&'a str>, ConfigFileError<'a>> {
|
||||||
|
if let Some(v) = table.get(key) {
|
||||||
|
if let Value::String(s) = v {
|
||||||
|
Ok(Some(s))
|
||||||
|
} else {
|
||||||
|
Err(ConfigFileError {
|
||||||
|
key_path,
|
||||||
|
message: "invalid type, should be string",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_key_as_table<'a>(
|
||||||
|
table: &'a Table,
|
||||||
|
key: &str,
|
||||||
|
key_path: String,
|
||||||
|
) -> Result<Option<&'a Table>, ConfigFileError<'a>> {
|
||||||
|
if let Some(v) = table.get(key) {
|
||||||
|
if let Value::Table(s) = v {
|
||||||
|
Ok(Some(s))
|
||||||
|
} else {
|
||||||
|
Err(ConfigFileError {
|
||||||
|
key_path,
|
||||||
|
message: "invalid type, should be a table of key-value pairs",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_key_as_bool<'a>(
|
||||||
|
table: &'a Table,
|
||||||
|
key: &str,
|
||||||
|
key_path: String,
|
||||||
|
) -> Result<Option<bool>, ConfigFileError<'a>> {
|
||||||
|
if let Some(v) = table.get(key) {
|
||||||
|
if let Value::Boolean(s) = v {
|
||||||
|
Ok(Some(*s))
|
||||||
|
} else {
|
||||||
|
Err(ConfigFileError {
|
||||||
|
key_path,
|
||||||
|
message: "invalid type, should be boolean",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_key_as_vec_str<'a>(
|
||||||
|
table: &'a Table,
|
||||||
|
key: &str,
|
||||||
|
key_path: String,
|
||||||
|
) -> Result<Option<Vec<&'a str>>, ConfigFileError<'a>> {
|
||||||
|
if let Some(v) = table.get(key) {
|
||||||
|
if let Value::Array(a) = v {
|
||||||
|
let mut ret: Vec<&'a str> = vec![];
|
||||||
|
for elem in a {
|
||||||
|
if let Value::String(s) = elem {
|
||||||
|
ret.push(&s);
|
||||||
|
} else {
|
||||||
|
return Err(ConfigFileError {
|
||||||
|
key_path: format!("{key_path} elemement '{elem}'"),
|
||||||
|
message: "invalid type, should be string",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(Some(ret))
|
||||||
|
} else {
|
||||||
|
Err(ConfigFileError {
|
||||||
|
key_path,
|
||||||
|
message: "invalid type, should be array of strings",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
45
src/config_table.rs
Normal file
45
src/config_table.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
use toml::Table;
|
||||||
|
|
||||||
|
use crate::config_file_parsing::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct ConfigTable<'a> {
|
||||||
|
pub build_dir: &'a str,
|
||||||
|
pub compile_commands: bool,
|
||||||
|
pub compile_commands_target: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> ConfigTable<'a> {
|
||||||
|
pub fn get_default() -> Self {
|
||||||
|
ConfigTable {
|
||||||
|
build_dir: "build",
|
||||||
|
compile_commands: false,
|
||||||
|
compile_commands_target: "main",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_table(table: &'a Table, key_path: String) -> Result<Self, ConfigFileError<'a>> {
|
||||||
|
let mut ret = Self::get_default();
|
||||||
|
|
||||||
|
if let Some(v) = get_key_as_str(table, "build_dir", format!("{key_path}.build_dir"))? {
|
||||||
|
ret.build_dir = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(v) = get_key_as_bool(
|
||||||
|
table,
|
||||||
|
"compile_commands",
|
||||||
|
format!("{key_path}.compile_commands"),
|
||||||
|
)? {
|
||||||
|
ret.compile_commands = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(v) = get_key_as_str(
|
||||||
|
table,
|
||||||
|
"compile_commands_target",
|
||||||
|
format!("{key_path}.compile_commands_target"),
|
||||||
|
)? {
|
||||||
|
ret.compile_commands_target = v;
|
||||||
|
}
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
}
|
216
src/main.rs
216
src/main.rs
|
@ -1,4 +1,6 @@
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use config_file_parsing::get_key_as_table;
|
||||||
|
use core::{panic, str};
|
||||||
use std::{
|
use std::{
|
||||||
fs::{read_to_string, write},
|
fs::{read_to_string, write},
|
||||||
path::Path,
|
path::Path,
|
||||||
|
@ -9,8 +11,11 @@ use toml::{Table, Value};
|
||||||
mod target;
|
mod target;
|
||||||
use target::*;
|
use target::*;
|
||||||
|
|
||||||
mod config;
|
mod config_table;
|
||||||
use config::*;
|
use config_table::*;
|
||||||
|
|
||||||
|
mod config_file_parsing;
|
||||||
|
mod target_options;
|
||||||
|
|
||||||
/// 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)]
|
||||||
|
@ -125,109 +130,128 @@ fn main() {
|
||||||
|
|
||||||
let config_file = read_to_string(config_file_name)
|
let config_file = read_to_string(config_file_name)
|
||||||
.unwrap_or_else(|e| panic!("could not read config file {config_file_name}: {e}"));
|
.unwrap_or_else(|e| panic!("could not read config file {config_file_name}: {e}"));
|
||||||
let parsed_config = toml::from_str::<Table>(&config_file)
|
let toml_config = toml::from_str::<Table>(&config_file)
|
||||||
.unwrap_or_else(|e| panic!("error parsing toml file {config_file_name}: {e}"));
|
.unwrap_or_else(|e| panic!("error parsing toml file {config_file_name}: {e}"));
|
||||||
|
|
||||||
// get config
|
// get config
|
||||||
let mut config = Config::get_default();
|
let config_tbl: ConfigTable;
|
||||||
if let Some(v) = parsed_config.get("config") {
|
match get_key_as_table(&toml_config, "config", "".to_string()) {
|
||||||
if let Value::Table(t) = v {
|
Ok(v) => match v {
|
||||||
config.set(&t);
|
Some(c) => {
|
||||||
} else {
|
config_tbl = ConfigTable::from_table(&c, ".config".to_string())
|
||||||
panic!("error parsing config table: config invalid type, must be a table.");
|
.unwrap_or_else(|e| panic!("{e}"))
|
||||||
}
|
}
|
||||||
|
None => config_tbl = ConfigTable::get_default(),
|
||||||
|
},
|
||||||
|
Err(e) => panic!("{e}"),
|
||||||
}
|
}
|
||||||
|
println!("{:?}", config_tbl);
|
||||||
|
//let mut config = Config::get_default();
|
||||||
|
//if let Some(v) = parsed_config.get("config") {
|
||||||
|
// if let Value::Table(t) = v {
|
||||||
|
// config.set(&t);
|
||||||
|
// } else {
|
||||||
|
// panic!("error parsing config table: config invalid type, must be a table.");
|
||||||
|
// }
|
||||||
|
//}
|
||||||
//----
|
//----
|
||||||
|
|
||||||
// parse the main target first
|
// parse the main target first
|
||||||
let mut targets: Vec<Target> = Vec::new();
|
//let mut targets: Vec<Target> = vec![];
|
||||||
let main_target = Target::new(&parsed_config, "main", None);
|
|
||||||
targets.push(main_target.clone());
|
|
||||||
let mut target_for_comp_cmds = main_target;
|
|
||||||
let mut target_for_comp_cmds_changed = false;
|
|
||||||
|
|
||||||
// parse other targets
|
match Target::from_table(&toml_config, "main", "".to_string()) {
|
||||||
for k in parsed_config.keys() {
|
Ok(v) => println!("{:?}", v),
|
||||||
if let Value::Table(t) = parsed_config.get(k).unwrap() {
|
Err(e) => panic!("{e}"),
|
||||||
if k == "config" {
|
|
||||||
continue; // ignore config
|
|
||||||
}
|
|
||||||
let target = Target::new(&t, k, Some(&targets[0]));
|
|
||||||
targets.push(target);
|
|
||||||
if let Some(_) = args.write_compile_commands {
|
|
||||||
if *k == config.compile_commands_target {
|
|
||||||
target_for_comp_cmds = targets[targets.len() - 1].clone();
|
|
||||||
target_for_comp_cmds_changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(file) = args.write_compile_commands {
|
exit(10);
|
||||||
if config.compile_commands_target == "" {
|
|
||||||
eprintln!(
|
|
||||||
"ngen: warn: no compile_commands target found, using 'main' target by default."
|
|
||||||
);
|
|
||||||
} else if !target_for_comp_cmds_changed && config.compile_commands_target != "main" {
|
|
||||||
let c = &config.compile_commands_target;
|
|
||||||
eprintln!(
|
|
||||||
"ngen: warn: compile_commands target {c} not found, using 'main' target instead."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
write(
|
|
||||||
&file,
|
|
||||||
&gen_compile_commands(&target_for_comp_cmds, &config.build_dir),
|
|
||||||
)
|
|
||||||
.unwrap_or_else(|e| panic!("fatal: could not write {file}: {e}"));
|
|
||||||
// no need to write ninja file
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
let build_dir = &config.build_dir;
|
// targets.push(main_target.clone());
|
||||||
let mut ninjafile = format!(
|
// let mut target_for_comp_cmds = main_target;
|
||||||
"\
|
// let mut target_for_comp_cmds_changed = false;
|
||||||
# Generated by ngen. Do not modify by hand.
|
//
|
||||||
|
// // parse other targets
|
||||||
builddir = {build_dir}
|
// for k in parsed_config.keys() {
|
||||||
|
// if let Value::Table(t) = parsed_config.get(k).unwrap() {
|
||||||
rule mkdir
|
// if k == "config" {
|
||||||
command = mkdir -p $out
|
// continue; // ignore config
|
||||||
description = Creating directory $out
|
// }
|
||||||
|
// let target = Target::new(&t, k, Some(&targets[0]));
|
||||||
rule regen_ninjafile
|
// targets.push(target);
|
||||||
command = ngen -c $in -o $out
|
// if let Some(_) = args.write_compile_commands {
|
||||||
generator = 1
|
// if *k == config.compile_commands_target {
|
||||||
description = Regenerating $out
|
// target_for_comp_cmds = targets[targets.len() - 1].clone();
|
||||||
|
// target_for_comp_cmds_changed = true;
|
||||||
",
|
// }
|
||||||
);
|
// }
|
||||||
|
// }
|
||||||
if config.compile_commands {
|
// }
|
||||||
ninjafile.push_str(&format!(
|
//
|
||||||
"\
|
// if let Some(file) = args.write_compile_commands {
|
||||||
rule regen_compile_commands
|
// if config.compile_commands_target == "" {
|
||||||
command = ngen -c $in --write-compile-commands $out
|
// eprintln!(
|
||||||
description = Regenerating $out
|
// "ngen: warn: no compile_commands target found, using 'main' target by default."
|
||||||
|
// );
|
||||||
build $builddir: mkdir
|
// } else if !target_for_comp_cmds_changed && config.compile_commands_target != "main" {
|
||||||
|
// let c = &config.compile_commands_target;
|
||||||
build $builddir/compile_commands.json: regen_compile_commands {config_file_name} || $builddir
|
// eprintln!(
|
||||||
pool = console
|
// "ngen: warn: compile_commands target {c} not found, using 'main' target instead."
|
||||||
|
// );
|
||||||
build {output_file}: regen_ninjafile {config_file_name} || $builddir/compile_commands.json
|
// }
|
||||||
pool = console
|
// write(
|
||||||
"
|
// &file,
|
||||||
));
|
// &gen_compile_commands(&target_for_comp_cmds, &config.build_dir),
|
||||||
} else {
|
// )
|
||||||
ninjafile.push_str(&format!(
|
// .unwrap_or_else(|e| panic!("fatal: could not write {file}: {e}"));
|
||||||
"build {output_file}: regen_ninjafile {config_file_name}\n pool = console\n"
|
// // no need to write ninja file
|
||||||
));
|
// exit(0);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
for t in targets {
|
// let build_dir = &config.build_dir;
|
||||||
ninjafile.push_str(&gen_ninja_code(&t));
|
// let mut ninjafile = format!(
|
||||||
}
|
// "\
|
||||||
|
//# Generated by ngen. Do not modify by hand.
|
||||||
write(output_file, &ninjafile)
|
//
|
||||||
.unwrap_or_else(|e| panic!("could not write ninja file {ninjafile}: {e}"));
|
//builddir = {build_dir}
|
||||||
|
//
|
||||||
|
//rule mkdir
|
||||||
|
// command = mkdir -p $out
|
||||||
|
// description = Creating directory $out
|
||||||
|
//
|
||||||
|
//rule regen_ninjafile
|
||||||
|
// command = ngen -c $in -o $out
|
||||||
|
// generator = 1
|
||||||
|
// description = Regenerating $out
|
||||||
|
//
|
||||||
|
//",
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// if config.compile_commands {
|
||||||
|
// ninjafile.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 {config_file_name} || $builddir
|
||||||
|
// pool = console
|
||||||
|
//
|
||||||
|
//build {output_file}: regen_ninjafile {config_file_name} || $builddir/compile_commands.json
|
||||||
|
// pool = console
|
||||||
|
//"
|
||||||
|
// ));
|
||||||
|
// } else {
|
||||||
|
// ninjafile.push_str(&format!(
|
||||||
|
// "build {output_file}: regen_ninjafile {config_file_name}\n pool = console\n"
|
||||||
|
// ));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// for t in targets {
|
||||||
|
// ninjafile.push_str(&gen_ninja_code(&t));
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// write(output_file, &ninjafile)
|
||||||
|
// .unwrap_or_else(|e| panic!("could not write ninja file {ninjafile}: {e}"));
|
||||||
}
|
}
|
||||||
|
|
193
src/target.rs
193
src/target.rs
|
@ -1,145 +1,90 @@
|
||||||
use toml::{Table, Value};
|
use toml::Table;
|
||||||
|
|
||||||
|
use crate::config_file_parsing::*;
|
||||||
|
use crate::target_options::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Target {
|
pub struct Target<'a> {
|
||||||
pub name: String,
|
pub name: &'a str,
|
||||||
pub outfile: String,
|
pub outfile: &'a str,
|
||||||
pub compiler: String,
|
pub compiler: &'a str,
|
||||||
pub compiler_flags: Vec<String>,
|
pub compiler_flags: Vec<&'a str>,
|
||||||
pub linker: String,
|
pub linker: &'a str,
|
||||||
pub linker_flags: Vec<String>,
|
pub linker_flags: Vec<&'a str>,
|
||||||
pub linker_libs: Vec<String>,
|
pub linker_libs: Vec<&'a str>,
|
||||||
pub sources: Vec<String>,
|
pub sources: Vec<&'a str>,
|
||||||
pub is_default: bool,
|
pub is_default: bool,
|
||||||
|
pub opts: TargetOptions<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Target {
|
impl<'a> Target<'a> {
|
||||||
fn get_default() -> Self {
|
pub fn get_default() -> Self {
|
||||||
Target {
|
Target {
|
||||||
name: String::from(""),
|
name: "",
|
||||||
outfile: String::from("a.out"),
|
outfile: "a.out",
|
||||||
compiler: String::from("cc"),
|
compiler: "cc",
|
||||||
compiler_flags: Vec::new(),
|
compiler_flags: vec![""],
|
||||||
linker: String::from(""),
|
linker: "cc",
|
||||||
linker_flags: Vec::new(),
|
linker_flags: vec![""],
|
||||||
linker_libs: Vec::new(),
|
linker_libs: vec![""],
|
||||||
sources: Vec::new(),
|
sources: vec![""],
|
||||||
is_default: false,
|
is_default: false,
|
||||||
|
opts: TargetOptions::get_default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn new(table: &Table, name: &str, inherit_from: Option<&Self>) -> Self {
|
pub fn from_table(
|
||||||
let mut ret: Self;
|
table: &'a Table,
|
||||||
let mut linker_set = false;
|
name: &'a str,
|
||||||
|
key_path: String,
|
||||||
|
) -> Result<Self, ConfigFileError<'a>> {
|
||||||
|
let mut ret = Self::get_default();
|
||||||
|
|
||||||
if let Some(t) = inherit_from {
|
if let Some(v) = get_key_as_table(table, "opts", format!("{key_path}.opts"))? {
|
||||||
ret = t.clone();
|
ret.opts = TargetOptions::from_table(&v, format!("{key_path}.opts"))?;
|
||||||
} else {
|
|
||||||
ret = Self::get_default();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.name = String::from(name);
|
ret.name = name;
|
||||||
ret.is_default = false;
|
|
||||||
|
|
||||||
for k in table.keys() {
|
if let Some(v) = get_key_as_str(table, "outfile", format!("{key_path}.outfile"))? {
|
||||||
match &*k.to_owned() {
|
ret.outfile = v;
|
||||||
"outfile" => {
|
|
||||||
if let Value::String(s) = table.get(k).unwrap() {
|
|
||||||
ret.outfile = s.to_owned();
|
|
||||||
} else {
|
|
||||||
panic!("error parsing target {name}: {k} invalid type, must be a string.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"compiler" => {
|
|
||||||
if let Value::String(s) = table.get(k).unwrap() {
|
|
||||||
ret.compiler = s.to_owned();
|
|
||||||
} else {
|
|
||||||
panic!("error parsing target {name}: {k} invalid type, must be a string.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"compiler_flags" => {
|
|
||||||
if let Value::Array(a) = table.get(k).unwrap() {
|
|
||||||
for element in a {
|
|
||||||
if let Value::String(s) = element {
|
|
||||||
ret.compiler_flags.push(s.to_owned());
|
|
||||||
} else {
|
|
||||||
panic!("error parsing target {name}: {k} invalid type, must be a array of strings.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
panic!("error parsing target {name}: {k} invalid type, must be a array of strings.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"linker" => {
|
|
||||||
if let Value::String(s) = table.get(k).unwrap() {
|
|
||||||
ret.linker = s.to_owned();
|
|
||||||
linker_set = true;
|
|
||||||
} else {
|
|
||||||
panic!("error parsing target {name}: {k} invalid type, must be a string.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"linker_flags" => {
|
|
||||||
if let Value::Array(a) = table.get(k).unwrap() {
|
|
||||||
for element in a {
|
|
||||||
if let Value::String(s) = element {
|
|
||||||
ret.linker_flags.push(s.to_owned());
|
|
||||||
} else {
|
|
||||||
panic!("error parsing target {name}: {k} invalid type, must be a array of strings.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
panic!("error parsing target {name}: {k} invalid type, must be a array of strings.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"linker_libs" => {
|
|
||||||
if let Value::Array(a) = table.get(k).unwrap() {
|
|
||||||
for element in a {
|
|
||||||
if let Value::String(s) = element {
|
|
||||||
ret.linker_libs.push(s.to_owned());
|
|
||||||
} else {
|
|
||||||
panic!("error parsing target {name}: {k} invalid type, must be a array of strings.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
panic!("error parsing target {name}: {k} invalid type, must be a array of strings.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"sources" => {
|
|
||||||
if let Value::Array(a) = table.get(k).unwrap() {
|
|
||||||
for element in a {
|
|
||||||
if let Value::String(s) = element {
|
|
||||||
ret.sources.push(s.to_owned());
|
|
||||||
} else {
|
|
||||||
panic!("error parsing target {name}: {k} invalid type, must be a array of strings.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
panic!("error parsing target {name}: {k} invalid type, must be a array of strings.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"default" => {
|
|
||||||
if let Value::Boolean(b) = table.get(k).unwrap() {
|
|
||||||
ret.is_default = *b;
|
|
||||||
} else {
|
|
||||||
panic!("error parsing target {name}: {k} invalid type, must be a boolean.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
if let Value::Table(_) = table.get(k).unwrap() {
|
|
||||||
} else {
|
|
||||||
panic!("error parsing target {name}: unrecognized key {k}.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !linker_set {
|
if let Some(v) = get_key_as_str(table, "compiler", format!("{key_path}.compiler"))? {
|
||||||
ret.linker = ret.compiler.clone();
|
ret.compiler = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ret.sources == Vec::<String>::new() {
|
if let Some(v) = get_key_as_vec_str(
|
||||||
panic!("error parsing target {name}: you MUST specify at least one source");
|
table,
|
||||||
|
"compiler_flags",
|
||||||
|
format!("{key_path}.compiler_flags"),
|
||||||
|
)? {
|
||||||
|
ret.compiler_flags = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret
|
if let Some(v) = get_key_as_str(table, "linker", format!("{key_path}.linker"))? {
|
||||||
|
ret.linker = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(v) =
|
||||||
|
get_key_as_vec_str(table, "linker_flags", format!("{key_path}.linker_flags"))?
|
||||||
|
{
|
||||||
|
ret.linker_flags = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(v) =
|
||||||
|
get_key_as_vec_str(table, "linker_libs", format!("{key_path}.linker_libs"))?
|
||||||
|
{
|
||||||
|
ret.linker_libs = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(v) = get_key_as_vec_str(table, "sources", format!("{key_path}.sources"))? {
|
||||||
|
ret.sources = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(v) = get_key_as_bool(table, "is_default", format!("{key_path}.is_default"))? {
|
||||||
|
ret.is_default = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
30
src/target_options.rs
Normal file
30
src/target_options.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
use toml::{Table, Value};
|
||||||
|
|
||||||
|
use crate::config_file_parsing::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct TargetOptions<'a> {
|
||||||
|
pub inherit: bool,
|
||||||
|
pub inherit_from: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TargetOptions<'a> {
|
||||||
|
pub fn get_default() -> Self {
|
||||||
|
TargetOptions {
|
||||||
|
inherit: true,
|
||||||
|
inherit_from: "main",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn from_table(table: &'a Table, key_path: String) -> Result<Self, ConfigFileError<'a>> {
|
||||||
|
let mut ret = Self::get_default();
|
||||||
|
|
||||||
|
if let Some(v) = get_key_as_bool(table, "inherit", format!("{key_path}.inherit"))? {
|
||||||
|
ret.inherit = v;
|
||||||
|
}
|
||||||
|
if let Some(v) = get_key_as_str(table, "inherit_from", format!("{key_path}.inherit_from"))?
|
||||||
|
{
|
||||||
|
ret.inherit_from = v;
|
||||||
|
}
|
||||||
|
Ok(ret)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue