99 lines
3.5 KiB
Rust
99 lines
3.5 KiB
Rust
//! Maintenance tasks for vlc-rs, invoked via `cargo xtask <task>`.
|
|
|
|
use std::path::{Path, PathBuf};
|
|
use std::process::ExitCode;
|
|
|
|
/// Minimum libvlc version the bindings target. Keep in sync with
|
|
/// `libvlc-sys/build.rs`.
|
|
const MIN_LIBVLC_VERSION: &str = "3.0.0";
|
|
|
|
fn main() -> ExitCode {
|
|
match std::env::args().nth(1).as_deref() {
|
|
Some("bindgen") => {
|
|
generate_bindings();
|
|
ExitCode::SUCCESS
|
|
}
|
|
_ => {
|
|
eprintln!("usage: cargo xtask <task>\n");
|
|
eprintln!("tasks:");
|
|
eprintln!(" bindgen regenerate libvlc-sys/bindings.rs from the system libvlc headers");
|
|
ExitCode::FAILURE
|
|
}
|
|
}
|
|
}
|
|
|
|
fn generate_bindings() {
|
|
let sys_dir = libvlc_sys_dir();
|
|
let header = sys_dir.join("wrapper.h");
|
|
let output = sys_dir.join("bindings.rs");
|
|
|
|
// Enforce the same minimum version the build script requires and pick up any
|
|
// header search paths.
|
|
let library = pkg_config::Config::new()
|
|
.atleast_version(MIN_LIBVLC_VERSION)
|
|
.cargo_metadata(false)
|
|
.probe("libvlc")
|
|
.unwrap_or_else(|e| panic!("libvlc >= {MIN_LIBVLC_VERSION} not found via pkg-config: {e}"));
|
|
|
|
let mut bindings = bindgen::Builder::default()
|
|
.header(header.to_str().expect("non-UTF-8 header path"))
|
|
// For no_std
|
|
.use_core()
|
|
// Use libc
|
|
.ctypes_prefix("libc")
|
|
// Allowlist every (lib)vlc symbol.
|
|
.allowlist_item("(lib|LIB)?(vlc|VLC)_.*")
|
|
// Avoid leaking unecessary glibc/platform specifics.
|
|
.blocklist_type("_IO_.*")
|
|
.blocklist_type("_iobuf")
|
|
.blocklist_type("FILE")
|
|
.blocklist_type("__off.*")
|
|
.blocklist_type("__uint64_t")
|
|
.raw_line("pub use libc::FILE;")
|
|
// Block the whole va_list family and rewrite the parameters bindings to our own `VaList`,
|
|
// which is ABI-correct on every target.
|
|
.blocklist_type(".*va_list.*")
|
|
.raw_line("pub use crate::valist::VaList;")
|
|
// These bindings are committed once and compiled everywhere, so the layout assertions would
|
|
// only ever encode the machine that ran bindgen.
|
|
.layout_tests(false)
|
|
// Emit a single extern block rather than one per function.
|
|
.merge_extern_blocks(true);
|
|
|
|
for path in &library.include_paths {
|
|
bindings = bindings.clang_arg(format!("-I{}", path.display()));
|
|
}
|
|
|
|
let generated = bindings
|
|
.generate()
|
|
.expect("unable to generate bindings")
|
|
.to_string();
|
|
|
|
let generated = generated
|
|
.replace("*mut __va_list_tag", "VaList")
|
|
.replace(": va_list", ": VaList");
|
|
assert!(
|
|
!generated.contains("va_list"),
|
|
"a va_list spelling we do not know about survived"
|
|
);
|
|
|
|
// On Windows rustc can synthesise the imports straight from the DLL, so no
|
|
// import library is needed. bindgen cannot emit the attribute itself.
|
|
let generated = generated.replace(
|
|
"unsafe extern \"C\" {",
|
|
"#[cfg_attr(windows, link(name = \"libvlc\", kind = \"raw-dylib\"))]\nunsafe extern \"C\" {",
|
|
);
|
|
|
|
std::fs::write(&output, generated).expect("couldn't write bindings");
|
|
println!("wrote {}", output.display());
|
|
}
|
|
|
|
/// Absolute path to the `libvlc-sys` crate directory, derived from this xtask's
|
|
/// location so it works regardless of the current working directory.
|
|
fn libvlc_sys_dir() -> PathBuf {
|
|
Path::new(env!("CARGO_MANIFEST_DIR"))
|
|
.parent()
|
|
.expect("xtask has no parent directory")
|
|
.join("libvlc-sys")
|
|
}
|