vortex_build/
lib.rs

1use std::env;
2use std::ffi::OsStr;
3use std::fs::create_dir_all;
4use std::path::{Path, PathBuf};
5use std::process::Command;
6
7use cargo_metadata::MetadataCommand;
8//use cargo_metadata::{CargoOpt, MetadataCommand};
9use walkdir::WalkDir;
10
11fn manifest_dir() -> PathBuf {
12    PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap())
13        .canonicalize()
14        .expect("Failed to canonicalize CARGO_MANIFEST_DIR")
15}
16
17fn out_dir() -> PathBuf {
18    PathBuf::from(env::var("OUT_DIR").unwrap())
19        .canonicalize()
20        .expect("Failed to canonicalize OUT_DIR")
21}
22
23pub fn build() {
24    // FlatBuffers
25    if env::var("CARGO_FEATURE_FLATBUFFERS").ok().is_some() {
26        build_flatbuffers();
27    }
28
29    // Proto (prost)
30    if env::var("CARGO_FEATURE_PROTO").ok().is_some() {
31        build_proto();
32    }
33}
34
35pub fn build_proto() {
36    let proto_dir = manifest_dir().join("proto");
37    let proto_files = walk_files(&proto_dir, "proto");
38    let proto_out = out_dir().join("proto");
39
40    create_dir_all(&proto_out).expect("Failed to create proto output directory");
41
42    // The proto include path contains all $CRATE/proto directories of ourself plus all of our
43    // transitive dependencies.
44    let metadata = MetadataCommand::new()
45        .manifest_path(manifest_dir().join("Cargo.toml"))
46        .no_deps()
47        .exec()
48        .unwrap();
49    let proto_feature = "proto".to_string();
50    let pkg_name = env::var("CARGO_PKG_NAME").unwrap();
51    let proto_includes = metadata
52        .packages
53        .iter()
54        .filter(|&pkg| {
55            pkg.features.contains_key(&proto_feature)
56                || pkg.name == pkg_name
57        })
58        .map(|pkg| {
59            println!("cargo:warning=using proto files from {:?}", pkg.name);
60            pkg.manifest_path.parent().unwrap().join("proto")
61        })
62        .collect::<Vec<_>>();
63
64    prost_build::Config::new()
65        .out_dir(&proto_out)
66        .compile_protos(&proto_files, proto_includes.as_slice())
67        .expect("Failed to compile protos");
68}
69
70pub fn build_flatbuffers() {
71    let flatbuffers_dir = manifest_dir().join("flatbuffers");
72    let metadata = MetadataCommand::new()
73        .manifest_path(manifest_dir().join("Cargo.toml"))
74        .no_deps()
75        .exec()
76        .unwrap();
77    let fbs_feature = "flatbuffers".to_string();
78    let pkg_name = env::var("CARGO_PKG_NAME").unwrap();
79    let fbs_includes = metadata
80        .packages
81        .iter()
82        .filter(|&pkg| {
83            // pkg.features.contains_key(&fbs_feature) || pkg.id == metadata.root_package().unwrap().id
84            pkg.features.contains_key(&fbs_feature) || pkg.name == pkg_name
85        })
86        .map(|pkg| {
87            println!("cargo:warning=using fbs files from {:?}", pkg.name);
88            pkg.manifest_path
89                .parent()
90                .unwrap()
91                .join("flatbuffers")
92                .into_std_path_buf()
93        })
94        .collect::<Vec<_>>();
95
96    let fbs_files = walk_files(&flatbuffers_dir, "fbs");
97
98    let include_args: Vec<String> = fbs_includes
99        .iter()
100        .flat_map(|path| vec!["-I".to_string(), path.to_str().unwrap().to_string()])
101        .collect();
102
103    println!("cargo:warning=flatc {:?}", include_args);
104
105    check_call(
106        Command::new("flatc")
107            .arg("--rust")
108            .arg("--filename-suffix")
109            .arg("")
110            .args(include_args)
111            .arg("--include-prefix")
112            .arg("flatbuffers::deps")
113            .arg("-o")
114            .arg(out_dir().join("flatbuffers"))
115            .args(fbs_files),
116    )
117}
118
119/// Recursively walk for files with the given extension, adding them to rerun-if-changed.
120fn walk_files(dir: &Path, ext: &str) -> Vec<PathBuf> {
121    WalkDir::new(dir)
122        .into_iter()
123        .filter_map(|e| e.ok())
124        .filter(|e| e.path().extension() == Some(OsStr::new(ext)))
125        .map(|e| {
126            rerun_if_changed(e.path());
127            e.path().to_path_buf()
128        })
129        .collect()
130}
131
132fn rerun_if_changed(path: &Path) {
133    println!(
134        "cargo:rerun-if-changed={}",
135        path.canonicalize()
136            .unwrap_or_else(|_| panic!("failed to canonicalize {}", path.to_str().unwrap()))
137            .to_str()
138            .unwrap()
139    );
140}
141
142fn check_call(command: &mut Command) {
143    let name = command.get_program().to_str().unwrap().to_string();
144    let Ok(status) = command.status() else {
145        panic!("Failed to launch {}", &name)
146    };
147    if !status.success() {
148        panic!("{} failed with status {}", &name, status.code().unwrap());
149    }
150}