first commit; core functionality done

This commit is contained in:
Noah Swerhun 2024-03-03 21:46:19 -06:00
commit d35bc218fd
5 changed files with 323 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
/target
ngen.toml
build.ninja

145
Cargo.lock generated Normal file
View 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
View 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
View file

@ -0,0 +1,2 @@
cargo build --release
cp target/release/ngen ~/.local/bin

164
src/main.rs Normal file
View 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}"));
}