use std::env;
use std::fs;
use std::io::Write;
use std::path::PathBuf;
use std::process::Command;
fn run_git(args: &[&str]) -> Option<String> {
let out = Command::new("git").args(args).output().ok()?;
if !out.status.success() {
return None;
}
Some(String::from_utf8_lossy(&out.stdout).trim().to_string())
}
fn resolve_git_dir_from(repo_dir: &PathBuf) -> Option<PathBuf> {
let mut cur = repo_dir.clone();
loop {
let dot_git = cur.join(".git");
if dot_git.is_dir() {
return Some(dot_git);
}
if dot_git.is_file() {
// Worktree style: ".git" file contains "gitdir: <path>"
let s = fs::read_to_string(&dot_git).ok()?;
let line = s.lines().next()?.trim();
let p = line.strip_prefix("gitdir:")?.trim();
let gitdir = if PathBuf::from(p).is_absolute() {
PathBuf::from(p)
} else {
cur.join(p)
};
return Some(gitdir);
}
if !cur.pop() {
return None;
}
}
}
fn main() {
let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let crate_dir = PathBuf::from(crate_dir);
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=aarch64.lds");
println!("cargo:rerun-if-env-changed=XTASK_BUILD");
println!("cargo:rerun-if-env-changed=RUSTFLAGS");
println!("cargo:rerun-if-env-changed=CARGO_ENCODED_RUSTFLAGS");
println!("cargo:rerun-if-env-changed=GITHUB_SHA");
// Best-effort: rerun build script when HEAD/index changes (works for normal repo/worktree).
if let Some(git_dir) = resolve_git_dir_from(&crate_dir) {
let head = git_dir.join("HEAD");
if head.exists() {
println!("cargo:rerun-if-changed={}", head.display());
}
let index = git_dir.join("index");
if index.exists() {
println!("cargo:rerun-if-changed={}", index.display());
}
}
// Prefer CI-provided SHA, fallback to local git.
let git_sha = env::var("GITHUB_SHA")
.ok()
.filter(|s| !s.trim().is_empty())
.or_else(|| run_git(&["rev-parse", "HEAD"]))
.unwrap_or_else(|| "unknown".to_string());
let git_sha_short = if git_sha != "unknown" && git_sha.len() >= 12 {
git_sha[..12].to_string()
} else {
git_sha.clone()
};
let git_dirty = run_git(&["status", "--porcelain"])
.map(|s| !s.is_empty())
.unwrap_or(false);
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let dst = out_dir.join("build_info.rs");
let mut f = fs::File::create(&dst).unwrap();
writeln!(f, "// @generated by bootloader/build.rs").unwrap();
writeln!(f, "pub const BUILD_GIT_SHA: &str = {:?};", git_sha).unwrap();
writeln!(
f,
"pub const BUILD_GIT_SHA_SHORT: &str = {:?};",
git_sha_short
)
.unwrap();
writeln!(f, "pub const BUILD_GIT_DIRTY: bool = {:?};", git_dirty).unwrap();
// Keep existing link behavior.
println!("cargo:rustc-link-search={}", crate_dir.display());
let rustflags = env::var("RUSTFLAGS").unwrap_or_default();
let encoded_rustflags = env::var("CARGO_ENCODED_RUSTFLAGS").unwrap_or_default();
let has_test_lds = rustflags.contains("test.lds") || encoded_rustflags.contains("test.lds");
if !has_test_lds {
let rpi4_lds = env::var_os("CARGO_FEATURE_RPI4").is_some();
let script = if rpi4_lds {
"aarch64-rpi4.lds"
} else {
"aarch64.lds"
};
println!("cargo:rustc-link-arg=-T{script}");
}
}