first commit; core functionality done
This commit is contained in:
commit
d35bc218fd
5 changed files with 323 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
/target
|
||||||
|
ngen.toml
|
||||||
|
build.ninja
|
145
Cargo.lock
generated
Normal file
145
Cargo.lock
generated
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "equivalent"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.14.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "2.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
|
||||||
|
dependencies = [
|
||||||
|
"equivalent",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ngen"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"toml",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.78"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.197"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.197"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_spanned"
|
||||||
|
version = "0.6.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.52"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.8.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_spanned",
|
||||||
|
"toml_datetime",
|
||||||
|
"toml_edit",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_datetime"
|
||||||
|
version = "0.6.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml_edit"
|
||||||
|
version = "0.22.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
|
"serde",
|
||||||
|
"serde_spanned",
|
||||||
|
"toml_datetime",
|
||||||
|
"winnow",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winnow"
|
||||||
|
version = "0.6.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
9
Cargo.toml
Normal file
9
Cargo.toml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "ngen"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
toml = "0.8.10"
|
2
install.sh
Normal file
2
install.sh
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
cargo build --release
|
||||||
|
cp target/release/ngen ~/.local/bin
|
164
src/main.rs
Normal file
164
src/main.rs
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
use core::panic;
|
||||||
|
use std::fs::{read, write};
|
||||||
|
use toml::{Table, Value};
|
||||||
|
|
||||||
|
fn print_tabs(num: usize) {
|
||||||
|
for _ in 0..num {
|
||||||
|
print!(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_table(table: &Table, depth: usize) {
|
||||||
|
for k in table.keys() {
|
||||||
|
match table.get(k) {
|
||||||
|
Some(v) => match v {
|
||||||
|
Value::Table(t) => {
|
||||||
|
print_tabs(depth);
|
||||||
|
println!("{k}:");
|
||||||
|
print_table(&t, depth + 1)
|
||||||
|
}
|
||||||
|
Value::String(s) => {
|
||||||
|
print_tabs(depth);
|
||||||
|
println!("{k}: {s}");
|
||||||
|
}
|
||||||
|
Value::Array(a) => {
|
||||||
|
print_tabs(depth);
|
||||||
|
println!("(array){k}:");
|
||||||
|
for element in a {
|
||||||
|
match element {
|
||||||
|
Value::String(s) => println!(" {}", s),
|
||||||
|
_ => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => continue,
|
||||||
|
},
|
||||||
|
None => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn target_generator(name: &str, config_table: &Table) -> String {
|
||||||
|
let mut ret = String::from("");
|
||||||
|
|
||||||
|
let clang = Value::String(String::from("clang"));
|
||||||
|
let blank = Value::String(String::from(""));
|
||||||
|
|
||||||
|
let compiler = match config_table.get("compiler").unwrap_or(&clang) {
|
||||||
|
Value::String(s) => s,
|
||||||
|
_ => panic!("fatal: {name}.compiler: invalid type (must be string)"),
|
||||||
|
};
|
||||||
|
let compiler_flags = match config_table.get("compiler_flags").unwrap_or(&blank) {
|
||||||
|
Value::String(s) => s,
|
||||||
|
_ => panic!("fatal: {name}.compiler_flags: invalid type (must be string)"),
|
||||||
|
};
|
||||||
|
let linker_flags = match config_table.get("linker_flags").unwrap_or(&blank) {
|
||||||
|
Value::String(s) => s,
|
||||||
|
_ => panic!("fatal: {name}.linker_flags: invalid type (must be string)"),
|
||||||
|
};
|
||||||
|
let linker_libs = match config_table.get("linker_libs").unwrap_or(&blank) {
|
||||||
|
Value::String(s) => s,
|
||||||
|
_ => panic!("fatal: {name}.linker_libs: invalid type (must be string)"),
|
||||||
|
};
|
||||||
|
let compiler_linker = Value::String(compiler.to_string());
|
||||||
|
let linker = match config_table.get("linker").unwrap_or(&compiler_linker) {
|
||||||
|
Value::String(s) => s,
|
||||||
|
_ => panic!("fatal: {name}.linker: invalid type (must be string)"),
|
||||||
|
};
|
||||||
|
|
||||||
|
ret.push_str(&format!(
|
||||||
|
r#"# BEGIN TARGET {name}
|
||||||
|
cflags_{name} = {compiler_flags}
|
||||||
|
linker_flags_{name} = {linker_flags}
|
||||||
|
linker_libs_{name} = {linker_libs}
|
||||||
|
rule cc_{name}
|
||||||
|
deps = gcc
|
||||||
|
depfile = $out.d
|
||||||
|
command = {compiler} $cflags_{name} -MD -MF $out.d -o $out -c $in
|
||||||
|
description = Building [{name}] object $out
|
||||||
|
rule link_{name}
|
||||||
|
command = {linker} $linker_flags_{name} -o $out $in $linker_libs_{name}
|
||||||
|
description = Linking [{name}] $out
|
||||||
|
|
||||||
|
build $builddir/{name}: mkdir
|
||||||
|
"#
|
||||||
|
));
|
||||||
|
let sources = config_table
|
||||||
|
.get("sources")
|
||||||
|
.unwrap_or_else(|| panic!("fatal: must provide sources"));
|
||||||
|
|
||||||
|
let mut source_list: Vec<String> = Vec::new();
|
||||||
|
|
||||||
|
match sources {
|
||||||
|
Value::Array(a) => {
|
||||||
|
for elem in a {
|
||||||
|
match elem {
|
||||||
|
Value::String(s) => {
|
||||||
|
let obj_name = format!("$builddir/{name}/{s}.o");
|
||||||
|
ret.push_str(&format!(
|
||||||
|
"build {obj_name}: cc_{name} {s} | build.ninja || $builddir/{name}\n"
|
||||||
|
));
|
||||||
|
source_list.push(obj_name);
|
||||||
|
}
|
||||||
|
_ => panic!(
|
||||||
|
"fatal: element in {name}.sources: invalid source type (must be a string)"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => panic!("fatal: {name}.sources: invalid sources type (must be a list of strings)"),
|
||||||
|
};
|
||||||
|
|
||||||
|
ret.push_str(&format!("\nbuild $builddir/{name}/{name}: link_{name} "));
|
||||||
|
ret.push_str(&source_list.join(" "));
|
||||||
|
ret.push_str(&format!(" \nbuild {name}: phony $builddir/{name}/{name}\n"));
|
||||||
|
ret.push_str(&format!("# END TARGET {name}\n\n"));
|
||||||
|
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let conf_file_name = "ngen.toml";
|
||||||
|
let conf_file_bytes =
|
||||||
|
read(conf_file_name).unwrap_or_else(|e| panic!("fatal: could not read file: {e}"));
|
||||||
|
let conf_file = String::from_utf8_lossy(&conf_file_bytes);
|
||||||
|
let conf = toml::from_str::<Table>(&conf_file)
|
||||||
|
.unwrap_or_else(|e| panic!("fatal: could not parse config file: {e}"));
|
||||||
|
|
||||||
|
let mut ninjafile = String::from(
|
||||||
|
r#"builddir = build
|
||||||
|
|
||||||
|
rule mkdir
|
||||||
|
command = mkdir -p $out
|
||||||
|
description = Creating directory $out
|
||||||
|
|
||||||
|
rule regen
|
||||||
|
command = ngen -f $in
|
||||||
|
generator = 1
|
||||||
|
description = Regenerating build.ninja
|
||||||
|
|
||||||
|
build build.ninja: regen ngen.toml
|
||||||
|
pool = console
|
||||||
|
|
||||||
|
"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
for k in conf.keys() {
|
||||||
|
match conf.get(k) {
|
||||||
|
Some(v) => match v {
|
||||||
|
Value::Table(t) => {
|
||||||
|
//print_table(&t, 0);
|
||||||
|
ninjafile.push_str(&target_generator(&k, &t));
|
||||||
|
}
|
||||||
|
Value::String(s) => {
|
||||||
|
println!("{k}: {s}");
|
||||||
|
}
|
||||||
|
_ => continue,
|
||||||
|
},
|
||||||
|
None => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write("build.ninja", ninjafile)
|
||||||
|
.unwrap_or_else(|e| panic!("fatal: could not write ninja file: {e}"));
|
||||||
|
}
|
Loading…
Reference in a new issue