-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild.rs
More file actions
150 lines (129 loc) · 6.13 KB
/
Copy pathbuild.rs
File metadata and controls
150 lines (129 loc) · 6.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// 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.
// Vendored verbatim from cros-libva (BSD-3-Clause); not subject to strict lints.
#![allow(clippy::all)]
use regex::Regex;
use std::env::{self};
use std::fs::read_to_string;
use std::path::{Path, PathBuf};
mod bindgen_gen;
use bindgen_gen::vaapi_gen_builder;
/// Wrapper file to use as input of bindgen.
const WRAPPER_PATH: &str = "libva-wrapper.h";
/// Generate `va_version.h` from the vendored `va_version.h.in` template by
/// extracting version numbers from `meson.build`. The `libva/` headers are
/// checked into the repo and refreshed by `just vendor`.
fn generate_vendored_version_header(out_dir: &Path) -> (u32, u32) {
let meson_build =
read_to_string("libva/meson.build").expect("failed to read libva/meson.build — run `just vendor`");
// Extract va_api_{major,minor,micro}_version from meson.build
let extract = |var_name: &str| -> String {
let re = Regex::new(&format!(r"{}\s*=\s*(\d+)", var_name)).unwrap();
re.captures(&meson_build)
.unwrap_or_else(|| panic!("{} not found in libva/meson.build", var_name))[1]
.to_string()
};
let major = extract("va_api_major_version");
let minor = extract("va_api_minor_version");
let micro = extract("va_api_micro_version");
let version = format!("{}.{}.{}", major, minor, micro);
let template = read_to_string("libva/va/va_version.h.in").expect("failed to read libva/va/va_version.h.in");
let generated = template
.replace("@VA_API_MAJOR_VERSION@", &major)
.replace("@VA_API_MINOR_VERSION@", &minor)
.replace("@VA_API_MICRO_VERSION@", µ)
.replace("@VA_API_VERSION@", &version);
let va_dir = out_dir.join("va");
std::fs::create_dir_all(&va_dir).expect("failed to create va dir in OUT_DIR");
std::fs::write(va_dir.join("va_version.h"), generated).expect("failed to write va_version.h");
// libva keeps va_drm.h under va/drm/ in its source tree, but installs it (and
// the wrapper includes it) as <va/va_drm.h>. Stage it next to the generated
// va_version.h so the OUT_DIR include path resolves <va/va_drm.h>.
std::fs::copy("libva/va/drm/va_drm.h", va_dir.join("va_drm.h")).expect("failed to stage va/drm/va_drm.h");
(
major.parse().expect("invalid major version"),
minor.parse().expect("invalid minor version"),
)
}
fn main() {
// NOTE: do not short-circuit for docs builds (CARGO_DOC / DOCS_RS). `src/bindings.rs`
// `include!`s the generated `$OUT_DIR/bindings.rs`, so skipping bindgen makes
// `cargo doc` (and docs.rs) fail to compile. The build is hermetic — it only needs
// libclang and the vendored headers, both available on docs.rs — so always generate.
let out_dir = PathBuf::from(env::var("OUT_DIR").expect("`OUT_DIR` is not set"));
// Bindings are generated from the vendored libva headers (checked into `libva/`,
// pinned to a known VA-API version so a system libva bump can't drift them).
// libva itself is linked on Linux (see below). The rlib compile needs only
// libclang + the vendored headers, so it builds on any OS for development.
let (major, minor) = generate_vendored_version_header(&out_dir);
println!("cargo:rerun-if-changed=libva/meson.build");
println!("cargo:rerun-if-changed=libva/va/va_version.h.in");
// Two include paths: the vendored `libva/` root so `#include <va/va.h>`
// resolves to `libva/va/va.h`, and OUT_DIR for the generated
// `<va/va_version.h>` and the staged `<va/va_drm.h>`.
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("`CARGO_MANIFEST_DIR` is not set"));
let va_h_path = manifest_dir.join("libva");
assert!(
va_h_path.join("meson.build").exists(),
"{} is missing the vendored libva headers — run `just vendor`",
va_h_path.display()
);
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)
};
// Declare the custom cfg flags to avoid warnings
println!("cargo::rustc-check-cfg=cfg(libva_1_21_or_higher)");
println!("cargo::rustc-check-cfg=cfg(libva_1_20_or_higher)");
println!("cargo::rustc-check-cfg=cfg(libva_1_19_or_higher)");
println!("cargo::rustc-check-cfg=cfg(libva_1_16_or_higher)");
println!("cargo::rustc-check-cfg=cfg(libva_1_15_or_higher)");
println!("cargo::rustc-check-cfg=cfg(libva_1_14_or_higher)");
println!("cargo::rustc-check-cfg=cfg(libva_1_10_or_higher)");
// Set the cfg flags based on version
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_check_version(1, 15) {
println!("cargo::rustc-cfg=libva_1_15_or_higher");
}
if va_check_version(1, 14) {
println!("cargo::rustc-cfg=libva_1_14_or_higher");
}
if va_check_version(1, 10) {
println!("cargo::rustc-cfg=libva_1_10_or_higher");
}
// Bindings are generated from the vendored headers (pinned, drift-proof), but
// the va* symbols still have to resolve, so link the system libva on Linux (the
// only platform with VA-API). VA-API's ABI is stable, so a system libva newer
// than the vendored headers links fine. On other hosts (e.g. macOS) this crate
// only ever builds as an rlib, which leaves the symbols for the final binary, so
// skip linking and keep it compilable for development.
if env::var("CARGO_CFG_TARGET_OS").as_deref() == Ok("linux") {
pkg_config::Config::new()
.probe("libva")
.expect("libva not found via pkg-config (install libva / libva-dev)");
pkg_config::Config::new()
.probe("libva-drm")
.expect("libva-drm not found via pkg-config (install libva / libva-dev)");
}
let bindings = vaapi_gen_builder(bindgen::builder())
.header(WRAPPER_PATH)
.clang_arg(format!("-I{}", va_h_path.display()))
.clang_arg(format!("-I{}", out_dir.display()))
.generate()
.expect("unable to generate bindings");
bindings
.write_to_file(out_dir.join("bindings.rs"))
.expect("Couldn't write bindings!");
}