1 // Copyright 2018 The Chromium OS Authors. All rights reserved.
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, PathBuf};
9 use std::process::Command;
10
11 // Performs a recursive search for a file with name under path and returns the full path if such a
12 // file is found.
scan_path<P: AsRef<Path>, O: AsRef<OsStr>>(path: P, name: O) -> Option<PathBuf>13 fn scan_path<P: AsRef<Path>, O: AsRef<OsStr>>(path: P, name: O) -> Option<PathBuf> {
14 for entry in fs::read_dir(path).ok()? {
15 if let Ok(entry) = entry {
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 }
30 None
31 }
32
33 // Searches for the given protocol in both the system wide and bundles protocols path.
find_protocol(name: &str) -> PathBuf34 fn find_protocol(name: &str) -> PathBuf {
35 let protocols_path =
36 env::var("WAYLAND_PROTOCOLS_PATH").unwrap_or("/usr/share/wayland-protocols".to_owned());
37 let protocol_file_name = PathBuf::from(format!("{}.xml", name));
38
39 // Prioritize the systems wayland protocols before using the bundled ones.
40 if let Some(found) = scan_path(protocols_path, &protocol_file_name) {
41 return found;
42 }
43
44 // Use bundled protocols as a fallback.
45 let protocol_path = Path::new("protocol").join(protocol_file_name);
46 assert!(
47 protocol_path.is_file(),
48 "unable to locate wayland protocol specification for `{}`",
49 name
50 );
51 protocol_path
52 }
53
compile_protocol<P: AsRef<Path>>(name: &str, out: P) -> PathBuf54 fn compile_protocol<P: AsRef<Path>>(name: &str, out: P) -> PathBuf {
55 let in_protocol = find_protocol(name);
56 println!("cargo:rerun-if-changed={}", in_protocol.display());
57 let out_code = out.as_ref().join(format!("{}.c", name));
58 let out_header = out.as_ref().join(format!("{}.h", name));
59 eprintln!("building protocol: {}", name);
60 Command::new("wayland-scanner")
61 .arg("code")
62 .arg(&in_protocol)
63 .arg(&out_code)
64 .output()
65 .unwrap();
66 Command::new("wayland-scanner")
67 .arg("client-header")
68 .arg(&in_protocol)
69 .arg(&out_header)
70 .output()
71 .unwrap();
72 out_code
73 }
74
main()75 fn main() {
76 println!("cargo:rerun-if-env-changed=WAYLAND_PROTOCOLS_PATH");
77 let out_dir = env::var("OUT_DIR").unwrap();
78
79 let mut build = cc::Build::new();
80 build.warnings(true);
81 build.warnings_into_errors(true);
82 build.include(&out_dir);
83 build.flag("-std=gnu11");
84 build.file("src/display_wl.c");
85 println!("cargo:rerun-if-changed=src/display_wl.c");
86
87 for protocol in &[
88 "aura-shell",
89 "linux-dmabuf-unstable-v1",
90 "xdg-shell-unstable-v6",
91 "viewporter",
92 ] {
93 build.file(compile_protocol(protocol, &out_dir));
94 }
95 build.compile("display_wl");
96
97 println!("cargo:rustc-link-lib=dylib=wayland-client");
98 }
99