xref: /aosp_15_r20/external/crosvm/crosvm_control/build.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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 std::env;
6 use std::fs;
7 use std::path::PathBuf;
8 
9 use anyhow::bail;
10 use anyhow::Context;
11 use anyhow::Result;
12 use cbindgen::Config;
13 use cbindgen::EnumConfig;
14 use cbindgen::Language;
15 use cbindgen::RenameRule;
16 use tempfile::TempDir;
17 
18 static COPYRIGHT_CLAUSE: &str = "// Copyright 2022 The ChromiumOS Authors
19 // Use of this source code is governed by a BSD-style license that can be
20 // found in the LICENSE file.";
21 
22 static AUTOGENERATED_DISCLAIMER: &str =
23     "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */";
24 
25 static INCLUDE_GUARD: &str = "CROSVM_CONTROL_H_";
26 
27 static CROSVM_CONTROL_HEADER_NAME: &str = "crosvm_control.h";
28 
29 static REGISTERED_EVENTS_PROTO_FILENAME: &str = "registered_events.proto";
30 static REGISTERED_EVENTS_PROTO_SRC: &str = "../protos/src";
31 
main() -> Result<()>32 fn main() -> Result<()> {
33     // Skip building dependencies when generating documents.
34     if std::env::var("CARGO_DOC").is_ok() {
35         return Ok(());
36     }
37 
38     let proto_src =
39         PathBuf::from(REGISTERED_EVENTS_PROTO_SRC).join(REGISTERED_EVENTS_PROTO_FILENAME);
40 
41     if !proto_src.exists() {
42         bail!(
43             "can't find {} in {}, won't be able to export for users",
44             REGISTERED_EVENTS_PROTO_FILENAME,
45             REGISTERED_EVENTS_PROTO_SRC
46         );
47     }
48 
49     let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
50 
51     let output_dir = PathBuf::from(env::var("OUT_DIR").context("failed to get OUT_DIR")?);
52 
53     let proto_out = output_dir.join(REGISTERED_EVENTS_PROTO_FILENAME);
54 
55     fs::copy(proto_src, proto_out).context("couldn't copy proto to OUT_DIR")?;
56 
57     let output_file = output_dir
58         .join(CROSVM_CONTROL_HEADER_NAME)
59         .display()
60         .to_string();
61 
62     let config = Config {
63         language: Language::C,
64         cpp_compat: true,
65         header: Some(String::from(COPYRIGHT_CLAUSE)),
66         include_guard: Some(String::from(INCLUDE_GUARD)),
67         autogen_warning: Some(String::from(AUTOGENERATED_DISCLAIMER)),
68         include_version: true,
69         enumeration: EnumConfig {
70             rename_variants: RenameRule::ScreamingSnakeCase,
71             ..Default::default()
72         },
73         ..Default::default()
74     };
75 
76     cbindgen::Builder::new()
77         .with_crate(crate_dir)
78         .with_config(config)
79         .with_parse_deps(true)
80         .with_parse_include(&["swap"])
81         .generate()
82         .context("Unable to generate bindings")?
83         .write_to_file(output_file);
84 
85     // Do not perform the compilation check on Windows since GCC might not be installed.
86     if std::env::var("CARGO_CFG_WINDOWS").is_ok() {
87         return Ok(());
88     }
89 
90     // Do a quick compile test of the generated header to ensure it is valid
91     let temp_dir = TempDir::new()?;
92     let test_file = temp_dir
93         .path()
94         .join("crosvm_control_test.c")
95         .display()
96         .to_string();
97 
98     fs::write(
99         &test_file,
100         format!("{}{}{}", "#include \"", CROSVM_CONTROL_HEADER_NAME, "\""),
101     )
102     .context("Failed to write crosvm_control test C file")?;
103 
104     cc::Build::new()
105         .include(output_dir)
106         .file(test_file)
107         .compile("crosvm_control_test");
108 
109     // The above outputs cargo:rerun-if-env-changed directives, so we need to explicitly tell cargo
110     // to rerun this script if anything in src/ is changed.
111     println!("cargo:rerun-if-changed=src");
112     Ok(())
113 }
114