main functionality done, working
This commit is contained in:
parent
9f46b676f7
commit
58d33da293
2 changed files with 114 additions and 25 deletions
|
@ -6,5 +6,5 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "4.4.4", features = ["derive"] }
|
clap = { version = "4.4.4", default_features = false, features = ["derive", "help", "usage", "std", "error-context", "suggestions"] }
|
||||||
regex = "1.9.5"
|
regex = "1.9.5"
|
||||||
|
|
135
src/main.rs
135
src/main.rs
|
@ -1,13 +1,14 @@
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::Read;
|
use std::io::{Read, Write};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct CFile {
|
struct CFile {
|
||||||
path: String,
|
file_path: String,
|
||||||
filename: String,
|
obj_path: String,
|
||||||
|
obj_name: String,
|
||||||
headers: Vec<String>,
|
headers: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,29 +18,36 @@ struct Args {
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
pretty: bool,
|
pretty: bool,
|
||||||
|
|
||||||
|
/// Path to makefile
|
||||||
|
#[arg(short, long, default_value = "./Makefile")]
|
||||||
|
makefile: String,
|
||||||
|
|
||||||
|
/// Directory to place build files
|
||||||
#[arg(default_value = "./build")]
|
#[arg(default_value = "./build")]
|
||||||
build_dir: String,
|
build_dir: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_c_file(path: &Path, re: &Regex) -> CFile {
|
fn parse_c_file(path: &Path, obj_dir: &Path, re: &Regex) -> CFile {
|
||||||
let strpath = path.to_str().unwrap();
|
|
||||||
let filename = path.file_stem().unwrap().to_str().unwrap();
|
|
||||||
|
|
||||||
let mut file_handle = fs::File::open(path).unwrap();
|
let mut file_handle = fs::File::open(path).unwrap();
|
||||||
let mut contents = String::new();
|
let mut contents = String::new();
|
||||||
file_handle.read_to_string(&mut contents).unwrap();
|
file_handle.read_to_string(&mut contents).unwrap();
|
||||||
|
|
||||||
let mut headers: Vec<String> = Vec::new();
|
let mut headers: Vec<String> = Vec::new();
|
||||||
let caps = re.captures_iter(&contents);
|
let captures = re.captures_iter(&contents);
|
||||||
for (_, [include_file]) in caps.map(|c| c.extract()) {
|
for (_, [include_file]) in captures.map(|c| c.extract()) {
|
||||||
headers.push(path.parent().unwrap()
|
headers.push(path.parent().unwrap()
|
||||||
.join(Path::new(include_file))
|
.join(Path::new(include_file))
|
||||||
.to_str().unwrap()
|
.to_str().unwrap()
|
||||||
.to_string());
|
.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
return CFile { path: strpath.to_string(), filename: filename.to_string(), headers }
|
let obj_path = obj_dir.join(Path::new(path.file_name().unwrap()).with_extension("o"));
|
||||||
|
return CFile {
|
||||||
|
file_path: path.to_str().unwrap().to_string(),
|
||||||
|
obj_path: obj_path.to_str().unwrap().to_string(),
|
||||||
|
obj_name: obj_path.file_name().unwrap().to_str().unwrap().to_string(),
|
||||||
|
headers
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn recurse_into_dir<F: FnMut(fs::DirEntry)>(path: &Path, file_callback: &mut F) {
|
fn recurse_into_dir<F: FnMut(fs::DirEntry)>(path: &Path, file_callback: &mut F) {
|
||||||
|
@ -66,14 +74,13 @@ fn recurse_into_dir<F: FnMut(fs::DirEntry)>(path: &Path, file_callback: &mut F)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut project_files: Vec<CFile> = Vec::new();
|
|
||||||
let includes_regex = Regex::new(r#"#include\s+"(.*?)""#).unwrap();
|
|
||||||
|
|
||||||
let args = Args::parse();
|
let args = Args::parse();
|
||||||
let build_dir = Path::new(&args.build_dir);
|
let build_dir = Path::new(&args.build_dir);
|
||||||
let pretty = args.pretty;
|
let pretty = args.pretty;
|
||||||
|
|
||||||
|
let mut project_files: Vec<CFile> = Vec::new();
|
||||||
let obj_dir = build_dir.join("obj");
|
let obj_dir = build_dir.join("obj");
|
||||||
|
let includes_regex = Regex::new(r#"#include\s+"(.*?)""#).unwrap();
|
||||||
|
|
||||||
recurse_into_dir(Path::new("./"), &mut |file| {
|
recurse_into_dir(Path::new("./"), &mut |file| {
|
||||||
let path = file.path();
|
let path = file.path();
|
||||||
|
@ -83,7 +90,7 @@ fn main() {
|
||||||
if v != "c" {
|
if v != "c" {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
project_files.push(parse_c_file(&path, &includes_regex));
|
project_files.push(parse_c_file(&path, &obj_dir, &includes_regex));
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
return;
|
return;
|
||||||
|
@ -91,21 +98,103 @@ fn main() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if !Path::new(&args.makefile).exists() {
|
||||||
|
fs::File::create(&args.makefile).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut makefile_handle = fs::OpenOptions::new()
|
||||||
|
.read(true)
|
||||||
|
.open(args.makefile.clone()).unwrap();
|
||||||
|
let mut makefile = String::new();
|
||||||
|
makefile_handle.read_to_string(&mut makefile).unwrap();
|
||||||
|
|
||||||
|
let start_key = "#=mgen_start=#";
|
||||||
|
let end_key = "#=mgen_end=#";
|
||||||
|
|
||||||
|
let mut build_rules = String::new();
|
||||||
|
|
||||||
|
build_rules.push_str(&start_key);
|
||||||
|
|
||||||
|
build_rules.push_str("\n");
|
||||||
|
|
||||||
|
let target_path = build_dir.join(Path::new("$(TARGET)"));
|
||||||
|
let target_path = target_path.to_str().unwrap();
|
||||||
|
|
||||||
|
build_rules.push_str(&format!("{}: ", target_path));
|
||||||
for file in project_files.iter() {
|
for file in project_files.iter() {
|
||||||
let mut build_rule: String = "#=mgen_rule=#\n".to_owned();
|
build_rules.push_str(&format!(" {}", file.obj_path));
|
||||||
|
}
|
||||||
|
build_rules.push_str("\n");
|
||||||
|
|
||||||
let objname = file.filename.to_owned() + ".o";
|
if pretty {
|
||||||
let objpath = obj_dir.join(&objname);
|
build_rules.push_str(&format!("\t@printf ':: Linking %s ... ' $(TARGET)\n"));
|
||||||
let objpath = objpath.to_str().unwrap();
|
}
|
||||||
|
|
||||||
build_rule.push_str(&format!("{}: {}", objpath, file.path));
|
build_rules.push_str(&format!("\t{}$(CC) $(LDFLAGS) -o {} ",
|
||||||
|
if pretty {"@"} else {""}, target_path));
|
||||||
|
for file in project_files.iter() {
|
||||||
|
build_rules.push_str(&format!(" {}", file.obj_path));
|
||||||
|
}
|
||||||
|
build_rules.push_str(" $(LDLIBS)\n");
|
||||||
|
|
||||||
|
if pretty {
|
||||||
|
build_rules.push_str(&format!("\t@printf 'done\\n'\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
for file in project_files.iter() {
|
||||||
|
let mut build_rule = String::new();
|
||||||
|
|
||||||
|
build_rule.push_str("\n");
|
||||||
|
|
||||||
|
build_rule.push_str(&format!("{}: {}", file.obj_path, file.file_path));
|
||||||
for header in file.headers.iter() {
|
for header in file.headers.iter() {
|
||||||
build_rule.push_str(&format!(" {}", header));
|
build_rule.push_str(&format!(" {}", header));
|
||||||
}
|
}
|
||||||
|
build_rule.push_str("\n");
|
||||||
|
|
||||||
build_rule.push_str(&format!("\n\t$(CC) $(CFLAGS) -o {} -c {}\n", objpath, file.path ));
|
if pretty {
|
||||||
|
build_rule.push_str(&format!("\t@printf ':: Building {} ... '\n",
|
||||||
println!("'{}'", build_rule);
|
file.obj_name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
build_rule.push_str(&format!("\t{}$(CC) $(CFLAGS) -o {} -c {}\n",
|
||||||
|
if pretty {"@"} else {""},
|
||||||
|
file.obj_path, file.file_path ));
|
||||||
|
|
||||||
|
if pretty {
|
||||||
|
build_rule.push_str(&format!("\t@printf 'done\\n'\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
build_rules.push_str(&build_rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
build_rules.push_str(&end_key);
|
||||||
|
|
||||||
|
if let Some(start) = makefile.find(start_key) {
|
||||||
|
if let Some(end) = makefile.find(end_key) {
|
||||||
|
let mut makefile_handle = fs::OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.truncate(true)
|
||||||
|
.open(&args.makefile).unwrap();
|
||||||
|
makefile.replace_range(start..(end+end_key.len()), &build_rules);
|
||||||
|
makefile_handle.write(makefile.as_bytes()).unwrap();
|
||||||
|
makefile_handle.flush().unwrap();
|
||||||
|
} else {
|
||||||
|
panic!("Makefile corrupted. Missing `#=mgen_end=#`, but `#=mgen_start=#` is present. Cannot perform replacement")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let Some(_) = makefile.find(end_key) {
|
||||||
|
panic!("Makefile corrupted. Missing `#=mgen_start=#`, but `#=mgen_end=#` is present. Cannot perform replacement")
|
||||||
|
} else {
|
||||||
|
let mut makefile_handle = fs::OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.truncate(true)
|
||||||
|
.open(&args.makefile).unwrap();
|
||||||
|
makefile.push_str("\n");
|
||||||
|
makefile.push_str(&build_rules);
|
||||||
|
makefile_handle.write(makefile.as_bytes()).unwrap();
|
||||||
|
makefile_handle.flush().unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue