Files

66 lines
3.2 KiB
Rust

// Generate syscall numbers and status codes from the C++ headers so Rust
// never becomes another hand-maintained copy of the syscall table.
//
// programs/include/Api/Syscall.hpp -> pub const SYS_*: u64
// kernel/src/Common/StatusCodes.hpp -> pub enum Status (positive values,
// matching montauk/statuscodes.h)
use std::env;
use std::fs;
use std::path::PathBuf;
fn main() {
let manifest = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let repo = manifest.join("../../..");
let syscall_hpp = repo.join("programs/include/Api/Syscall.hpp");
let status_hpp = repo.join("kernel/src/Common/StatusCodes.hpp");
println!("cargo:rerun-if-changed={}", syscall_hpp.display());
println!("cargo:rerun-if-changed={}", status_hpp.display());
let mut out = String::from("// @generated by montauk-rt/build.rs - do not edit.\n\n");
// static constexpr uint64_t SYS_NAME = 123; (decimal literals only)
let syscalls = fs::read_to_string(&syscall_hpp).expect("read Syscall.hpp");
let mut count = 0;
for line in syscalls.lines() {
let line = line.trim();
let Some(rest) = line.strip_prefix("static constexpr uint64_t SYS_") else { continue };
let Some((name, value)) = rest.split_once('=') else { continue };
let value = value.split(';').next().unwrap_or("").trim();
if value.is_empty() || !value.bytes().all(|b| b.is_ascii_digit()) {
continue;
}
out.push_str(&format!("pub const SYS_{}: u64 = {};\n", name.trim(), value));
count += 1;
}
assert!(count > 100, "parsed only {count} syscalls from {}", syscall_hpp.display());
// enum StatusCodes { Success = 0, GenericFailure = -1, ... };
let status = fs::read_to_string(&status_hpp).expect("read StatusCodes.hpp");
let body = status
.split_once("enum StatusCodes")
.and_then(|(_, rest)| rest.split_once('{'))
.and_then(|(_, rest)| rest.split_once('}'))
.map(|(body, _)| body)
.expect("enum StatusCodes not found");
out.push_str("\n/// Kernel status codes, stored positive like montauk/statuscodes.h.\n");
out.push_str("/// The kernel returns them negated; see [`Status::from_result`].\n");
out.push_str("#[derive(Clone, Copy, Debug, PartialEq, Eq)]\n#[repr(i32)]\npub enum Status {\n");
let mut variants = Vec::new();
for entry in body.split(',') {
let entry = entry.split("//").next().unwrap_or("").trim();
let Some((name, value)) = entry.split_once('=') else { continue };
let value: i32 = value.trim().parse().expect("status value");
out.push_str(&format!(" {} = {},\n", name.trim(), -value));
variants.push((name.trim().to_string(), -value));
}
out.push_str("}\n\nimpl Status {\n pub const fn from_code(code: i32) -> Status {\n match code {\n");
for (name, value) in &variants {
out.push_str(&format!(" {} => Status::{},\n", value, name));
}
out.push_str(" _ => Status::GenericFailure,\n }\n }\n}\n");
let dest = PathBuf::from(env::var("OUT_DIR").unwrap()).join("abi.rs");
fs::write(dest, out).expect("write abi.rs");
}