#[cfg(feature = "use_bindgen")]
mod use_bindgen {
extern crate bindgen;
extern crate pkg_config;
use self::bindgen::{Builder, CodegenConfig};
use std::env::var;
use std::path::PathBuf;
fn create_builder(contents: &str) -> Builder {
println!("{}", contents);
let pkgconf = pkg_config::Config::new();
let lib = pkgconf.probe("libdrm").unwrap();
let config = CodegenConfig::all();
Builder::default()
.clang_args(
lib.include_paths
.into_iter()
.map(|path| "-I".to_string() + &path.into_os_string().into_string().unwrap()),
)
.header_contents("bindings.h", contents)
.ctypes_prefix("libc")
.with_codegen_config(config)
.prepend_enum_name(false)
.layout_tests(false)
.generate_comments(false)
.rustfmt_bindings(true)
.derive_copy(true)
.derive_debug(true)
.derive_default(true)
.derive_hash(true)
.derive_eq(true)
.allowlist_recursively(true)
.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_.*")
.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");
bindings
.write_to_file(bind_file)
.expect("Could not write bindings");
}
#[cfg(feature = "update_bindings")]
pub fn update_bindings() {
use std::{fs, io::Write};
let out_path = var("OUT_DIR").unwrap();
let bind_file = PathBuf::from(out_path).join("bindings.rs");
let dest_dir = PathBuf::from("src")
.join("platforms")
.join(var("CARGO_CFG_TARGET_OS").unwrap())
.join(var("CARGO_CFG_TARGET_ARCH").unwrap());
let dest_file = dest_dir.join("bindings.rs");
fs::create_dir_all(&dest_dir).unwrap();
fs::copy(&bind_file, &dest_file).unwrap();
if let Ok(github_env) = var("GITHUB_ENV") {
let mut env_file = fs::OpenOptions::new()
.create(true)
.append(true)
.open(github_env)
.unwrap();
writeln!(env_file, "DRM_SYS_BINDINGS_FILE={}", dest_file.display()).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() {
use std::{env::var, path::Path};
let target_os = var("CARGO_CFG_TARGET_OS").unwrap();
let target_arch = var("CARGO_CFG_TARGET_ARCH").unwrap();
let bindings_file = Path::new("src")
.join("platforms")
.join(&target_os)
.join(&target_arch)
.join("bindings.rs");
if bindings_file.is_file() {
println!(
"cargo:rustc-env=DRM_SYS_BINDINGS_PATH={}/{}",
target_os, target_arch
);
} else {
panic!(
"No prebuilt bindings for target OS `{}` and/or architecture `{}`. Try `use_bindgen` feature.",
target_os, target_arch
);
}
}