use std::{
env::{self, current_dir},
ffi::OsString,
fs::{read_to_string, write},
process::{Command, exit}
};
#[cfg(not(any(unix, target_vendor = "apple")))]
compile_error!("snailx only supports Unix and macOS");
struct Version {
major: usize,
minor: usize
}
fn rust_version() -> Version {
let rustc = env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"));
let mut cmd = if let Some(wrapper) = env::var_os("RUSTC_WRAPPER").filter(|w| !w.is_empty()) {
let mut cmd = Command::new(wrapper);
cmd.arg(rustc);
cmd
} else {
Command::new(rustc)
};
let out = cmd.arg("-V").output().expect("failed to execute rustc to get version");
if !out.status.success() {
eprintln!("rustc execution failed: {}", String::from_utf8_lossy(&out.stderr));
exit(1);
}
let stdout = String::from_utf8(out.stdout).expect("rustc output was not valid UTF-8");
let mut parts = stdout
.trim()
.split(' ')
.nth(1)
.expect("rustc output did not contain version info")
.split('-')
.next()
.expect("rustc version info did not contain a version")
.splitn(3, '.');
let major = parts
.next()
.expect("rustc version did not contain a major version")
.parse()
.expect("rustc version major version was not a number");
let minor = parts
.next()
.expect("rustc version did not contain a minor version")
.parse()
.expect("rustc version minor version was not a number");
Version { major, minor }
}
fn main() {
let v = rust_version();
let cwd = current_dir().expect("failed to get current directory");
let raw_src = cwd.join("src");
let direct_src = raw_src.join("direct.rs.src");
println!("cargo:rerun-if-changed={}", raw_src.display());
println!("cargo:rerun-if-env-changed=RUSTC");
println!("cargo:rerun-if-env-changed=RUSTC_WRAPPER");
let src_contents = read_to_string(direct_src).expect("failed to read source file");
let generated = src_contents.as_str().replace(
"[Replace me with link section]",
if v.minor > 81 || v.major > 1 {
"#[unsafe(link_section = \".init_array.00098\")]"
} else {
"#[link_section = \".init_array.00098\"]"
}
);
let dst_path = raw_src.join("direct.rs");
if let Ok(existing) = read_to_string(&dst_path) {
if existing == generated {
exit(0);
}
}
write(&dst_path, generated.as_bytes()).expect("failed to write destination file");
}