extern crate bindgen;
extern crate pkg_config;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
fn generate_bindings() {
let pkg_names = [
"glx",
"x11",
"x11-xcb",
"xcursor",
"xext",
"xfixes",
"xft",
"xi",
"xinerama",
"xmu",
"xpresent",
"xrandr",
"xrender",
"xss",
"xt",
"xtst",
"xxf86vm",
];
let manifest_dir = PathBuf::from(std::env::var_os("CARGO_MANIFEST_DIR")
.expect("missing CARGO_MANIFEST_DIR"));
let lists_dir = manifest_dir.join("lists");
let out_dir = PathBuf::from(std::env::var_os("OUT_DIR").expect("missing OUT_DIR"));
let header_path = out_dir.join("header.h");
let bindings_path = out_dir.join("bindings.rs");
let mut header_file = File::create(&header_path).expect("can't create header");
let mut builder = bindgen::builder()
.allowlist_file(".*/GL/glx\\.h")
.allowlist_file(".*/GL/glxext\\.h")
.allowlist_file(".*/X11/\\.h");
let mut any_libs_enabled = false;
for pkg_name in pkg_names.into_iter() {
let lib_feature = format!("CARGO_FEATURE_{}", pkg_name.to_uppercase().replace("-", "_"));
let header_feature = format!("{}_HEADERS", lib_feature);
let pc_pkg_name = match pkg_name {
"xss" => "xscrnsaver",
_ => pkg_name,
};
if std::env::var_os(header_feature).is_some() {
let pkg = pkg_config::probe_library(pc_pkg_name).expect("can't probe package");
for dir in pkg.include_paths {
builder = builder.clang_arg(format!("-I{}", dir.display()));
}
let header_list_path = lists_dir.join(format!("{}-headers.txt", pkg_name));
let header_list_str = match std::fs::read_to_string(&header_list_path) {
Ok(s) => s,
Err(err) => panic!("{}: {}", header_list_path.display(), err),
};
for header in header_list_str.split_ascii_whitespace() {
writeln!(header_file, "#include <{}>", header).expect("write failed");
}
println!("cargo:rerun-if-changed={}", header_list_path.display());
if std::env::var_os(lib_feature).is_some() {
any_libs_enabled = true;
for lib in pkg.libs {
println!("cargo:rustc-link-lib={}", lib);
}
let fn_list_path = lists_dir.join(format!("{}-functions.txt", pkg_name));
let fn_list_str = match std::fs::read_to_string(&fn_list_path) {
Ok(s) => s,
Err(err) => panic!("{}: {}", fn_list_path.display(), err),
};
for fn_name in fn_list_str.split_ascii_whitespace() {
builder = builder.allowlist_function(fn_name);
}
println!("cargo:rerun-if-changed={}", fn_list_path.display());
let var_list_path = lists_dir.join(format!("{}-vars.txt", pkg_name));
let var_list_str = match std::fs::read_to_string(&var_list_path) {
Ok(s) => s,
Err(err) => panic!("{}: {}", var_list_path.display(), err),
};
for var_name in var_list_str.split_ascii_whitespace() {
builder = builder.allowlist_var(var_name);
}
println!("cargo:rerun-if-changed={}", var_list_path.display());
}
}
}
header_file.flush().expect("write failed");
std::mem::drop(header_file);
if !any_libs_enabled {
builder = builder.blocklist_function(".*");
}
builder.header(header_path.display().to_string())
.generate().expect("can't generate bindings")
.write_to_file(&bindings_path).expect("write failed");
}
fn main() {
if let Ok(target_os) = std::env::var("CARGO_CFG_TARGET_OS") {
match target_os.as_str() {
"dragonfly" | "freebsd" | "linux" | "netbsd" | "openbsd" => {
generate_bindings();
},
"macos" => {
if std::env::var_os("CARGO_FEATURE_MACOS").is_some() {
generate_bindings();
}
},
_ => (),
}
}
}