xref: /aosp_15_r20/external/crosvm/gpu_display/build.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2018 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 std::env;
6 use std::ffi::OsStr;
7 use std::fs;
8 use std::path::Path;
9 use std::path::PathBuf;
10 use std::process::Command;
11 
12 // Performs a recursive search for a file with name under path and returns the full path if such a
13 // file is found.
scan_path<P: AsRef<Path>, O: AsRef<OsStr>>(path: P, name: O) -> Option<PathBuf>14 fn scan_path<P: AsRef<Path>, O: AsRef<OsStr>>(path: P, name: O) -> Option<PathBuf> {
15     for entry in (fs::read_dir(path).ok()?).flatten() {
16         let file_type = match entry.file_type() {
17             Ok(t) => t,
18             Err(_) => continue,
19         };
20 
21         if file_type.is_file() && entry.file_name() == name.as_ref() {
22             return Some(entry.path());
23         } else if file_type.is_dir() {
24             if let Some(found) = scan_path(entry.path(), name.as_ref()) {
25                 return Some(found);
26             }
27         }
28     }
29     None
30 }
31 
32 // Searches for the given protocol in both the system wide and bundles protocols path.
find_protocol(name: &str) -> PathBuf33 fn find_protocol(name: &str) -> PathBuf {
34     let protocol_file_name = PathBuf::from(format!("{}.xml", name));
35     // Prioritize the systems wayland protocols before using the bundled ones.
36     if let Ok(protocols_path) = pkg_config::get_variable("wayland-protocols", "pkgdatadir") {
37         if let Some(found) = scan_path(protocols_path, &protocol_file_name) {
38             return found;
39         }
40     }
41     let protocols_path = format!("/usr/share/wayland-protocols/stable/{}", name);
42     if let Some(found) = scan_path(protocols_path, &protocol_file_name) {
43         return found;
44     }
45     // Use bundled protocols as a fallback.
46     let protocol_path = Path::new("protocol").join(protocol_file_name);
47     assert!(
48         protocol_path.is_file(),
49         "unable to locate wayland protocol specification for `{}`",
50         name
51     );
52     protocol_path
53 }
54 
compile_protocol<P: AsRef<Path>>(name: &str, out: P) -> PathBuf55 fn compile_protocol<P: AsRef<Path>>(name: &str, out: P) -> PathBuf {
56     let in_protocol = find_protocol(name);
57     println!("cargo:rerun-if-changed={}", in_protocol.display());
58     let out_code = out.as_ref().join(format!("{}.c", name));
59     let out_header = out.as_ref().join(format!("{}.h", name));
60     eprintln!("building protocol: {}", name);
61 
62     let wayland_scanner = which::which("wayland-scanner")
63         .expect("missing wayland-scanner - please install libwayland-dev");
64 
65     Command::new(&wayland_scanner)
66         .arg("code")
67         .arg(&in_protocol)
68         .arg(&out_code)
69         .output()
70         .expect("wayland-scanner code failed");
71     Command::new(&wayland_scanner)
72         .arg("client-header")
73         .arg(&in_protocol)
74         .arg(&out_header)
75         .output()
76         .expect("wayland-scanner client-header failed");
77     out_code
78 }
79 
build_wayland()80 fn build_wayland() {
81     println!("cargo:rerun-if-env-changed=WAYLAND_PROTOCOLS_PATH");
82     let out_dir = env::var("OUT_DIR").unwrap();
83 
84     let mut build = cc::Build::new();
85     build.warnings(true);
86     build.warnings_into_errors(true);
87     build.include(&out_dir);
88     build.flag("-std=gnu11");
89     build.file("src/display_wl.c");
90     println!("cargo:rerun-if-changed=src/display_wl.c");
91 
92     for protocol in &[
93         "aura-shell",
94         "linux-dmabuf-unstable-v1",
95         "xdg-shell",
96         "viewporter",
97         "virtio-gpu-metadata-v1",
98     ] {
99         build.file(compile_protocol(protocol, &out_dir));
100     }
101     build.compile("display_wl");
102 
103     println!("cargo:rustc-link-lib=dylib=wayland-client");
104 }
105 
main()106 fn main() {
107     // Skip installing dependencies when generating documents.
108     if std::env::var("CARGO_DOC").is_ok() {
109         return;
110     }
111 
112     match std::env::var("CARGO_CFG_TARGET_OS").as_deref().unwrap() {
113         "linux" | "android" => {
114             build_wayland();
115         }
116         _ => {}
117     }
118 }
119