1use std::{
7 fs::File,
8 io::{Read, Seek},
9 path::PathBuf,
10};
11
12include!("clang_info.rs");
13
14const BPF_H: &str = "bpf_h";
15
16pub struct Builder;
17
18impl Builder {
19 pub fn new() -> Self {
20 Builder
21 }
22
23 fn gen_bpf_h(&self) {
24 let out_dir = env::var("OUT_DIR").unwrap();
25 let file = File::create(PathBuf::from(&out_dir).join(format!("{BPF_H}.tar"))).unwrap();
26 let mut ar = tar::Builder::new(file);
27
28 ar.follow_symlinks(false);
29 ar.append_dir_all(".", BPF_H).unwrap();
30
31 let vmlinux_dir = tempfile::tempdir().unwrap();
32 let mut vmlinux_tar_zst = File::open("vmlinux.tar.zst").unwrap();
33 let vmlinux_tar = ruzstd::decoding::StreamingDecoder::new(&mut vmlinux_tar_zst).unwrap();
34 tar::Archive::new(vmlinux_tar)
35 .unpack(vmlinux_dir.path())
36 .unwrap();
37 ar.append_dir_all(".", vmlinux_dir.path().join("vmlinux"))
38 .unwrap();
39
40 ar.finish().unwrap();
41
42 for ent in walkdir::WalkDir::new(BPF_H) {
43 let ent = ent.unwrap();
44 if !ent.file_type().is_dir() {
45 println!("cargo:rerun-if-changed={}", ent.path().to_string_lossy());
46 }
47 }
48 }
49
50 fn gen_bindings(&self) {
51 let out_dir = env::var("OUT_DIR").unwrap();
52 let clang = ClangInfo::new().unwrap();
53 let kernel_target = clang.kernel_target().unwrap();
54
55 let mut vmlinux_tar_zst = File::open("vmlinux.tar.zst").unwrap();
56
57 let mut vmlinux_h = String::new();
58
59 let search: PathBuf = format!("vmlinux/arch/{kernel_target}/vmlinux.h").into();
61
62 let mut vmlinux_tar =
63 ruzstd::decoding::StreamingDecoder::new(&mut vmlinux_tar_zst).unwrap();
64 let mut archive = tar::Archive::new(&mut vmlinux_tar);
65 let vmlinux_link_entry = archive
66 .entries()
67 .unwrap()
68 .find(|x| x.as_ref().unwrap().path().unwrap() == search.as_path())
69 .unwrap()
70 .unwrap();
71
72 let vmlinux_path = PathBuf::from(vmlinux_link_entry.path().unwrap())
73 .parent()
74 .unwrap()
75 .join(vmlinux_link_entry.link_name().unwrap().unwrap());
76
77 vmlinux_tar_zst.rewind().unwrap();
78 let vmlinux_tar = ruzstd::decoding::StreamingDecoder::new(&mut vmlinux_tar_zst).unwrap();
79
80 tar::Archive::new(vmlinux_tar)
81 .entries()
82 .unwrap()
83 .find(|x| x.as_ref().unwrap().path().unwrap() == vmlinux_path.as_path())
84 .unwrap()
85 .unwrap()
86 .read_to_string(&mut vmlinux_h)
87 .unwrap();
88
89 let bindings = bindgen::Builder::default()
90 .header_contents(&search.to_string_lossy(), &vmlinux_h)
91 .allowlist_type("scx_exit_kind")
92 .allowlist_type("scx_consts")
93 .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
94 .generate()
95 .expect("Unable to generate bindings");
96
97 bindings
98 .write_to_file(PathBuf::from(&out_dir).join("bindings.rs"))
99 .expect("Couldn't write bindings");
100 }
101
102 pub fn build(self) {
103 self.gen_bpf_h();
104 self.gen_bindings();
105 }
106}