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