add change to hash and build to hash and build each file independently (#12)

issue: #10
Reviewed-on: http://192.168.1.227:3000/sfrembling/pallet/pulls/12
Co-authored-by: godsfryingpan <sfrembling@gmail.com>
Co-committed-by: godsfryingpan <sfrembling@gmail.com>
This commit was merged in pull request #12.
This commit is contained in:
2026-03-23 11:00:40 -06:00
committed by sfrembling
parent f30432c1db
commit 94d6f5d54d

View File

@@ -248,53 +248,87 @@ fn build(mode: &Option<String>, force_recompile: bool) -> std::io::Result<()> {
let start = std::time::Instant::now(); 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 source_files: Vec<PathBuf> = glob("src/*.c")
let text = std::fs::read_to_string(old_compute_path)?; .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!( println!(
" {} (code not changed, recompile not made)", " {} (code not changed, recompile not made)",
"Finished".green().bold() "Finished".green().bold()
); );
return Ok(()); 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 { let status = Command::new(compiler)
command.arg(arg); .args(&obj_files)
}
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
.arg("-o") .arg("-o")
.arg(format!("target/{}/{}", build_config.name, conf.name)); .arg(&binary)
.status()?;
let status = command.status()?;
if !status.success() { if !status.success() {
return Err(std::io::Error::new( return Err(std::io::Error::new(
std::io::ErrorKind::Other, 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(); let stop = start.elapsed();
println!( println!(
@@ -308,16 +342,9 @@ fn build(mode: &Option<String>, force_recompile: bool) -> std::io::Result<()> {
Ok(()) Ok(())
} }
fn hash_src_tree() -> std::io::Result<String> { fn hash_file(path: &Path) -> std::io::Result<String> {
let mut hashes = String::new(); let contents = std::fs::read_to_string(path)?;
for entry in glob("src/**/*").expect("a valid glob pattern") { Ok(sha256::digest(contents))
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 run(mode: &Option<String>, args: Option<Vec<String>>) -> std::io::Result<()> { fn run(mode: &Option<String>, args: Option<Vec<String>>) -> std::io::Result<()> {