#[cfg(feature = "use_bindgen")]
mod use_bindgen {
use bindgen::{
callbacks::{DeriveTrait, ImplementsTrait, ParseCallbacks},
Builder, CodegenConfig,
};
use std::env::var;
use std::path::PathBuf;
#[derive(Debug)]
struct Callbacks;
impl ParseCallbacks for Callbacks {
fn blocklisted_type_implements_trait(
&self,
name: &str,
_derive_trait: DeriveTrait,
) -> Option<ImplementsTrait> {
if name == "__kernel_size_t" || name == "drm_handle_t" {
Some(ImplementsTrait::Yes)
} else {
None
}
}
}
fn create_builder(contents: &str) -> Builder {
println!("{}", contents);
let pkgconf = pkg_config::Config::new();
let include_paths = if let Ok(value) = var("LIBDRM_INCLUDE_PATH") {
vec![PathBuf::from(value)]
} else {
pkgconf.probe("libdrm").unwrap().include_paths
};
let config = CodegenConfig::all();
Builder::default()
.clang_args(
include_paths
.into_iter()
.map(|path| "-I".to_string() + &path.into_os_string().into_string().unwrap()),
)
.header_contents("bindings.h", contents)
.ctypes_prefix("core::ffi")
.with_codegen_config(config)
.prepend_enum_name(false)
.layout_tests(false)
.generate_comments(false)
.derive_copy(true)
.derive_debug(true)
.derive_default(true)
.derive_hash(true)
.derive_eq(true)
.allowlist_recursively(true)
.blocklist_type("__kernel_.*")
.blocklist_type("drm_handle_t")
.parse_callbacks(Box::new(Callbacks))
.use_core()
}
const TMP_BIND_PREFIX: &str = "__BINDGEN_TMP_";
const TMP_BIND_PREFIX_REG: &str = "_BINDGEN_TMP_.*";
const INCLUDES: &[&str] = &["drm.h", "drm_mode.h"];
const MACROS: &[&str] = &["DRM_MODE_PROP_SIGNED_RANGE", "DRM_MODE_PROP_OBJECT"];
fn apply_formatting<I, F>(iter: I, f: F) -> String
where
I: Iterator,
I::Item: AsRef<str>,
F: Fn(&str) -> String,
{
iter.fold(String::new(), |acc, x| acc + &f(x.as_ref()) + "\n")
}
fn tmp_val(name: &str) -> String {
format!("{}{}", TMP_BIND_PREFIX, name)
}
fn include(header: &str) -> String {
format!("#include <{}>", header)
}
fn decl_const(ty: &str, name: &str, value: &str) -> String {
format!("const {} {} = {};", ty, name, value)
}
fn define_macro(name: &str, val: &str) -> String {
format!("#define {} {}", name, val)
}
fn undefine_macro(name: &str) -> String {
format!("#undef {}", name)
}
fn rebind_macro(name: &str) -> String {
let tmp_name = tmp_val(name);
format!(
"{}\n{}\n{}\n{}",
decl_const("unsigned int", &tmp_name, name),
undefine_macro(name),
decl_const("unsigned int", name, &tmp_name),
define_macro(name, name)
)
}
fn create_header() -> String {
apply_formatting(INCLUDES.iter(), include) + &apply_formatting(MACROS.iter(), rebind_macro)
}
pub fn generate_bindings() {
let bindings = create_builder(&create_header())
.blocklist_type(TMP_BIND_PREFIX_REG)
.blocklist_type("drm_control_DRM_ADD_COMMAND")
.allowlist_type("_?DRM_.*|drm_.*|hdr_.*")
.allowlist_var("_?DRM_.*|drm_.*")
.constified_enum_module("drm_control_.*")
.constified_enum_module("drm_buf_desc_.*")
.constified_enum_module("drm_map_type")
.constified_enum_module("drm_map_flags")
.constified_enum_module("drm_stat_type")
.constified_enum_module("drm_lock_flags")
.constified_enum_module("drm_dma_flags")
.constified_enum_module("drm_ctx_flags")
.constified_enum_module("drm_drawable_info_type_t")
.constified_enum_module("drm_vblank_seq_type")
.constified_enum_module("drm_mode_subconnector")
.generate()
.expect("Unable to generate libdrm bindings");
let out_path = var("OUT_DIR").unwrap();
let bind_file = PathBuf::from(out_path).join("bindings.rs");
println!("cargo:rerun-if-changed={}", bind_file.display());
bindings
.write_to_file(bind_file)
.expect("Could not write bindings");
}
#[cfg(feature = "update_bindings")]
pub fn update_bindings() {
use std::fs;
let out_path = var("OUT_DIR").unwrap();
let bind_file = PathBuf::from(out_path).join("bindings.rs");
let dest_file = PathBuf::from("src/bindings.rs");
println!("cargo:rerun-if-changed={}", dest_file.display());
fs::copy(bind_file, &dest_file).unwrap();
}
}
#[cfg(feature = "use_bindgen")]
pub fn main() {
use_bindgen::generate_bindings();
#[cfg(feature = "update_bindings")]
use_bindgen::update_bindings();
}
#[cfg(not(feature = "use_bindgen"))]
pub fn main() {}