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
|
# Generated by Cargo
|
||||||
/target/
|
/target/
|
||||||
/libvlc-sys/target
|
/libvlc-sys/target
|
||||||
|
/xtask/target
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ crate-type = ["rlib"]
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
libvlc-sys = { path = "libvlc-sys" }
|
libvlc-sys = { path = "libvlc-sys" }
|
||||||
|
|
||||||
[features]
|
# `xtask` contains maintenance tools; keep it out of the workspace so normal
|
||||||
default = []
|
# builds never compile it.
|
||||||
use-bindgen = ["libvlc-sys/use-bindgen"]
|
[workspace]
|
||||||
|
exclude = ["xtask"]
|
||||||
|
|
|
||||||
|
|
@ -22,12 +22,7 @@ crate-type = ["rlib"]
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
bindgen = { version = "0.72", optional = true }
|
|
||||||
pkg-config = "0.3"
|
pkg-config = "0.3"
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.build-dependencies]
|
[target.'cfg(target_os = "windows")'.build-dependencies]
|
||||||
vswhom = "0.1.0"
|
vswhom = "0.1.0"
|
||||||
|
|
||||||
[features]
|
|
||||||
default = []
|
|
||||||
use-bindgen = ["bindgen"]
|
|
||||||
|
|
|
||||||
|
|
@ -1,54 +1,8 @@
|
||||||
use std::env;
|
//! Build script for `libvlc-sys`, locates and links libvlc.
|
||||||
use std::path::PathBuf;
|
|
||||||
use pkg_config;
|
|
||||||
|
|
||||||
/// Minimum supported libvlc version.
|
/// Minimum supported libvlc version.
|
||||||
const MIN_LIBVLC_VERSION: &str = "3.0.0";
|
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.
|
/// Locate libvlc via pkg-config.
|
||||||
fn probe_libvlc() -> Result<pkg_config::Library, pkg_config::Error> {
|
fn probe_libvlc() -> Result<pkg_config::Library, pkg_config::Error> {
|
||||||
pkg_config::Config::new()
|
pkg_config::Config::new()
|
||||||
|
|
@ -142,8 +96,11 @@ mod windows {
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
.spawn()
|
.status()
|
||||||
.unwrap();
|
.expect("Failed to run lib.exe")
|
||||||
|
.success()
|
||||||
|
.then_some(())
|
||||||
|
.expect("lib.exe failed to generate the vlc import library");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vlc_path() -> PathBuf {
|
fn vlc_path() -> PathBuf {
|
||||||
|
|
@ -166,22 +123,9 @@ mod windows {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Probe once and reuse the result for both binding generation (include
|
// On success pkg-config has already emitted the link directives; only the
|
||||||
// paths) and linking (pkg-config emits the link directives on success).
|
// failure path needs handling.
|
||||||
let library = probe_libvlc();
|
if let Err(err) = 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 {
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
windows::link_vlc();
|
windows::link_vlc();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,6 @@
|
||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
#![no_std]
|
#![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