Skip to content

Commit

Permalink
refactor build script to support linux 3.12+
Browse files Browse the repository at this point in the history
  • Loading branch information
Thaumy committed Jan 25, 2024
1 parent 310c266 commit babadff
Show file tree
Hide file tree
Showing 6 changed files with 229 additions and 171 deletions.
19 changes: 17 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ license = "MIT"
repository = "https://github.com/OptimatistOpenSource/perf-event-rs.git"
keywords = ["binding", "event", "perf"]
categories = ["api-bindings"]
build = "build.rs"
build = "build/main.rs"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

Expand All @@ -22,7 +22,22 @@ build = "build.rs"
"linux-5.8" = ["linux-5.7"]
"linux-5.7" = ["linux-5.5"]
"linux-5.5" = ["linux-5.4"]
"linux-5.4" = []
"linux-5.4" = ["linux-5.1"]
"linux-5.1" = ["linux-4.17"]
"linux-4.17" = ["linux-4.16"]
"linux-4.16" = ["linux-4.14"]
"linux-4.14" = ["linux-4.12"]
"linux-4.12" = ["linux-4.8"]
"linux-4.8" = ["linux-4.7"]
"linux-4.7" = ["linux-4.4"]
"linux-4.4" = ["linux-4.3"]
"linux-4.3" = ["linux-4.2"]
"linux-4.2" = ["linux-4.1"]
"linux-4.1" = ["linux-3.19"]
"linux-3.19" = ["linux-3.16"]
"linux-3.16" = ["linux-3.13"]
"linux-3.13" = ["linux-3.12"]
"linux-3.12" = []

[build-dependencies]
bindgen = "0.68.1"
Expand Down
145 changes: 0 additions & 145 deletions build.rs

This file was deleted.

40 changes: 40 additions & 0 deletions build/consts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// [(major, patch_level, is_selected)]
#[rustfmt::skip]
pub const LINUX_FEATURE_VERSIONS: [(usize, usize, bool); 26] = [
(6, 3, cfg!(feature = "linux-6.3" )),
(6, 0, cfg!(feature = "linux-6.0" )),
(5,16, cfg!(feature = "linux-5.16")),
(5,13, cfg!(feature = "linux-5.13")),
(5,12, cfg!(feature = "linux-5.12")),
(5,11, cfg!(feature = "linux-5.11")),
(5, 9, cfg!(feature = "linux-5.9" )),
(5, 8, cfg!(feature = "linux-5.8" )),
(5, 7, cfg!(feature = "linux-5.7" )),
(5, 5, cfg!(feature = "linux-5.5" )),
(5, 4, cfg!(feature = "linux-5.4" )),
(5, 1, cfg!(feature = "linux-5.1" )),
(4,17, cfg!(feature = "linux-4.17")),
(4,16, cfg!(feature = "linux-4.16")),
(4,14, cfg!(feature = "linux-4.14")),
(4,12, cfg!(feature = "linux-4.12")),
(4, 8, cfg!(feature = "linux-4.8" )),
(4, 7, cfg!(feature = "linux-4.7" )),
(4, 4, cfg!(feature = "linux-4.4" )),
(4, 3, cfg!(feature = "linux-4.3" )),
(4, 2, cfg!(feature = "linux-4.2" )),
(4, 1, cfg!(feature = "linux-4.1" )),
(3,19, cfg!(feature = "linux-3.19")),
(3,16, cfg!(feature = "linux-3.16")),
(3,13, cfg!(feature = "linux-3.13")),
(3,12, cfg!(feature = "linux-3.12")),
];

// [(major, patch_level, enum_entry)]
#[rustfmt::skip]
pub const IOCTLS: [(usize, usize, &str); 5] = [
(3,12, "PERF_EVENT_IOCTL_ID = PERF_EVENT_IOC_ID," ),
(4, 1, "PERF_EVENT_IOCTL_SET_BPF = PERF_EVENT_IOC_SET_BPF," ),
(4, 7, "PERF_EVENT_IOCTL_PAUSE_OUTPUT = PERF_EVENT_IOC_PAUSE_OUTPUT," ),
(4,16, "PERF_EVENT_IOCTL_QUERY_BPF = PERF_EVENT_IOC_QUERY_BPF," ),
(4,17, "PERF_EVENT_IOCTL_MODIFY_ATTRIBUTES = PERF_EVENT_IOC_MODIFY_ATTRIBUTES,"),
];
90 changes: 90 additions & 0 deletions build/helpers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use crate::consts::IOCTLS;
use std::fs;

/// Parse `LINUX_VERSION_CODE` of `linux/version.h` to (major, patch_level, sub_level)
pub fn parse_linux_version_h(path: &str) -> (usize, usize, usize) {
let first_line = fs::read_to_string(path)
.unwrap_or_else(|_| panic!("Failed to read {}", path))
.lines()
.next()
.unwrap_or_else(|| panic!("No lines in {}", path))
.to_string();
let linux_version_code = first_line
.split(' ')
.nth(2)
.unwrap_or_else(|| panic!("Invalid line {}", first_line))
.to_string();
let linux_version_code = linux_version_code.parse::<usize>().unwrap_or_else(|e| {
panic!(
"Invalid LINUX_VERSION_CODE `{}` ({})",
linux_version_code, e
)
});

let major = linux_version_code >> 16;
let patch_lv = (linux_version_code & 65535) >> 8;
let sub_lv = linux_version_code & 255;
(major, patch_lv, sub_lv)
}

