-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor build script to support linux 3.12+
- Loading branch information
Showing
6 changed files
with
229 additions
and
171 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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,"), | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |
Oops, something went wrong.