use std::collections::HashMap;
use std::env;
use std::fs::write;
use std::path::{Path, PathBuf};
fn generate_build_info_rs() {
let mut version_file_path =
PathBuf::from(&env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is not set"));
version_file_path.push("../VERSION");
println!("cargo:rerun-if-changed={}", version_file_path.display());
let version_file_content =
std::fs::read_to_string(version_file_path).unwrap_or_else(|_| String::new());
let key_values_from_version_file: HashMap<&str, &str> = version_file_content
.lines()
.filter_map(|l| l.split_once(':'))
.map(|(k, v)| (k.trim(), v.trim()))
.collect();
struct VersionVarInfo {
key: &'static str,
var: &'static str,
default: &'static str,
}
let keys_and_vars_defaults = [
VersionVarInfo {
key: "VERSION",
var: "VERSION",
default: "dev",
},
VersionVarInfo {
key: "GIT COMMIT",
var: "GIT_COMMIT",
default: "unknown",
},
VersionVarInfo {
key: "BUILD ID",
var: "BUILD_ID",
default: "unknown",
},
];
let build_info_rs_src = keys_and_vars_defaults
.iter()
.fold(String::new(), |mut acc, info| {
let value = key_values_from_version_file
.get(info.key)
.unwrap_or(&info.default);
acc.push_str(&format!("pub const {}: &str = \"{}\";\n", info.var, value));
acc
});
let out_dir = env::var_os("OUT_DIR").expect("OUT_DIR is not set");
let dest_path = Path::new(&out_dir).join("build_info.rs");
write(dest_path, build_info_rs_src).expect("Failed to write build_info.rs");
}
#[cfg(all(feature = "ebpf", not(target_os = "macos")))]
mod ebpf {
use std::{env, fs::write};
use std::{path::Path, process::Command};
struct EbpfProgram {
src_dir: &'static str,
out_key: &'static str,
out_name: &'static str,
}
impl EbpfProgram {
const fn new(src_dir: &'static str, out_key: &'static str, out_name: &'static str) -> Self {
EbpfProgram {
src_dir,
out_key,
out_name,
}
}
}
const PROGRAMS: [EbpfProgram; 1] = [EbpfProgram::new("ebpf/disk_io.c", "DISK_IO", "disk_io.o")];
pub fn build_ebpf() {
let cargo_dir = env::var_os("CARGO_MANIFEST_DIR")
.expect("CARGO_MANIFEST_DIR is not set")
.into_string()
.expect("Failed to convert to string");
let out_dir = env::var_os("OUT_DIR")
.expect("OUT_DIR is not set")
.into_string()
.expect("Failed to convert to string");
let mut ebpf_programs_rs_src = String::new();
ebpf_programs_rs_src.push_str("use aya::include_bytes_aligned;\n");
for program in &PROGRAMS {
println!("cargo:rerun-if-changed={}", program.src_dir);
let program_dir = format!("{}/{}", out_dir, program.out_name);
let clang_exit_status = Command::new("clang")
.args([
"-target",
"bpf",
"-O2",
"-c",
"-g",
&format!("{}/{}", &cargo_dir, program.src_dir),
"-o",
&program_dir,
])
.status()
.expect("Failed to execute clang");
if !clang_exit_status.success() {
panic!(
"Failed to build ebpf program {}: {}",
program.src_dir, clang_exit_status
);
}
let output_def = format!(
"pub const {}: &[u8] = include_bytes_aligned!(\"{}\");\n",
program.out_key, program_dir
);
ebpf_programs_rs_src.push_str(&output_def);
}
let out_dir = env::var_os("OUT_DIR")
.expect("OUT_DIR is not set")
.into_string()
.expect("Failed to convert to string");
let dest_path = Path::new(&out_dir).join("ebpf_programs.rs");
println!("Output ebpf: {:?}", dest_path);
write(dest_path, ebpf_programs_rs_src).expect("Failed to write ebpf_program.rs");
}
}
#[cfg(all(feature = "ebpf", target_os = "macos"))]
mod ebpf {
pub fn build_ebpf() {}
}
fn main() {
generate_build_info_rs();
#[cfg(feature = "ebpf")]
ebpf::build_ebpf();
println!("cargo:rerun-if-changed=build.rs");
}