pub fn bindgen(linux_headers_path: &str, enabled_feature_versions: &[(usize, usize)]) {
let bindings_output_path = "src/syscall/bindings/bindgen.rs";
// Try delete `bindgen.rs` for every build
let _ = fs::remove_file(bindings_output_path);

let header_contents = {
let include_linux_bpf_h = if enabled_feature_versions.contains(&(5, 1)) {
"#include <linux/bpf.h>"
} else {
""
};
let enum_entries = enabled_feature_versions
.iter()
.fold(String::new(), |mut acc, it| {
IOCTLS.iter().try_for_each(|(m, p, str)| {
if *it == (*m, *p) {
acc.push_str(str);
None
} else {
Some(())
}
});
acc
});
format!(
"
#include <asm/unistd.h>
#include <linux/hw_breakpoint.h>
#include <linux/perf_event.h>
{}
enum perf_event_ioctls {{
PERF_EVENT_IOCTL_ENABLE = PERF_EVENT_IOC_ENABLE,
PERF_EVENT_IOCTL_DISABLE = PERF_EVENT_IOC_DISABLE,
PERF_EVENT_IOCTL_REFRESH = PERF_EVENT_IOC_REFRESH,
PERF_EVENT_IOCTL_RESET = PERF_EVENT_IOC_RESET,
PERF_EVENT_IOCTL_PERIOD = PERF_EVENT_IOC_PERIOD,
PERF_EVENT_IOCTL_SET_OUTPUT = PERF_EVENT_IOC_SET_OUTPUT,
PERF_EVENT_IOCTL_SET_FILTER = PERF_EVENT_IOC_SET_FILTER,
{}
}};",
include_linux_bpf_h, enum_entries,
)
};

let builder = bindgen::Builder::default()
.derive_default(true)
.generate_comments(false)
.prepend_enum_name(false)
.header_contents("wrapper.h", &header_contents);

if linux_headers_path != "/usr/include" {
builder.clang_arg(format!("-I{}", linux_headers_path))
} else {
builder
}
.generate()
.unwrap_or_else(|e| panic!("Failed to generate bindings: {}", e))
.write_to_file(bindings_output_path)
.unwrap_or_else(|e| panic!("Failed to write {}: {}", bindings_output_path, e));
}
82 changes: 82 additions & 0 deletions build/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
mod consts;
mod helpers;

extern crate bindgen;

use crate::consts::LINUX_FEATURE_VERSIONS;
use crate::helpers::{bindgen, parse_linux_version_h};
use std::env;
use std::path::Path;

fn main() {
// Check target OS
match env::var("CARGO_CFG_TARGET_OS") {
Ok(target_os) => match target_os.as_str() {
"linux" | "android" => {}
target_os => panic!("Invalid target OS: {:?}", target_os),
},
Err(e) => {
panic!("Unknown target OS: {}", e);
}
};

let linux_headers_path = if let Ok(path) = env::var("LINUX_HEADERS_PATH") {
let path = format!("{}/include", path);
let path = Path::new(&path).canonicalize().unwrap();
path.to_str().unwrap().to_string()
} else {
// TODO: get the right location of libc in the building system.
// as different linux distros have different locations of libc header files.
// on Ubuntu or Fedora, the default location is `/usr/include`
// while on other distros like nix, they may have different locations.
"/usr/include".to_string()
};

let linux_version_h_path = format!("{}/{}", linux_headers_path, "linux/version.h");
let (major, patch_level, sub_level) = parse_linux_version_h(&linux_version_h_path);

let selected_linux_feature_versions: Vec<(usize, usize)> = LINUX_FEATURE_VERSIONS
.into_iter()
.filter(|(.., is_selected)| *is_selected)
.map(|(m, p, _)| (m, p))
.collect();

let enabled_linux_features = if selected_linux_feature_versions.is_empty() {
// Apply default features based on parsed linux version
LINUX_FEATURE_VERSIONS
.into_iter()
.filter_map(|(m, p, _)| {
if (major == m && patch_level >= p) || major > m {
println!("cargo:rustc-cfg=feature=\"linux-{}.{}\"", m, p);
Some((m, p))
} else {
None
}
})
.collect()
} else {
// Features are manually selected by the user
// show warning if major or patch_level dose not match
let (selected_major, selected_patch_level) = selected_linux_feature_versions[0];
if selected_major != major || selected_patch_level != patch_level {
let selected_linux_feature =
format!("linux-{}.{}", selected_major, selected_patch_level,);
println!(
"cargo:warning=\
Selected feature `{}` may not compatible with compile against Linux version `{}.{}.{}`",
selected_linux_feature,
major,
patch_level,
sub_level,
);
println!(
"cargo:warning=\
To set another Linux headers path, run `LINUX_HEADERS_PATH=/path/to/directory cargo build --features {}`",
selected_linux_feature
);
}
selected_linux_feature_versions
};

bindgen(&linux_headers_path, &enabled_linux_features)
}
Loading

0 comments on commit babadff

Please sign in to comment.