-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbuild.rs
More file actions
128 lines (110 loc) · 5.14 KB
/
Copy pathbuild.rs
File metadata and controls
128 lines (110 loc) · 5.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// build.rs — Cross-platform kernel build script
//
// Responsibilities:
// 1. Assemble architecture-specific assembly files with Clang.
// 2. Bundle the object files into a static archive that Cargo links.
// 3. Detect the host toolchain dynamically (no hardcoded paths).
// 4. Support both AArch64 and x86_64 targets.
//
// Prerequisites on the PATH:
// * clang (or clang-17, clang-16 etc. — we probe alternatives)
// * llvm-ar (preferred) or ar
use std::env;
use std::process::Command;
use std::path::Path;
fn main() {
let target = env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default();
// Tell Cargo which files should trigger a rebuild.
println!("cargo:rerun-if-changed=linker.ld");
println!("cargo:rerun-if-changed=linker_x86_64.ld");
println!("cargo:rerun-if-changed=boot.s");
println!("cargo:rerun-if-changed=boot_x86_64.s");
println!("cargo:rerun-if-changed=src/arch/context.s");
println!("cargo:rerun-if-changed=src/arch/exception.s");
println!("cargo:rerun-if-changed=src/arch/x86_64/context.s");
println!("cargo:rerun-if-changed=src/arch/x86_64/exception.s");
let out = env::var("OUT_DIR").expect("OUT_DIR not set");
let clang = find_tool(&["clang", "clang-17", "clang-16", "clang-15"])
.expect("Could not find `clang` on PATH. Install LLVM: https://releases.llvm.org/");
let archiver = find_tool(&["llvm-ar", "ar"])
.expect("Could not find `llvm-ar` or `ar` on PATH.");
match target.as_str() {
"aarch64" => build_aarch64(&clang, &archiver, &out),
"x86_64" => build_x86_64(&clang, &archiver, &out),
other => {
eprintln!("cargo:warning=Unsupported target architecture: {other}");
eprintln!("cargo:warning=Supported targets: aarch64-unknown-none, x86_64-unknown-none");
}
}
}
fn build_aarch64(clang: &str, archiver: &str, out: &str) {
let triple = "aarch64-unknown-none";
let boot_obj = format!("{out}/boot_aarch64.o");
let context_obj = format!("{out}/context_aarch64.o");
let exception_obj = format!("{out}/exception_aarch64.o");
asm(clang, triple, "boot.s", &boot_obj);
asm(clang, triple, "src/arch/context.s", &context_obj);
asm(clang, triple, "src/arch/exception.s", &exception_obj);
archive(archiver, out, "boot_obj_aarch64",
&[&boot_obj, &context_obj, &exception_obj]);
println!("cargo:rustc-link-lib=static=boot_obj_aarch64");
}
fn build_x86_64(clang: &str, archiver: &str, out: &str) {
let triple = "x86_64-unknown-none";
let boot_obj = format!("{out}/boot_x86_64.o");
let context_obj = format!("{out}/context_x86_64.o");
let exception_obj = format!("{out}/exception_x86_64.o");
// Only assemble files that exist — graceful if x86_64 stubs not yet written.
if Path::new("boot_x86_64.s").exists() {
asm(clang, triple, "boot_x86_64.s", &boot_obj);
}
if Path::new("src/arch/x86_64/context.s").exists() {
asm(clang, triple, "src/arch/x86_64/context.s", &context_obj);
}
if Path::new("src/arch/x86_64/exception.s").exists() {
asm(clang, triple, "src/arch/x86_64/exception.s", &exception_obj);
}
let mut objs: Vec<String> = Vec::new();
if Path::new("boot_x86_64.s").exists() { objs.push(boot_obj); }
if Path::new("src/arch/x86_64/context.s").exists() { objs.push(context_obj); }
if Path::new("src/arch/x86_64/exception.s").exists() { objs.push(exception_obj); }
if !objs.is_empty() {
let obj_refs: Vec<&str> = objs.iter().map(|s| s.as_str()).collect();
archive(archiver, out, "boot_obj_x86_64", &obj_refs);
println!("cargo:rustc-link-lib=static=boot_obj_x86_64");
}
}
// ── Helper functions ──────────────────────────────────────────────────────────
/// Invoke clang to assemble one `.s` file into a `.o` object.
fn asm(clang: &str, triple: &str, src: &str, obj: &str) {
let status = Command::new(clang)
.args([&format!("--target={triple}"), "-c", src, "-o", obj])
.status()
.unwrap_or_else(|_| panic!("Failed to run: {clang} --target={triple} -c {src}"));
if !status.success() {
panic!("Clang failed to assemble `{src}` for target `{triple}`");
}
}
/// Bundle object files into a `lib<name>.a` static archive.
fn archive(archiver: &str, out: &str, name: &str, objs: &[&str]) {
let archive_path = format!("{out}/lib{name}.a");
let mut args = vec!["rcs", &archive_path];
args.extend_from_slice(objs);
let status = Command::new(archiver)
.args(&args)
.status()
.unwrap_or_else(|_| panic!("Failed to run archiver: {archiver}"));
if !status.success() {
panic!("Archiver failed for `{name}`");
}
println!("cargo:rustc-link-search=native={out}");
}
/// Try each tool name in order; return the first one found on PATH.
fn find_tool(candidates: &[&str]) -> Option<String> {
for &name in candidates {
if Command::new(name).arg("--version").output().is_ok() {
return Some(name.to_string());
}
}
None
}