add change to hash and build to hash and build each file independently #12
101
src/app.rs
101
src/app.rs
@@ -248,53 +248,87 @@ fn build(mode: &Option<String>, force_recompile: bool) -> std::io::Result<()> {
|
||||
|
||||
let start = std::time::Instant::now();
|
||||
|
||||
std::fs::create_dir_all(format!("target/{}", build_config.name))?;
|
||||
let obj_dir = format!("target/{}/obj", build_config.name);
|
||||
|
||||
let hash = hash_src_tree()?;
|
||||
std::fs::create_dir_all(&obj_dir)?;
|
||||
|
||||
let old_compute_path = PathBuf::from(format!("target/{}/.build_hash", build_config.name));
|
||||
let compiler = conf.compiler.as_deref().unwrap_or("gcc");
|
||||
|
||||
if old_compute_path.exists() && !force_recompile {
|
||||
let text = std::fs::read_to_string(old_compute_path)?;
|
||||
let source_files: Vec<PathBuf> = glob("src/*.c")
|
||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::NotFound, format!("{e}")))?
|
||||
.filter_map(|e| e.ok())
|
||||
.collect();
|
||||
|
||||
if hash.trim() == text.trim() {
|
||||
let mut any_changed = false;
|
||||
|
||||
for src in &source_files {
|
||||
let stem = src.file_stem().unwrap().to_string_lossy();
|
||||
let obj_path = format!("{}/{}.o", obj_dir, stem);
|
||||
let hash_path = format!("{}/{}.c.hash", obj_dir, stem);
|
||||
|
||||
let hash = hash_file(src)?;
|
||||
|
||||
let needs_compile = force_recompile
|
||||
|| match std::fs::read_to_string(&hash_path) {
|
||||
Ok(old) => old.trim() != hash.trim(),
|
||||
Err(_) => true,
|
||||
};
|
||||
|
||||
if needs_compile {
|
||||
println!(" {} {}", "Compiling".green().bold(), src.display());
|
||||
|
||||
let status = Command::new(compiler)
|
||||
.args(&build_config.args)
|
||||
.arg("-c")
|
||||
.arg(src)
|
||||
.arg("-o")
|
||||
.arg(&obj_path)
|
||||
.status()?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!("failed to compile {}", src.display()),
|
||||
));
|
||||
}
|
||||
|
||||
std::fs::write(&hash_path, &hash)?;
|
||||
any_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
let binary = format!("target/{}/{}", build_config.name, conf.name);
|
||||
let binary_exists = PathBuf::from(&binary).exists();
|
||||
|
||||
if !any_changed && binary_exists {
|
||||
println!(
|
||||
" {} (code not changed, recompile not made)",
|
||||
"Finished".green().bold()
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
let mut command = Command::new(conf.compiler.as_deref().unwrap_or("gcc"));
|
||||
let obj_files: Vec<String> = source_files
|
||||
.iter()
|
||||
.map(|src| {
|
||||
let stem = src.file_stem().unwrap().to_string_lossy();
|
||||
format!("{}/{}.o", obj_dir, stem)
|
||||
})
|
||||
.collect();
|
||||
|
||||
for arg in &build_config.args {
|
||||
command.arg(arg);
|
||||
}
|
||||
|
||||
for entry in glob("src/*.c")
|
||||
.map_err(|e| std::io::Error::new(std::io::ErrorKind::NotFound, format!("{e}").as_str()))?
|
||||
{
|
||||
if let Ok(path) = entry {
|
||||
command.arg(path.to_string_lossy().to_string());
|
||||
}
|
||||
}
|
||||
|
||||
command
|
||||
let status = Command::new(compiler)
|
||||
.args(&obj_files)
|
||||
.arg("-o")
|
||||
.arg(format!("target/{}/{}", build_config.name, conf.name));
|
||||
|
||||
let status = command.status()?;
|
||||
.arg(&binary)
|
||||
.status()?;
|
||||
|
||||
if !status.success() {
|
||||
return Err(std::io::Error::new(
|
||||
std::io::ErrorKind::Other,
|
||||
format!("compiler exited with status {status}"),
|
||||
"linking failed",
|
||||
));
|
||||
}
|
||||
|
||||
std::fs::write(format!("target/{}/.build_hash", build_config.name), hash)?;
|
||||
|
||||
let stop = start.elapsed();
|
||||
|
||||
println!(
|
||||
@@ -308,16 +342,9 @@ fn build(mode: &Option<String>, force_recompile: bool) -> std::io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn hash_src_tree() -> std::io::Result<String> {
|
||||
let mut hashes = String::new();
|
||||
for entry in glob("src/**/*").expect("a valid glob pattern") {
|
||||
if let Ok(file) = entry {
|
||||
let text = std::fs::read_to_string(file)?;
|
||||
let hash = sha256::digest(text);
|
||||
hashes.push_str(hash.as_str());
|
||||
}
|
||||
}
|
||||
Ok(sha256::digest(hashes))
|
||||
fn hash_file(path: &Path) -> std::io::Result<String> {
|
||||
let contents = std::fs::read_to_string(path)?;
|
||||
Ok(sha256::digest(contents))
|
||||
}
|
||||
|
||||
fn run(mode: &Option<String>, args: Option<Vec<String>>) -> std::io::Result<()> {
|
||||
|
||||
Reference in New Issue
Block a user