Merge branch 'build/bindgen-cleanup' into 'master'

build: Build and bindings cleanups

See merge request videolan/vlc-rs!17
merge-requests/17/merge
Alaric Senat 2026-07-24 10:08:44 +02:00
commit 9ba4b1de76
9 changed files with 1450 additions and 3672 deletions

View File

@ -0,0 +1,2 @@
[alias]
xtask = "run --manifest-path xtask/Cargo.toml --"

1
.gitignore vendored
View File

@ -13,4 +13,5 @@
# Generated by Cargo
/target/
/libvlc-sys/target
/xtask/target
Cargo.lock

View File

@ -11,7 +11,8 @@ repository = "https://code.videolan.org/videolan/vlc-rs"
homepage = "https://code.videolan.org/videolan/vlc-rs"
license = "MIT"
readme = "README.md"
edition = "2018"
edition = "2021"
rust-version = "1.82"
[lib]
name = "vlc"
@ -21,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"]

View File

@ -10,7 +10,8 @@ documentation = "https://docs.rs/vlc-rs"
repository = "https://code.videolan.org/videolan/vlc-rs"
homepage = "https://code.videolan.org/videolan/vlc-rs"
license = "MIT"
edition = "2018"
edition = "2021"
rust-version = "1.82"
build = "build.rs"
[lib]
@ -21,12 +22,7 @@ crate-type = ["rlib"]
libc = "0.2"
[build-dependencies]
bindgen = {version = "0.59", optional = true }
pkg-config = "0.3"
[target.'cfg(target_os = "windows")'.build-dependencies]
vswhom = "0.1.0"
[features]
default = []
use-bindgen = ["bindgen"]

File diff suppressed because it is too large Load Diff

View File

@ -1,55 +1,12 @@
use std::env;
use std::path::PathBuf;
use pkg_config;
//! Build script for `libvlc-sys`, locates and links libvlc.
#[cfg(feature = "bindgen")]
fn generate_bindings() {
println!("cargo:rerun-if-changed=wrapper.h");
/// Minimum supported libvlc version.
const MIN_LIBVLC_VERSION: &str = "3.0.0";
let mut bindings = bindgen::Builder::default()
.header("wrapper.h")
// For no_std
.use_core()
// Use libc
.ctypes_prefix("libc")
// Whitelist
.whitelist_type(".*vlc.*")
.whitelist_function(".*vlc.*")
.whitelist_var(".*vlc.*")
.whitelist_function("vsnprintf")
.parse_callbacks(Box::new(bindgen::CargoCallbacks));
// Set header include paths
let pkg_config_library = pkg_config::Config::new().probe("libvlc").unwrap();
for include_path in &pkg_config_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!");
}
fn link_vlc_with_pkgconfig() -> Result<pkg_config::Library, pkg_config::Error> {
/// Locate libvlc via pkg-config.
fn probe_libvlc() -> Result<pkg_config::Library, pkg_config::Error> {
pkg_config::Config::new()
.print_system_libs(false)
.atleast_version(MIN_LIBVLC_VERSION)
.probe("libvlc")
}
@ -139,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 {
@ -163,21 +123,13 @@ mod windows {
}
fn main() {
// Binding generation
#[cfg(feature = "bindgen")]
generate_bindings();
#[cfg(not(feature = "bindgen"))]
copy_pregenerated_bindings();
// Link
if let Err(err) = link_vlc_with_pkgconfig() {
// 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();
#[cfg(not(target_os = "windows"))]
panic!("libvlc not found: {:?}", err);
panic!("libvlc (>= {}) not found: {:?}", MIN_LIBVLC_VERSION, err);
}
println!("cargo:rustc-link-lib=vlc");
}

View File

@ -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");

12
xtask/Cargo.toml 100644
View File

@ -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]

70
xtask/src/main.rs 100644
View File

@ -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")
}