build: replace the use-bindgen feature with a `cargo xtask bindgen` tool
Generating the FFI bindings at consumer build time is unecessary. The `use-bindgen` Cargo feature was non-additive, and forced bindgen + libclang onto every build that opted in, for a decision that is really about the maintainer's environment, not the public API. Move binding generation out of the build entirely, following the xtask pattern[^1]: - build.rs is reduced to locating and linking libvlc. - Regeneration lives in a `xtask` crate, run with `cargo xtask bindgen`. [^1]: <https://github.com/matklad/cargo-xtask>merge-requests/17/head
parent
13e5713e30
commit
0d57a4e242
|
|
@ -0,0 +1,2 @@
|
|||
[alias]
|
||||
xtask = "run --manifest-path xtask/Cargo.toml --"
|
||||
|
|
@ -13,4 +13,5 @@
|
|||
# Generated by Cargo
|
||||
/target/
|
||||
/libvlc-sys/target
|
||||
/xtask/target
|
||||
Cargo.lock
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ crate-type = ["rlib"]
|
|||
libc = "0.2"
|
||||
libvlc-sys = { path = "libvlc-sys" }
|
||||
|
||||
[features]
|
||||
default = []
|
||||
use-bindgen = ["libvlc-sys/use-bindgen"]
|
||||
# `xtask` contains maintenance tools; keep it out of the workspace so normal
|
||||
# builds never compile it.
|
||||
[workspace]
|
||||
exclude = ["xtask"]
|
||||
|
|
|
|||
|
|
@ -22,12 +22,7 @@ crate-type = ["rlib"]
|
|||
libc = "0.2"
|
||||
|
||||
[build-dependencies]
|
||||
bindgen = { version = "0.72", optional = true }
|
||||
pkg-config = "0.3"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.build-dependencies]
|
||||
vswhom = "0.1.0"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
use-bindgen = ["bindgen"]
|
||||
|
|
|
|||
|
|
@ -1,54 +1,8 @@
|
|||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use pkg_config;
|
||||
//! Build script for `libvlc-sys`, locates and links libvlc.
|
||||
|
||||
/// Minimum supported libvlc version.
|
||||
const MIN_LIBVLC_VERSION: &str = "3.0.0";
|
||||
|
||||
#[cfg(feature = "bindgen")]
|
||||
fn generate_bindings(library: &pkg_config::Library) {
|
||||
println!("cargo:rerun-if-changed=wrapper.h");
|
||||
|
||||
let mut bindings = bindgen::Builder::default()
|
||||
.header("wrapper.h")
|
||||
// For no_std
|
||||
.use_core()
|
||||
// Use libc
|
||||
.ctypes_prefix("libc")
|
||||
// Allowlist every (lib)vlc symbol.
|
||||
.allowlist_item("(lib|LIB)?(vlc|VLC)_.*")
|
||||
// Required by the Windows `legacy_stdio_definitions` link workaround
|
||||
// (see `windows::link_vlc`).
|
||||
.allowlist_function("vsnprintf")
|
||||
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()));
|
||||
|
||||
// Set header include paths from the pkg-config probe.
|
||||
for include_path in &library.include_paths {
|
||||
bindings = bindings.clang_arg(format!("-I{}", include_path.display()));
|
||||
}
|
||||
|
||||
let bindings = bindings.generate().expect("Unable to generate bindings");
|
||||
|
||||
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||
bindings
|
||||
.write_to_file(out_path.join("bindings.rs"))
|
||||
.expect("Couldn't write bindings!");
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "bindgen"))]
|
||||
fn copy_pregenerated_bindings()
|
||||
{
|
||||
use std::fs;
|
||||
|
||||
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||
let crate_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
|
||||
fs::copy(
|
||||
crate_path.join("bindings.rs"),
|
||||
out_path.join("bindings.rs"),
|
||||
)
|
||||
.expect("Couldn't find pregenerated bindings!");
|
||||
}
|
||||
|
||||
/// Locate libvlc via pkg-config.
|
||||
fn probe_libvlc() -> Result<pkg_config::Library, pkg_config::Error> {
|
||||
pkg_config::Config::new()
|
||||
|
|
@ -142,8 +96,11 @@ mod windows {
|
|||
}
|
||||
),
|
||||
])
|
||||
.spawn()
|
||||
.unwrap();
|
||||
.status()
|
||||
.expect("Failed to run lib.exe")
|
||||
.success()
|
||||
.then_some(())
|
||||
.expect("lib.exe failed to generate the vlc import library");
|
||||
}
|
||||
|
||||
fn vlc_path() -> PathBuf {
|
||||
|
|
@ -166,22 +123,9 @@ mod windows {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
// Probe once and reuse the result for both binding generation (include
|
||||
// paths) and linking (pkg-config emits the link directives on success).
|
||||
let library = probe_libvlc();
|
||||
|
||||
// Binding generation
|
||||
#[cfg(feature = "bindgen")]
|
||||
generate_bindings(library.as_ref().expect(
|
||||
"pkg-config is required to locate the libvlc headers with the `bindgen` feature",
|
||||
));
|
||||
|
||||
#[cfg(not(feature = "bindgen"))]
|
||||
copy_pregenerated_bindings();
|
||||
|
||||
// Link. On success pkg-config has already emitted the link directives; only
|
||||
// the failure path needs handling.
|
||||
if let Err(err) = library {
|
||||
// On success pkg-config has already emitted the link directives; only the
|
||||
// failure path needs handling.
|
||||
if let Err(err) = probe_libvlc() {
|
||||
#[cfg(target_os = "windows")]
|
||||
windows::link_vlc();
|
||||
|
||||
|
|
|
|||
|
|
@ -3,4 +3,6 @@
|
|||
#![allow(non_snake_case)]
|
||||
#![no_std]
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
||||
// The bindings are a committed source file, regenerated out of band with
|
||||
// `cargo xtask bindgen`.
|
||||
include!("../bindings.rs");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
[package]
|
||||
name = "xtask"
|
||||
version = "0.0.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
bindgen = "0.72"
|
||||
pkg-config = "0.3"
|
||||
|
||||
# Standalone from the vlc-rs workspace, kept out of the normal build graph.
|
||||
[workspace]
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
//! 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)_.*")
|
||||
// Required by the Windows `legacy_stdio_definitions` link workaround
|
||||
// (see libvlc-sys/build.rs).
|
||||
.allowlist_function("vsnprintf");
|
||||
|
||||
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();
|
||||
|
||||
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")
|
||||
}
|
||||
Loading…
Reference in New Issue