2021-03-29 15:59:14 +08:00
use std ::{
env , fs ,
path ::{ Path , PathBuf } ,
2023-05-20 07:19:28 +02:00
println ,
2021-03-29 15:59:14 +08:00
} ;
2023-05-20 07:19:28 +02:00
#[ cfg(all(target_os = " linux " , feature = " linux-pkg-config " )) ]
fn link_pkg_config ( name : & str ) -> Vec < PathBuf > {
// sometimes an override is needed
let pc_name = match name {
" libvpx " = > " vpx " ,
_ = > name ,
} ;
let lib = pkg_config ::probe_library ( pc_name )
. expect ( format! (
" unable to find '{pc_name}' development headers with pkg-config (feature linux-pkg-config is enabled).
try installing ' { pc_name } - dev ' from your system package manager . " ).as_str());
lib . include_paths
}
#[ cfg(not(all(target_os = " linux " , feature = " linux-pkg-config " ))) ]
fn link_pkg_config ( _name : & str ) -> Vec < PathBuf > {
unimplemented! ( )
}
2023-11-01 11:37:39 +02:00
/// Link vcpkg package.
2022-06-02 16:13:34 +08:00
fn link_vcpkg ( mut path : PathBuf , name : & str ) -> PathBuf {
2022-05-12 17:35:25 +08:00
let target_os = std ::env ::var ( " CARGO_CFG_TARGET_OS " ) . unwrap ( ) ;
let mut target_arch = std ::env ::var ( " CARGO_CFG_TARGET_ARCH " ) . unwrap ( ) ;
if target_arch = = " x86_64 " {
target_arch = " x64 " . to_owned ( ) ;
2023-11-01 11:37:39 +02:00
} else if target_arch = = " x86 " {
target_arch = " x86 " . to_owned ( ) ;
2024-02-23 20:08:35 +08:00
} else if target_arch = = " loongarch64 " {
target_arch = " loongarch64 " . to_owned ( ) ;
2022-05-12 17:35:25 +08:00
} else if target_arch = = " aarch64 " {
target_arch = " arm64 " . to_owned ( ) ;
2023-11-01 11:37:39 +02:00
} else {
target_arch = " arm " . to_owned ( ) ;
2021-08-14 00:45:12 +08:00
}
2022-05-12 17:35:25 +08:00
let mut target = if target_os = = " macos " {
2022-09-16 22:22:17 +08:00
if target_arch = = " x64 " {
" x64-osx " . to_owned ( )
2023-04-17 19:26:39 +08:00
} else if target_arch = = " arm64 " {
2022-09-16 22:22:17 +08:00
" arm64-osx " . to_owned ( )
} else {
format! ( " {} - {} " , target_arch , target_os )
}
2022-05-12 17:35:25 +08:00
} else if target_os = = " windows " {
" x64-windows-static " . to_owned ( )
} else {
format! ( " {} - {} " , target_arch , target_os )
} ;
if target_arch = = " x86 " {
target = target . replace ( " x64 " , " x86 " ) ;
}
println! ( " cargo:info= {} " , target ) ;
path . push ( " installed " ) ;
path . push ( target ) ;
2022-06-02 16:13:34 +08:00
println! (
" {} " ,
format! (
" cargo:rustc-link-lib=static={} " ,
name . trim_start_matches ( " lib " )
)
) ;
println! (
" {} " ,
format! (
" cargo:rustc-link-search={} " ,
path . join ( " lib " ) . to_str ( ) . unwrap ( )
)
) ;
let include = path . join ( " include " ) ;
println! ( " {} " , format! ( " cargo:include= {} " , include . to_str ( ) . unwrap ( ) ) ) ;
include
}
/// Link homebrew package(for Mac M1).
fn link_homebrew_m1 ( name : & str ) -> PathBuf {
let target_os = std ::env ::var ( " CARGO_CFG_TARGET_OS " ) . unwrap ( ) ;
let target_arch = std ::env ::var ( " CARGO_CFG_TARGET_ARCH " ) . unwrap ( ) ;
if target_os ! = " macos " | | target_arch ! = " aarch64 " {
panic! ( " Couldn't find VCPKG_ROOT, also can't fallback to homebrew because it's only for macos aarch64. " ) ;
}
let mut path = PathBuf ::from ( " /opt/homebrew/Cellar " ) ;
path . push ( name ) ;
let entries = if let Ok ( dir ) = std ::fs ::read_dir ( & path ) {
dir
} else {
panic! ( " Could not find package in {} . Make sure your homebrew and package {} are all installed. " , path . to_str ( ) . unwrap ( ) , & name ) ;
} ;
let mut directories = entries
. into_iter ( )
. filter ( | x | x . is_ok ( ) )
. map ( | x | x . unwrap ( ) . path ( ) )
. filter ( | x | x . is_dir ( ) )
. collect ::< Vec < _ > > ( ) ;
// Find the newest version.
directories . sort_unstable ( ) ;
if directories . is_empty ( ) {
panic! (
" There's no installed version of {} in /opt/homebrew/Cellar " ,
name
) ;
}
path . push ( directories . pop ( ) . unwrap ( ) ) ;
// Link the library.
println! (
" {} " ,
format! (
" cargo:rustc-link-lib=static={} " ,
name . trim_start_matches ( " lib " )
)
) ;
// Add the library path.
2022-05-12 17:35:25 +08:00
println! (
" {} " ,
format! (
" cargo:rustc-link-search={} " ,
path . join ( " lib " ) . to_str ( ) . unwrap ( )
)
) ;
2022-06-02 16:13:34 +08:00
// Add the include path.
2022-05-12 17:35:25 +08:00
let include = path . join ( " include " ) ;
println! ( " {} " , format! ( " cargo:include= {} " , include . to_str ( ) . unwrap ( ) ) ) ;
2022-06-02 16:13:34 +08:00
include
}
/// Find package. By default, it will try to find vcpkg first, then homebrew(currently only for Mac M1).
2023-05-20 07:19:28 +02:00
/// If building for linux and feature "linux-pkg-config" is enabled, will try to use pkg-config
/// unless check fails (e.g. NO_PKG_CONFIG_libyuv=1)
2022-06-02 16:13:34 +08:00
fn find_package ( name : & str ) -> Vec < PathBuf > {
2023-05-20 07:19:28 +02:00
let no_pkg_config_var_name = format! ( " NO_PKG_CONFIG_ {name} " ) ;
println! ( " cargo:rerun-if-env-changed= {no_pkg_config_var_name} " ) ;
if cfg! ( all ( target_os = " linux " , feature = " linux-pkg-config " ) )
2023-05-20 16:23:00 +08:00
& & std ::env ::var ( no_pkg_config_var_name ) . as_deref ( ) ! = Ok ( " 1 " )
{
link_pkg_config ( name )
2023-05-20 07:19:28 +02:00
} else if let Ok ( vcpkg_root ) = std ::env ::var ( " VCPKG_ROOT " ) {
2022-06-02 16:13:34 +08:00
vec! [ link_vcpkg ( vcpkg_root . into ( ) , name ) ]
} else {
// Try using homebrew
vec! [ link_homebrew_m1 ( name ) ]
}
2021-03-29 15:59:14 +08:00
}
fn generate_bindings (
ffi_header : & Path ,
include_paths : & [ PathBuf ] ,
ffi_rs : & Path ,
exact_file : & Path ,
2023-05-08 19:57:32 +08:00
regex : & str ,
2021-03-29 15:59:14 +08:00
) {
let mut b = bindgen ::builder ( )
. header ( ffi_header . to_str ( ) . unwrap ( ) )
2023-05-08 19:57:32 +08:00
. allowlist_type ( regex )
. allowlist_var ( regex )
. allowlist_function ( regex )
. rustified_enum ( regex )
2021-03-29 15:59:14 +08:00
. trust_clang_mangling ( false )
. layout_tests ( false ) // breaks 32/64-bit compat
2023-05-08 19:57:32 +08:00
. generate_comments ( false ) ; // comments have prefix /*!\
2021-03-29 15:59:14 +08:00
for dir in include_paths {
b = b . clang_arg ( format! ( " -I {} " , dir . display ( ) ) ) ;
}
b . generate ( ) . unwrap ( ) . write_to_file ( ffi_rs ) . unwrap ( ) ;
fs ::copy ( ffi_rs , exact_file ) . ok ( ) ; // ignore failure
}
2023-05-08 19:57:32 +08:00
fn gen_vcpkg_package ( package : & str , ffi_header : & str , generated : & str , regex : & str ) {
let includes = find_package ( package ) ;
2021-03-29 15:59:14 +08:00
let src_dir = env ::var_os ( " CARGO_MANIFEST_DIR " ) . unwrap ( ) ;
let src_dir = Path ::new ( & src_dir ) ;
let out_dir = env ::var_os ( " OUT_DIR " ) . unwrap ( ) ;
let out_dir = Path ::new ( & out_dir ) ;
2023-05-08 19:57:32 +08:00
let ffi_header = src_dir . join ( " src " ) . join ( " bindings " ) . join ( ffi_header ) ;
2021-03-29 15:59:14 +08:00
println! ( " rerun-if-changed= {} " , ffi_header . display ( ) ) ;
for dir in & includes {
println! ( " rerun-if-changed= {} " , dir . display ( ) ) ;
}
2023-05-08 19:57:32 +08:00
let ffi_rs = out_dir . join ( generated ) ;
let exact_file = src_dir . join ( " generated " ) . join ( generated ) ;
generate_bindings ( & ffi_header , & includes , & ffi_rs , & exact_file , regex ) ;
2021-03-29 15:59:14 +08:00
}
fn main ( ) {
// note: all link symbol names in x86 (32-bit) are prefixed wth "_".
// run "rustup show" to show current default toolchain, if it is stable-x86-pc-windows-msvc,
// please install x64 toolchain by "rustup toolchain install stable-x86_64-pc-windows-msvc",
// then set x64 to default by "rustup default stable-x86_64-pc-windows-msvc"
let target = target_build_utils ::TargetInfo ::new ( ) ;
if target . unwrap ( ) . target_pointer_width ( ) ! = " 64 " {
2021-08-14 00:45:12 +08:00
// panic!("Only support 64bit system");
2021-03-29 15:59:14 +08:00
}
env ::remove_var ( " CARGO_CFG_TARGET_FEATURE " ) ;
env ::set_var ( " CARGO_CFG_TARGET_FEATURE " , " crt-static " ) ;
find_package ( " libyuv " ) ;
2023-05-08 19:57:32 +08:00
gen_vcpkg_package ( " libvpx " , " vpx_ffi.h " , " vpx_ffi.rs " , " ^[vV].* " ) ;
gen_vcpkg_package ( " aom " , " aom_ffi.h " , " aom_ffi.rs " , " ^(aom|AOM|OBU|AV1).* " ) ;
2023-10-27 15:44:07 +08:00
gen_vcpkg_package ( " libyuv " , " yuv_ffi.h " , " yuv_ffi.rs " , " .* " ) ;
2021-03-29 15:59:14 +08:00
// there is problem with cfg(target_os) in build.rs, so use our workaround
let target_os = std ::env ::var ( " CARGO_CFG_TARGET_OS " ) . unwrap ( ) ;
2022-05-12 17:35:25 +08:00
if target_os = = " ios " {
2021-03-29 15:59:14 +08:00
// nothing
2022-05-12 17:35:25 +08:00
} else if target_os = = " android " {
println! ( " cargo:rustc-cfg=android " ) ;
2021-03-29 15:59:14 +08:00
} else if cfg! ( windows ) {
// The first choice is Windows because DXGI is amazing.
println! ( " cargo:rustc-cfg=dxgi " ) ;
} else if cfg! ( target_os = " macos " ) {
// Quartz is second because macOS is the (annoying) exception.
println! ( " cargo:rustc-cfg=quartz " ) ;
} else if cfg! ( unix ) {
// On UNIX we pray that X11 (with XCB) is available.
println! ( " cargo:rustc-cfg=x11 " ) ;
}
}