diff --git a/Cargo.lock b/Cargo.lock index 647b3b6..8ef6810 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,22 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "cc" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "509591b7bcd67f4ef775afad7662703b4935daaa6ec0e5605cfb1090b32a2b6d" -dependencies = [ - "find-msvc-tools", - "shlex", -] - -[[package]] -name = "find-msvc-tools" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890" - [[package]] name = "libc" version = "0.2.189" @@ -30,7 +14,6 @@ version = "0.2.0" dependencies = [ "libc", "pkg-config", - "vswhom", ] [[package]] @@ -39,12 +22,6 @@ version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" -[[package]] -name = "shlex" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" - [[package]] name = "vlc-rs" version = "0.3.0" @@ -52,23 +29,3 @@ dependencies = [ "libc", "libvlc-sys", ] - -[[package]] -name = "vswhom" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" -dependencies = [ - "libc", - "vswhom-sys", -] - -[[package]] -name = "vswhom-sys" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150" -dependencies = [ - "cc", - "libc", -] diff --git a/libvlc-sys/Cargo.toml b/libvlc-sys/Cargo.toml index b263112..0e1e870 100644 --- a/libvlc-sys/Cargo.toml +++ b/libvlc-sys/Cargo.toml @@ -23,6 +23,3 @@ libc = "0.2" [build-dependencies] pkg-config = "0.3" - -[target.'cfg(target_os = "windows")'.build-dependencies] -vswhom = "0.1.0" diff --git a/libvlc-sys/bindings.rs b/libvlc-sys/bindings.rs index 9cd88a7..0fb8651 100644 --- a/libvlc-sys/bindings.rs +++ b/libvlc-sys/bindings.rs @@ -1610,6 +1610,7 @@ const _: () = { ["Offset of field: libvlc_log_message_t::psz_message"] [::core::mem::offset_of!(libvlc_log_message_t, psz_message) - 32usize]; }; +#[cfg_attr(windows, link(name = "libvlc", kind = "raw-dylib"))] unsafe extern "C" { pub fn libvlc_errmsg() -> *const libc::c_char; pub fn libvlc_clearerr(); diff --git a/libvlc-sys/build.rs b/libvlc-sys/build.rs index dd3eb63..30a7056 100644 --- a/libvlc-sys/build.rs +++ b/libvlc-sys/build.rs @@ -1,5 +1,7 @@ //! Build script for `libvlc-sys`, locates and links libvlc. +use std::env; + /// Minimum supported libvlc version. const MIN_LIBVLC_VERSION: &str = "3.0.0"; @@ -10,126 +12,21 @@ fn probe_libvlc() -> Result { .probe("libvlc") } -#[cfg(target_os = "windows")] -mod windows { - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] - compile_error!("Only x86 and x86_64 are supported at the moment. Adding support for other architectures should be trivial."); - - use std::env; - use std::ffi::OsString; - use std::fs; - use std::path::{Path, PathBuf}; - use std::process::Command; - - use vswhom::VsFindResult; - - pub fn link_vlc() { - let vlc_path = vlc_path(); - - let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap()); - - let vs = VsFindResult::search().expect("Could not locate Visual Studio"); - let vs_exe_path = PathBuf::from( - vs.vs_exe_path - .expect("Could not retrieve executable path for Visual Studio"), - ); - - generate_lib_from_dll(&out_dir, &vs_exe_path, &vlc_path); - println!("cargo:rustc-link-search=native={}", out_dir.display()); - // NOTE: Without this directive, linking fails with: - // ``` - // error LNK2019: unresolved external symbol vsnprintf referenced in function _{MangledSymbolName} - // msvcrt.lib(vsnprintf.obj) : error LNK2001: unresolved external symbol vsnprintf - // msvcrt.lib(vsnprintf.obj) : error LNK2001: unresolved external symbol _vsnprintf - // ``` - // https://stackoverflow.com/a/34230122 +fn main() { + // vsnprintf is inlined by the UCRT headers, so MSVC needs this to resolve + // the symbol src/lib.rs declares. https://stackoverflow.com/a/34230122 + if env::var("CARGO_CFG_TARGET_ENV").unwrap_or_default() == "msvc" { println!("cargo:rustc-link-lib=dylib=legacy_stdio_definitions"); } - fn generate_lib_from_dll(out_dir: &Path, vs_exe_path: &Path, vlc_path: &Path) { - // https://wiki.videolan.org/GenerateLibFromDll/ - - let vs_dumpbin = vs_exe_path.join("dumpbin.exe"); - let vs_lib = vs_exe_path.join("lib.exe"); - let vlc_def_path = out_dir.join("libvlc.def"); - let vlc_import_lib = out_dir.join("vlc.lib"); - - let libvlc = vlc_path.join("libvlc.dll"); - let exports = Command::new(vs_dumpbin) - .current_dir(out_dir) - .arg("/EXPORTS") - .arg(libvlc.display().to_string().trim_end_matches(r"\")) - .output() - .unwrap(); - let exports = String::from_utf8(exports.stdout).unwrap(); - - let mut vlc_def = String::from("EXPORTS\n"); - for line in exports.lines() { - if let Some(line) = line.get(26..) { - if line.starts_with("libvlc_") { - vlc_def.push_str(line); - vlc_def.push_str("\r\n"); - } - } - } - fs::write(&vlc_def_path, vlc_def.into_bytes()).unwrap(); - - // FIXME: Handle paths with spaces in them. - Command::new(vs_lib) - .current_dir(out_dir) - .arg("/NOLOGO") - .args(&[ - format!( - r#"/DEF:{}"#, - vlc_def_path.display().to_string().trim_end_matches(r"\") - ), - format!( - r#"/OUT:{}"#, - vlc_import_lib.display().to_string().trim_end_matches(r"\") - ), - format!( - "/MACHINE:{}", - match target_arch().as_str() { - "x86" => "x86", - "x86_64" => "x64", - _ => unreachable!(), - } - ), - ]) - .status() - .expect("Failed to run lib.exe") - .success() - .then_some(()) - .expect("lib.exe failed to generate the vlc import library"); + // The bindings import from libvlc.dll directly via `raw-dylib`, so + // Windows needs neither an import library nor a search path, + // only the DLL at runtime. + if env::var("CARGO_CFG_TARGET_OS").unwrap() == "windows" { + return; } - fn vlc_path() -> PathBuf { - #[allow(unused_assignments)] - let arch_path: Option = match target_arch().as_str() { - "x86" => env::var_os("VLC_LIB_DIR_X86"), - "x86_64" => env::var_os("VLC_LIB_DIR_X86_64"), - _ => unreachable!(), - }; - - arch_path - .or_else(|| env::var_os("VLC_LIB_DIR")) - .map(PathBuf::from) - .expect("VLC_LIB_DIR not set") - } - - fn target_arch() -> String { - env::var("CARGO_CFG_TARGET_ARCH").unwrap() - } -} - -fn main() { - // 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: {:?}", MIN_LIBVLC_VERSION, err); } } diff --git a/xtask/src/main.rs b/xtask/src/main.rs index df9a2da..0d2ea28 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -73,6 +73,13 @@ fn generate_bindings() { "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()); }