• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use regex::Regex;
6 use std::env::VarError;
7 use std::env::{self};
8 use std::fs::read_to_string;
9 use std::path::{Path, PathBuf};
10 
11 mod bindgen_gen;
12 use bindgen_gen::vaapi_gen_builder;
13 
14 /// Environment variable that can be set to point to the directory containing the `va.h`, `va_drm.h` and `va_drmcommon.h`
15 /// files to use to generate the bindings.
16 const CROS_LIBVA_H_PATH_ENV: &str = "CROS_LIBVA_H_PATH";
17 const CROS_LIBVA_LIB_PATH_ENV: &str = "CROS_LIBVA_LIB_PATH";
18 
19 /// Wrapper file to use as input of bindgen.
20 const WRAPPER_PATH: &str = "libva-wrapper.h";
21 
22 // Return VA_MAJOR_VERSION and VA_MINOR_VERSION from va_version.h.
get_va_version(va_h_path: &str) -> (u32, u32)23 fn get_va_version(va_h_path: &str) -> (u32, u32) {
24     let va_version_h_path = Path::new(va_h_path).join("va/va_version.h");
25     assert!(
26         va_version_h_path.exists(),
27         "{} doesn't exist",
28         va_version_h_path.display()
29     );
30     let header_content = read_to_string(va_version_h_path).unwrap();
31     let lines = header_content.lines();
32 
33     const VERSION_REGEX_STRINGS: [&str; 2] = [
34         r"#define VA_MAJOR_VERSION\s*[0-9]+",
35         r"#define VA_MINOR_VERSION\s*[0-9]+",
36     ];
37     let mut numbers: [u32; 2] = [0; 2];
38     for i in 0..2 {
39         let re = Regex::new(VERSION_REGEX_STRINGS[i]).unwrap();
40         let match_line = lines
41             .clone()
42             .filter(|&s| re.is_match(s))
43             .collect::<Vec<_>>();
44         assert_eq!(
45             match_line.len(),
46             1,
47             "unexpected match for {}: {:?}",
48             VERSION_REGEX_STRINGS[i],
49             match_line
50         );
51         let number_str = Regex::new(r"[0-9]+")
52             .unwrap()
53             .find(match_line[0])
54             .unwrap()
55             .as_str();
56         numbers[i] = number_str.parse::<u32>().unwrap();
57     }
58 
59     (numbers[0], numbers[1])
60 }
61 
main()62 fn main() {
63     // Do not require dependencies when generating docs.
64     if std::env::var("CARGO_DOC").is_ok() || std::env::var("DOCS_RS").is_ok() {
65         return;
66     }
67 
68     let va_h_path = env::var(CROS_LIBVA_H_PATH_ENV)
69         .or_else(|e| {
70             if let VarError::NotPresent = e {
71                 let libva_library = pkg_config::probe_library("libva");
72                 match libva_library {
73                     Ok(_) => Ok(libva_library.unwrap().include_paths[0]
74                         .clone()
75                         .into_os_string()
76                         .into_string()
77                         .unwrap()),
78                     Err(e) => panic!("libva is not found in system: {}", e),
79                 }
80             } else {
81                 Err(e)
82             }
83         })
84         .expect("libva header location is unknown");
85 
86     let va_lib_path = env::var(CROS_LIBVA_LIB_PATH_ENV).unwrap_or_default();
87     // Check the path exists.
88     if !va_h_path.is_empty() {
89         assert!(
90             Path::new(&va_h_path).exists(),
91             "{} doesn't exist",
92             va_h_path
93         );
94     }
95 
96     let (major, minor) = get_va_version(&va_h_path);
97     println!("libva {}.{} is used to generate bindings", major, minor);
98     let va_check_version = |desired_major: u32, desired_minor: u32| {
99         major > desired_major || (major == desired_major && minor >= desired_minor)
100     };
101 
102     if va_check_version(1, 21) {
103         println!("cargo::rustc-cfg=libva_1_21_or_higher");
104     }
105     if va_check_version(1, 20) {
106         println!("cargo::rustc-cfg=libva_1_20_or_higher")
107     }
108     if va_check_version(1, 19) {
109         println!("cargo::rustc-cfg=libva_1_19_or_higher")
110     }
111     if va_check_version(1, 16) {
112         println!("cargo::rustc-cfg=libva_1_16_or_higher")
113     }
114 
115     if !va_lib_path.is_empty() {
116         assert!(
117             Path::new(&va_lib_path).exists(),
118             "{} doesn't exist",
119             va_lib_path
120         );
121         println!("cargo:rustc-link-arg=-Wl,-rpath={}", va_lib_path);
122     }
123 
124     // Tell cargo to link va and va-drm objects dynamically.
125     println!("cargo:rustc-link-lib=dylib=va");
126     println!("cargo:rustc-link-lib=dylib=va-drm"); // for the vaGetDisplayDRM entrypoint
127 
128     let mut bindings_builder = vaapi_gen_builder(bindgen::builder()).header(WRAPPER_PATH);
129     if !va_h_path.is_empty() {
130         bindings_builder = bindings_builder.clang_arg(format!("-I{}", va_h_path));
131     }
132     let bindings = bindings_builder
133         .generate()
134         .expect("unable to generate bindings");
135 
136     let out_path = PathBuf::from(env::var("OUT_DIR").expect("`OUT_DIR` is not set"));
137 
138     bindings
139         .write_to_file(out_path.join("bindings.rs"))
140         .expect("Couldn't write bindings!");
141 }
142