summary refs log tree commit diff
path: root/gpu_display/build.rs
blob: 69c0fae64f44b982e9b8f1cf76f40fa1eb6a7994 (plain) (blame)
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
// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::env;
use std::ffi::OsStr;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::Command;

// Performs a recursive search for a file with name under path and returns the full path if such a
// file is found.
fn scan_path<P: AsRef<Path>, O: AsRef<OsStr>>(path: P, name: O) -> Option<PathBuf> {
    for entry in fs::read_dir(path).ok()? {
        if let Ok(entry) = entry {
            let file_type = match entry.file_type() {
                Ok(t) => t,
                Err(_) => continue,
            };

            if file_type.is_file() && entry.file_name() == name.as_ref() {
                return Some(entry.path());
            } else if file_type.is_dir() {
                if let Some(found) = scan_path(entry.path(), name.as_ref()) {
                    return Some(found);
                }
            }
        }
    }
    None
}

// Searches for the given protocol in both the system wide and bundles protocols path.
fn find_protocol(name: &str) -> PathBuf {
    let protocols_path =
        env::var("WAYLAND_PROTOCOLS_PATH").unwrap_or("/usr/share/wayland-protocols".to_owned());
    let protocol_file_name = PathBuf::from(format!("{}.xml", name));

    // Prioritize the systems wayland protocols before using the bundled ones.
    if let Some(found) = scan_path(protocols_path, &protocol_file_name) {
        return found;
    }

    // Use bundled protocols as a fallback.
    let protocol_path = Path::new("protocol").join(protocol_file_name);
    assert!(
        protocol_path.is_file(),
        "unable to locate wayland protocol specification for `{}`",
        name
    );
    protocol_path
}

fn compile_protocol<P: AsRef<Path>>(name: &str, out: P) -> PathBuf {
    let in_protocol = find_protocol(name);
    println!("cargo:rerun-if-changed={}", in_protocol.display());
    let out_code = out.as_ref().join(format!("{}.c", name));
    let out_header = out.as_ref().join(format!("{}.h", name));
    eprintln!("building protocol: {}", name);
    Command::new("wayland-scanner")
        .arg("code")
        .arg(&in_protocol)
        .arg(&out_code)
        .output()
        .unwrap();
    Command::new("wayland-scanner")
        .arg("client-header")
        .arg(&in_protocol)
        .arg(&out_header)
        .output()
        .unwrap();
    out_code
}

fn main() {
    println!("cargo:rerun-if-env-changed=WAYLAND_PROTOCOLS_PATH");
    let out_dir = env::var("OUT_DIR").unwrap();

    let mut build = cc::Build::new();
    build.warnings(true);
    build.warnings_into_errors(true);
    build.include(&out_dir);
    build.flag("-std=gnu11");
    build.file("src/display_wl.c");
    println!("cargo:rerun-if-changed=src/display_wl.c");

    for protocol in &[
        "aura-shell",
        "linux-dmabuf-unstable-v1",
        "xdg-shell-unstable-v6",
        "viewporter",
    ] {
        build.file(compile_protocol(protocol, &out_dir));
    }
    build.compile("display_wl");

    println!("cargo:rustc-link-lib=dylib=wayland-client");
}