diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f0f98f2..2c9cea8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -103,7 +103,7 @@ jobs: - name: Cache vcpkg id: cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ${{ github.workspace }}/vcpkg @@ -327,20 +327,40 @@ jobs: - target: "x86_64-pc-windows-msvc" vcpkg_triplet: "x64-windows-static" rustflags: "-Ctarget-feature=+crt-static" + linking: "static" + probe_method: "vcpkg" - target: "x86_64-pc-windows-msvc" vcpkg_triplet: "x64-windows-static-md" + linking: "static" + probe_method: "vcpkg" - target: "x86_64-pc-windows-msvc" vcpkg_triplet: "x64-windows" - dynamic: true + linking: "dynamic" + probe_method: "vcpkg" - target: "i686-pc-windows-msvc" vcpkg_triplet: "x86-windows-static" rustflags: "-Ctarget-feature=+crt-static" + linking: "static" + probe_method: "vcpkg" - target: "i686-pc-windows-msvc" vcpkg_triplet: "x86-windows-static-md" + linking: "static" + probe_method: "vcpkg" - target: "i686-pc-windows-msvc" vcpkg_triplet: "x86-windows" - dynamic: true + linking: "dynamic" + probe_method: "vcpkg" + + # Additional ways of telling the build script to find FFmpeg: + - target: "x86_64-pc-windows-msvc" + vcpkg_triplet: "x64-windows-static-md" + linking: "static" + probe_method: "dir_vars" + - target: "x86_64-pc-windows-msvc" + vcpkg_triplet: "x64-windows-static-md" + linking: "static" + probe_method: "pkg_config" fail-fast: false steps: - uses: actions/checkout@v4 @@ -358,7 +378,7 @@ jobs: - name: Cache vcpkg id: cache - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ${{ github.workspace }}/vcpkg @@ -377,19 +397,36 @@ jobs: - name: Set env shell: bash run: | - if [ '${{ matrix.config.dynamic }}' != '' ]; then + if [ '${{ matrix.config.linking }}' == 'dynamic' ]; then echo "VCPKGRS_DYNAMIC=1" >> $GITHUB_ENV fi + if [ '${{ matrix.config.probe_method }}' == 'vcpkg' ]; then + echo "VCPKG_ROOT=${{ github.workspace }}/vcpkg" >> $GITHUB_ENV + echo "VCPKG_DEFAULT_TRIPLET=${{ matrix.config.vcpkg_triplet }}" >> $GITHUB_ENV + echo "FEATURES=--features link_vcpkg_ffmpeg" >> $GITHUB_ENV + elif [ '${{ matrix.config.probe_method }}' == 'dir_vars' ]; then + echo "FFMPEG_INCLUDE_DIR=${{ github.workspace }}/vcpkg/installed/"\ + "${{ matrix.config.vcpkg_triplet }}/include" >> $GITHUB_ENV + echo "FFMPEG_LIBS_DIR=${{ github.workspace }}/vcpkg/installed/"\ + "${{ matrix.config.vcpkg_triplet }}/debug/lib" >> $GITHUB_ENV + echo "FEATURES=" >> $GITHUB_ENV + elif [ '${{ matrix.config.probe_method }}' == 'pkg_config' ]; then + echo "PKG_CONFIG=${{ github.workspace }}/vcpkg/installed/"\ + "x64-windows/tools/pkgconf/pkgconf.exe" >> $GITHUB_ENV + echo "FFMPEG_PKG_CONFIG_PATH=${{ github.workspace }}/vcpkg/installed/"\ + "${{ matrix.config.vcpkg_triplet }}/debug/lib/pkgconfig" >> $GITHUB_ENV + echo "FEATURES=" >> $GITHUB_ENV + fi - - name: Binding build + - name: Binding build and run example shell: bash env: - VCPKG_ROOT: ${{ github.workspace }}/vcpkg RUSTFLAGS: ${{ matrix.config.rustflags }} - VCPKG_DEFAULT_TRIPLET: ${{ matrix.config.vcpkg_triplet }} LIBCLANG_PATH: ${{ github.workspace }}/clang/lib LLVM_CONFIG_PATH: ${{ github.workspace }}/clang/bin/llvm-config - run: cargo build --features link_vcpkg_ffmpeg --target ${{ matrix.config.target }} --verbose + run: | + cargo build $FEATURES --target ${{ matrix.config.target }} --verbose + cargo run $FEATURES --target ${{ matrix.config.target }} --example slice --verbose build_dynamic_and_test_ubuntu: runs-on: ubuntu-latest diff --git a/Cargo.toml b/Cargo.toml index 3399d1c..8f1ee79 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,10 +28,8 @@ libc = "0.2" bindgen = "0.70" camino = "1.1" once_cell = "1.12" -vcpkg = { version = "0.2", optional = true } - -[target.'cfg(not(windows))'.build-dependencies] pkg-config = "0.3" +vcpkg = { version = "0.2", optional = true } [features] # Probe and link FFmpeg with pkg-config diff --git a/README.md b/README.md index 5aabc60..06dbb82 100644 --- a/README.md +++ b/README.md @@ -10,54 +10,124 @@ Cross platform FFI bindings for FFmpeg internal libraries. This is a crate that: 1. Links FFmpeg libraries for you. 2. Generates Rust binding for FFmpeg libraries. -## Getting started: +## Getting started -To use this crate, you need to set several environment variables. +This create requires configuration before you can start using it. To quickly get started, follow the steps below. -### The simplest usage: +For more advanced usage, consult the [reference section](#reference) below. -#### Linux, macOS..(*nix) +Before beginning to build FFmpeg, you should install LLVM first. This will enable Rusty FFmpeg to generate Rust bindings from the C header files. The `bindgen` documentation has [good instructions](https://rust-lang.github.io/rust-bindgen/requirements.html) on how to install prebuilt LLVM binaries for your platform. You can also build LLVM from source, such as using vcpkg, but this can take hours on all but the most well-equipped computers. -If you have FFmpeg installed with package manager, import `rusty_ffmpeg` with feature `link_system_ffmpeg`. Then it should work. +### Linux, macOS..(*nix) -If you built FFmpeg from source, set `FFMPEG_PKG_CONFIG_PATH` to the path of the generated FFmpeg `pkg-config` directory. Then it should work. +If you have FFmpeg installed with your system package manager, import `rusty_ffmpeg` with feature `link_system_ffmpeg` and the feature for your installed FFmpeg version. The build script will use pkg-config to probe for the system-installed FFmpeg. -#### Windows +If you'd like to use an FFmpeg that you built from source, set `FFMPEG_PKG_CONFIG_PATH` to the path of the generated `pkgconfig` directory. The build script will use pkg-config to probe in that directory. You may also use `vcpkg`, as described below: the instructions should be similar to Windows. -`rusty_ffmpeg` can link FFmpeg using `vcpkg`: -1. Install [`vcpkg`](https://github.com/microsoft/vcpkg), check [documentation of the vcpkg *crate*](https://docs.rs/vcpkg) for the environment variables to set. -2. Import `rusty_ffmpeg` with feature `link_vcpkg_ffmpeg`, Then it should work. +### Windows -### Fine-grained usage: +One of the easiest ways to get started on Windows is to build FFmpeg using [`vcpkg`](https://github.com/microsoft/vcpkg), which provides a [port for FFmpeg](https://vcpkg.io/en/package/ffmpeg). -You need to set several environment variables for both the linking and binding generating procedures. +#### Classic mode of vcpkg -#### To link prebuilt libraries: +1. Install vcpkg according to the [instructions](https://learn.microsoft.com/en-us/vcpkg/get_started/get-started?pivots=shell-powershell#1---set-up-vcpkg) (the first step of cloning and bootstrapping). +2. Build and install ffmpeg: `vcpkg install ffmpeg --triplet=`, where `triplet` is set to an appropriate value for your project ([see below](#vcpkg-triplets)). +3. Check [documentation of the vcpkg *crate*](https://docs.rs/vcpkg) for the environment variables to set. +4. Import `rusty_ffmpeg` with feature `link_vcpkg_ffmpeg` and the feature corresponding to the FFmpeg version that you built. -1. Dynamic linking with pre-built dylib: Set `FFMPEG_DLL_PATH` to the path of `dll` or `so` files. (Windows: Put corresponding `.lib` file next to the `.dll` file.) +You may want to look into [`cargo-vcpkg`](https://crates.io/crates/cargo-vcpkg), which can automate these steps. -2. Static linking with pre-built staticlib: Set `FFMPEG_LIBS_DIR` to the path of FFmpeg pre-built libs directory. +#### Manifest mode -#### To generate bindings: +When using [manifest mode](https://learn.microsoft.com/en-us/vcpkg/concepts/manifest-mode), you create a `vcpkg.json` file in your repository that declares what vcpkg ports your project requires. vcpkg then builds and installs the packages in a `vcpkg_installed` directory that is local to your repository. -1. Compile-time binding generation([requires the `Clang` dylib](https://github.com/KyleMayes/clang-sys/blob/c9ae24a7a218e73e1eccd320174349eef5a3bd1a/build.rs#L23)): Set `FFMPEG_INCLUDE_DIR` to the path of the header files for binding generation. +1. Create a `vcpkg.json` file for your project by following instructions in vcpkg's documentation. In addition to FFmpeg, make sure you also install the [`pkgconf`](https://vcpkg.io/en/package/pkgconf) port as a host tool. +2. Build and install your manifest: `vcpkg install --triplet=`, where `triplet` is set to an appropriate value for your project ([see below](#vcpkg-triplets)). +3. Set the `PKG_CONFIG` environment variable to the vcpkg-built `pkgconf.exe` tool within the built `tools/` directory. Set the `PKG_CONFIG_PATH` to the `pkgconfig` directory that was installed within the built `lib/` directory. +4. Import `rusty_ffmpeg` with the feature corresponding to the FFmpeg version that you built. -2. Use your prebuilt binding: Set `FFMPEG_BINDING_PATH` to the pre-built binding file. The pre-built binding is usually copied from the `OUT_DIR` of the compile-time binding generation, using it will prevent the need to regenerate the same binding file repeatedly. +## Reference -### Linking FFmpeg installed by package manager on (*nix) +Basic usage of Rusty FFmpeg requires that you: -You can link FFmpeg libraries installed by package manager by enabling feature `link_system_ffmpeg` (which uses pkg-config underneath). +- Set the feature for the FFmpeg version that you are using (see [Features](#features), below). +- [Instruct the build script](#how-the-build-script-finds-ffmpeg) how to find FFmpeg. -### Linking FFmpeg installed by vcpkg +### How the build script finds FFmpeg -You can link FFmpeg libraries installed by vcpkg by enabling feature `link_vcpkg_ffmpeg` on Windows, macOS, and Linux. +There are several ways that FFmpeg can be found and configured using the [environment variables](#environment-variables) and [features](#features). There is no default method for finding FFmpeg: you must choose one or more of these methods to utilize. -### Use a specific FFmpeg version +Unless the `FFMPEG_DLL_PATH` environment variable is set, static linking will be done. -- Do nothing when you are using FFmpeg `4.*` -- Enable `ffmpeg5` feature when you are using FFmpeg `5.*` -- Enable `ffmpeg6` feature when you are using FFmpeg `6.*` -- Enable `ffmpeg7` feature when you are using FFmpeg `7.*` +#### Static linking + +When the build script is in static linking mode, it will try to statically link with FFmpeg in the following order: + +1. First, if `FFMPEG_PKG_CONFIG_PATH` is set, pkg-config or pkgconf is used to probe for FFmpeg by using the `.pc` files in the given directory. The `PKG_CONFIG` and `FFMPEG_BINDING_PATH` environment variables will also be used if they are set. +2. If `FFMPEG_LIBS_DIR` is set, then FFmpeg libraries from that directory will be used. No probing with pkg-config will take place. You must also set the `FFMPEG_INCLUDE_DIR` or the `FFMPEG_BINDING_PATH` environment variable in this case. +3. If the `link_system_ffmpeg` feature is enabled, then pkg-config will be used to probe for an FFmpeg package installed by your system package manager. +4. If the `link_vcpkg_ffmpeg` feature is enabled, then the [vcpkg](https://docs.rs/vcpkg) crate will be used to probe for FFmpeg. + - Note that as of this writing, the [published crate does not support](https://github.com/mcgoo/vcpkg-rs/issues/41) using vcpkg in [manifest mode](https://learn.microsoft.com/en-us/vcpkg/concepts/manifest-mode), so you may want to consider setting `PKG_CONFIG` and `FFMPEG_PKG_CONFIG_PATH` to the corresponding file/directories installed by vcpkg in that case. + +Both `link_system_ffmpeg` and `link_vcpkg_ffmpeg` features can be enabled simultaneously. If system pkg-config probing fails, then it will fallback to vcpkg probing. + +#### Dynamic linking + +At this time, the build script locates a dynamically-linked FFmpeg using only one way. Probing using pkg-config or vcpkg is not currently supported. + +To dynamically link with FFmpeg, the following environment variables must be set: + +- `FFMPEG_DLL_PATH` +- `FFMPEG_INCLUDE_DIR` or `FFMPEG_BINDING_PATH` + +At this time, more advanced search methods such as those used for static linking are not supported. + +### Environment variables + +Several aspects of the build are controlled by environment variables: + +| Variable | Purpose | +| -------- | ------- | +| `FFMPEG_BINDING_PATH` | Path to a pre-built `binding.rs` file so as to avoid repeatedly regenerating the same binding file. Include files will be ignored in this case; the variable takes precedence over `FFMPEG_INCLUDE_DIR` or any include files discovered using pkg-config. It can be copied from the `OUT_DIR` of a previous build that generated the bindings. | +| `FFMPEG_DLL_PATH` | Path to the FFmpeg dynamically linked library file. The lib file is expected to be alongside it. | +| `FFMPEG_INCLUDE_DIR` | Path to directory containing FFmpeg include files. Bindings will be generated using bindgen. | +| `FFMPEG_LIBS_DIR` | Path to directory containing FFmpeg library files. | +| `FFMPEG_PKG_CONFIG_PATH` | Path to directory containing `.pc` files to probe with pkg-config. | +| `PKG_CONFIG` | Path to pkg-config executable file, if pkg-config is not in your `PATH`. The pkgconf tool can also be used. | + +### Features + +This crate has several features which can be configured: + +| Feature | Purpose | +| ------- | ------- | +| `ffmpeg5` | Compile with support for FFmpeg `5.*` | +| `ffmpeg6` | Compile with support for FFmpeg `6.*` | +| `ffmpeg7` | Compile with support for FFmpeg `7.*` | +| `link_system_ffmpeg` | Enable probing for FFmpeg installed by your system package manager using pkg-config. | +| `link_vcpkg_ffmpeg` | Enable probing for FFmpeg using the [vcpkg](https://docs.rs/vcpkg) crate. | + +None of the features are enabled by default. If no `ffmpeg*` feature is chosen, then support for FFmpeg `4.*` will be compiled. + +### vcpkg triplets + +The vcpkg [triplet](https://learn.microsoft.com/en-us/vcpkg/concepts/triplets) controls the CPU architecture, operating system, runtime library, etc. It is very important that you choose a triplet that is known to be compatible with your Rust toolchain targets and configuration in order to avoid undefined behavior. + +This table provides a quick reference for what vcpkg triplet to choose: + +| Rust toolchain target | FFmpeg linking | CRT linking | vcpkg triplet | +| --------------------- | -------------- | ----------- | ------------- | +| `x86_64-pc-windows-msvc` | Static | Static | `x64-windows-static` | +| `x86_64-pc-windows-msvc` | Static | Dynamic | `x64-windows-static-md` | +| `x86_64-pc-windows-msvc` | Dynamic | Dynamic | `x64-windows` | +| `x86_64-unknown-linux-gnu` | Static | Dynamic | `x64-linux` | +| `x86_64-unknown-linux-gnu` | Dynamic | Dynamic | `x64-linux-dynamic` | +| `aarch64-apple-darwin` | Static | Dynamic | `arm64-osx` | +| `aarch64-apple-darwin` | Dynamic | Dynamic | `arm64-osx-dynamic` | + +- **Rust toolchain target**: View Rust toolchain targets using `rustup target list`. +- **CRT linking**: The C runtime can be dynamically or statically linked to the code compiled by Rust. The [`crt-static`](https://doc.rust-lang.org/reference/linkage.html#static-and-dynamic-c-runtimes) target feature controls this; the default varies by target. On Windows, macOS, and Linux with glibc, dynamic linking is the Rust default. +- **vcpkg triplet**: The vcpkg triplet that you should use for the given Rust target and CRT linking. Typically set using the [`--triplet`](https://learn.microsoft.com/en-us/vcpkg/commands/common-options#triplet) parameter. ## Attention diff --git a/build.rs b/build.rs index d52a844..22cc000 100644 --- a/build.rs +++ b/build.rs @@ -3,7 +3,10 @@ use bindgen::{callbacks, Bindings}; use camino::Utf8Path as Path; use camino::Utf8PathBuf as PathBuf; use once_cell::sync::Lazy; -use std::{collections::HashSet, env, fs}; +use std::{ + collections::{HashMap, HashSet}, + env, fs, +}; /// All the libs that FFmpeg has static LIBS: Lazy<[&str; 7]> = Lazy::new(|| { @@ -18,6 +21,38 @@ static LIBS: Lazy<[&str; 7]> = Lazy::new(|| { ] }); +static SYS_STATIC_LIBS: Lazy>> = Lazy::new(|| { + if cfg!(target_os = "windows") { + // Statically linking FFmpeg on Windows requires additional dependencies. This is a map + // of FFmpeg library name to system libraries. In the future, if + // https://github.com/CCExtractor/rusty_ffmpeg/issues/128 is addressed, we will want to + // selectively choose which system libraries to link based on chosen FFmpeg features. + // + // Note that the values were obtained by building FFmpeg using vcpkg with the + // x64-windows-static triplet, and then examining the generated .pc files in the pkgconfig + // directory. + HashMap::from([ + ( + "avcodec", + vec!["mfuuid", "ole32", "strmiids", "ole32", "user32"], + ), + ( + "avdevice", + vec![ + "psapi", "ole32", "strmiids", "uuid", "oleaut32", "shlwapi", "gdi32", "vfw32", + ], + ), + ("avfilter", vec![]), + ("avformat", vec!["secur32", "ws2_32"]), + ("avutil", vec!["user32", "bcrypt"]), + ("swresample", vec![]), + ("swscale", vec![]), + ]) + } else { + HashMap::new() + } +}); + /// Whitelist of the headers we want to generate bindings static HEADERS: Lazy> = Lazy::new(|| { [ @@ -291,7 +326,6 @@ fn remove_verbatim(path: String) -> PathBuf { PathBuf::from(path) } -#[cfg(not(target_os = "windows"))] mod pkg_config_linking { use super::*; @@ -300,6 +334,7 @@ mod pkg_config_linking { /// Note: no side effect if this function errors. pub fn linking_with_pkg_config( library_names: &[&str], + statik: bool, ) -> Result, pkg_config::Error> { // dry run for library linking for libname in library_names { @@ -308,6 +343,7 @@ mod pkg_config_linking { .env_metadata(false) .print_system_libs(false) .print_system_cflags(false) + .statik(statik) .probe(&format!("lib{}", libname))?; } @@ -315,6 +351,7 @@ mod pkg_config_linking { let mut paths = HashSet::new(); for libname in library_names { let new_paths = pkg_config::Config::new() + .statik(statik) .probe(&format!("lib{}", libname)) .unwrap_or_else(|_| panic!("{} not found!", libname)) .include_paths; @@ -399,119 +436,109 @@ fn dynamic_linking(env_vars: &EnvVars) { fn static_linking(env_vars: &EnvVars) { let output_binding_path = &env_vars.out_dir.as_ref().unwrap().join("binding.rs"); - #[cfg(not(target_os = "windows"))] - { - fn static_linking_with_pkg_config_and_bindgen( - env_vars: &EnvVars, - output_binding_path: &Path, - ) -> Result<(), pkg_config::Error> { - // Probe libraries(enable emitting cargo metadata) - let include_paths = pkg_config_linking::linking_with_pkg_config(&*LIBS)?; - if let Some(ffmpeg_binding_path) = env_vars.ffmpeg_binding_path.as_ref() { - use_prebuilt_binding(ffmpeg_binding_path, output_binding_path); - } else if let Some(ffmpeg_include_dir) = env_vars.ffmpeg_include_dir.as_ref() { - // If use ffmpeg_pkg_config_path with ffmpeg_include_dir, prefer using the user given dir rather than pkg_config_path. - generate_bindings(ffmpeg_include_dir, &HEADERS) - .write_to_file(output_binding_path) - .expect("Cannot write binding to file."); - } else { - generate_bindings(&include_paths[0], &HEADERS) - .write_to_file(output_binding_path) - .expect("Cannot write binding to file."); - } - Ok(()) - } - // Hint: set PKG_CONFIG_PATH to some placeholder value will let pkg_config probing system library. - if let Some(ffmpeg_pkg_config_path) = env_vars.ffmpeg_pkg_config_path.as_ref() { - if !Path::new(ffmpeg_pkg_config_path).exists() { - panic!( - "error: FFMPEG_PKG_CONFIG_PATH is set to `{}`, which does not exist.", - ffmpeg_pkg_config_path - ); - } - env::set_var("PKG_CONFIG_PATH", ffmpeg_pkg_config_path); - static_linking_with_pkg_config_and_bindgen(env_vars, output_binding_path) - .expect("Static linking with pkg-config failed."); - } else if let Some(ffmpeg_libs_dir) = env_vars.ffmpeg_libs_dir.as_ref() { - static_linking_with_libs_dir(&*LIBS, ffmpeg_libs_dir); - if let Some(ffmpeg_binding_path) = env_vars.ffmpeg_binding_path.as_ref() { - use_prebuilt_binding(ffmpeg_binding_path, output_binding_path); - } else if let Some(ffmpeg_include_dir) = env_vars.ffmpeg_include_dir.as_ref() { - generate_bindings(ffmpeg_include_dir, &HEADERS) - .write_to_file(output_binding_path) - .expect("Cannot write binding to file."); - } else { - panic!("No binding generation method is set!"); - } + fn static_linking_with_pkg_config_and_bindgen( + env_vars: &EnvVars, + output_binding_path: &Path, + ) -> Result<(), pkg_config::Error> { + // Probe libraries(enable emitting cargo metadata) + let include_paths = pkg_config_linking::linking_with_pkg_config(&*LIBS, true)?; + if let Some(ffmpeg_binding_path) = env_vars.ffmpeg_binding_path.as_ref() { + use_prebuilt_binding(ffmpeg_binding_path, output_binding_path); + } else if let Some(ffmpeg_include_dir) = env_vars.ffmpeg_include_dir.as_ref() { + // If use ffmpeg_pkg_config_path with ffmpeg_include_dir, prefer using the user given dir rather than pkg_config_path. + generate_bindings(ffmpeg_include_dir, &HEADERS) + .write_to_file(output_binding_path) + .expect("Cannot write binding to file."); } else { - #[cfg(not(any(feature = "link_system_ffmpeg", feature = "link_vcpkg_ffmpeg")))] + generate_bindings(&include_paths[0], &HEADERS) + .write_to_file(output_binding_path) + .expect("Cannot write binding to file."); + } + Ok(()) + } + + fn static_link_sys_libs() { + // Statically linking to FFmpeg may also require us to link to some system libraries. + let mut sys_libs: Vec<_> = SYS_STATIC_LIBS.values().flatten().collect(); + sys_libs.sort(); + sys_libs.dedup(); + for sys_lib in sys_libs { + println!("cargo:rustc-link-lib={sys_lib}"); + } + } + + // Hint: set PKG_CONFIG_PATH to some placeholder value will let pkg_config probing system library. + if let Some(ffmpeg_pkg_config_path) = env_vars.ffmpeg_pkg_config_path.as_ref() { + if !Path::new(ffmpeg_pkg_config_path).exists() { panic!( - " + "error: FFMPEG_PKG_CONFIG_PATH is set to `{}`, which does not exist.", + ffmpeg_pkg_config_path + ); + } + env::set_var("PKG_CONFIG_PATH", ffmpeg_pkg_config_path); + static_linking_with_pkg_config_and_bindgen(env_vars, output_binding_path) + .expect("Static linking with pkg-config failed."); + } else if let Some(ffmpeg_libs_dir) = env_vars.ffmpeg_libs_dir.as_ref() { + static_linking_with_libs_dir(&*LIBS, ffmpeg_libs_dir); + if let Some(ffmpeg_binding_path) = env_vars.ffmpeg_binding_path.as_ref() { + use_prebuilt_binding(ffmpeg_binding_path, output_binding_path); + } else if let Some(ffmpeg_include_dir) = env_vars.ffmpeg_include_dir.as_ref() { + generate_bindings(ffmpeg_include_dir, &HEADERS) + .write_to_file(output_binding_path) + .expect("Cannot write binding to file."); + } else { + panic!("No binding generation method is set!"); + } + + // Statically linking to FFmpeg may also require us to link to some system libraries. + static_link_sys_libs(); + } else { + #[cfg(not(any(feature = "link_system_ffmpeg", feature = "link_vcpkg_ffmpeg")))] + panic!( + " !!!!!!! rusty_ffmpeg: No linking method set! -Use `FFMPEG_PKG_CONFIG_PATH` or `FFMPEG_LIBS_DIR` if you have prebuilt FFmpeg libraries. -Enable `link_system_ffmpeg` feature if you want to link ffmpeg libraries installed in system path(which can be probed by pkg-config). -Enable `link_vcpkg_ffmpeg` feature if you want to link ffmpeg libraries installed by vcpkg. +Use `FFMPEG_PKG_CONFIG_PATH` to probe with pkg-config for prebuilt FFmpeg libraries. +Alternatively, use `FFMPEG_LIBS_DIR` and `FFMPEG_INCLUDE_DIR` to bypass pkg-config. +Alternatively, enable `link_system_ffmpeg` feature if you want to link ffmpeg libraries installed + in system path (which can be probed by pkg-config). +Alternatively, enable `link_vcpkg_ffmpeg` feature if you want to link ffmpeg libraries installed by vcpkg. " - ); - #[cfg(any(feature = "link_system_ffmpeg", feature = "link_vcpkg_ffmpeg"))] - { - let mut success = false; - let mut error = String::new(); - #[cfg(feature = "link_system_ffmpeg")] - if !success { - if let Err(e) = - static_linking_with_pkg_config_and_bindgen(env_vars, output_binding_path) - { - error.push('\n'); - error.push_str(&format!("Link system FFmpeg failed: {:?}", e)); - } else { - println!("Link system FFmpeg succeeded."); - success = true; - } - } - #[cfg(feature = "link_vcpkg_ffmpeg")] - if !success { - if let Err(e) = - vcpkg_linking::linking_with_vcpkg_and_bindgen(env_vars, output_binding_path) - { - error.push('\n'); - error.push_str(&format!("Link vcpkg FFmpeg failed: {:?}", e)); - } else { - println!("Link vcpkg FFmpeg succeeded."); - success = true; - } + ); + #[cfg(any(feature = "link_system_ffmpeg", feature = "link_vcpkg_ffmpeg"))] + { + let mut success = false; + let mut error = String::new(); + #[cfg(feature = "link_system_ffmpeg")] + if !success { + if let Err(e) = + static_linking_with_pkg_config_and_bindgen(env_vars, output_binding_path) + { + error.push('\n'); + error.push_str(&format!("Link system FFmpeg failed: {:?}", e)); + } else { + println!("Link system FFmpeg succeeded."); + success = true; } - if !success { - panic!("FFmpeg linking trial failed: {}", error); + } + #[cfg(feature = "link_vcpkg_ffmpeg")] + if !success { + if let Err(e) = + vcpkg_linking::linking_with_vcpkg_and_bindgen(env_vars, output_binding_path) + { + error.push('\n'); + error.push_str(&format!("Link vcpkg FFmpeg failed: {:?}", e)); + } else { + // vcpkg_linking doesn't currently link these indirect system packages, even + // though they were specified in the pkg-config files. + static_link_sys_libs(); + + println!("Link vcpkg FFmpeg succeeded."); + success = true; } } - } - } - #[cfg(target_os = "windows")] - { - if let Some(ffmpeg_libs_dir) = env_vars.ffmpeg_libs_dir.as_ref() { - static_linking_with_libs_dir(&*LIBS, ffmpeg_libs_dir); - if let Some(ffmpeg_binding_path) = env_vars.ffmpeg_binding_path.as_ref() { - use_prebuilt_binding(ffmpeg_binding_path, output_binding_path); - } else if let Some(ffmpeg_include_dir) = env_vars.ffmpeg_include_dir.as_ref() { - generate_bindings(ffmpeg_include_dir, &HEADERS) - .write_to_file(output_binding_path) - .expect("Cannot write binding to file."); - } else { - panic!("No binding generation method is set!"); + if !success { + panic!("FFmpeg linking trial failed: {}", error); } - } else { - #[cfg(feature = "link_vcpkg_ffmpeg")] - vcpkg_linking::linking_with_vcpkg_and_bindgen(env_vars, output_binding_path) - .expect("Linking FFmpeg with vcpkg failed."); - #[cfg(not(feature = "link_vcpkg_ffmpeg"))] - panic!( - " -!!!!!!! rusty_ffmpeg: No linking method set! -Use FFMPEG_PKG_CONFIG_PATH or FFMPEG_LIBS_DIR if you have prebuilt FFmpeg libraries. -Enable `link_vcpkg_ffmpeg` feature if you want to link ffmpeg provided by vcpkg. -" - ); } } }