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