blob: b6730e69ab77024894b6b1e095f27199a6f6ea34 [file] [log] [blame]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use regex::Regex;
use std::env::VarError;
use std::env::{self};
use std::fs::read_to_string;
use std::path::{Path, PathBuf};
mod bindgen_gen;
use bindgen_gen::vaapi_gen_builder;
/// Environment variable that can be set to point to the directory containing the `va.h`, `va_drm.h` and `va_drmcommon.h`
/// files to use to generate the bindings.
const CROS_LIBVA_H_PATH_ENV: &str = "CROS_LIBVA_H_PATH";
const CROS_LIBVA_LIB_PATH_ENV: &str = "CROS_LIBVA_LIB_PATH";
/// Wrapper file to use as input of bindgen.
const WRAPPER_PATH: &str = "libva-wrapper.h";
// Return VA_MAJOR_VERSION and VA_MINOR_VERSION from va_version.h.
fn get_va_version(va_h_path: &str) -> (u32, u32) {
let va_version_h_path = Path::new(va_h_path).join("va/va_version.h");
assert!(
va_version_h_path.exists(),
"{} doesn't exist",
va_version_h_path.display()
);
let header_content = read_to_string(va_version_h_path).unwrap();
let lines = header_content.lines();
const VERSION_REGEX_STRINGS: [&str; 2] = [
r"#define VA_MAJOR_VERSION\s*[0-9]+",
r"#define VA_MINOR_VERSION\s*[0-9]+",
];
let mut numbers: [u32; 2] = [0; 2];
for i in 0..2 {
let re = Regex::new(VERSION_REGEX_STRINGS[i]).unwrap();
let match_line = lines
.clone()
.filter(|&s| re.is_match(s))
.collect::<Vec<_>>();
assert_eq!(
match_line.len(),
1,
"unexpected match for {}: {:?}",
VERSION_REGEX_STRINGS[i],
match_line
);
let number_str = Regex::new(r"[0-9]+")
.unwrap()
.find(match_line[0])
.unwrap()
.as_str();
numbers[i] = number_str.parse::<u32>().unwrap();
}
(numbers[0], numbers[1])
}
fn main() {
// Do not require dependencies when generating docs.
if std::env::var("CARGO_DOC").is_ok() || std::env::var("DOCS_RS").is_ok() {
return;
}
let va_h_path = env::var(CROS_LIBVA_H_PATH_ENV)
.or_else(|e| {
if let VarError::NotPresent = e {
let libva_library = pkg_config::probe_library("libva");
match libva_library {
Ok(_) => Ok(libva_library.unwrap().include_paths[0]
.clone()
.into_os_string()
.into_string()
.unwrap()),
Err(e) => panic!("libva is not found in system: {}", e),
}
} else {
Err(e)
}
})
.expect("libva header location is unknown");
let va_lib_path = env::var(CROS_LIBVA_LIB_PATH_ENV).unwrap_or_default();
// Check the path exists.
if !va_h_path.is_empty() {
assert!(
Path::new(&va_h_path).exists(),
"{} doesn't exist",
va_h_path
);
}
let (major, minor) = get_va_version(&va_h_path);
println!("libva {}.{} is used to generate bindings", major, minor);
let va_check_version = |desired_major: u32, desired_minor: u32| {
major > desired_major || (major == desired_major && minor >= desired_minor)
};
if va_check_version(1, 21) {
println!("cargo::rustc-cfg=libva_1_21_or_higher");
}
if va_check_version(1, 20) {
println!("cargo::rustc-cfg=libva_1_20_or_higher")
}
if va_check_version(1, 19) {
println!("cargo::rustc-cfg=libva_1_19_or_higher")
}
if va_check_version(1, 16) {
println!("cargo::rustc-cfg=libva_1_16_or_higher")
}
if !va_lib_path.is_empty() {
assert!(
Path::new(&va_lib_path).exists(),
"{} doesn't exist",
va_lib_path
);
println!("cargo:rustc-link-arg=-Wl,-rpath={}", va_lib_path);
}
// Tell cargo to link va and va-drm objects dynamically.
println!("cargo:rustc-link-lib=dylib=va");
println!("cargo:rustc-link-lib=dylib=va-drm"); // for the vaGetDisplayDRM entrypoint
let mut bindings_builder = vaapi_gen_builder(bindgen::builder()).header(WRAPPER_PATH);
if !va_h_path.is_empty() {
bindings_builder = bindings_builder.clang_arg(format!("-I{}", va_h_path));
}
let bindings = bindings_builder
.generate()
.expect("unable to generate bindings");
let out_path = PathBuf::from(env::var("OUT_DIR").expect("`OUT_DIR` is not set"));
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}