1use serde::*;
2
3use std::fs;
4use std::ffi::OsString;
5use std::path::*;
6use std::process::*;
7
8
9
10macro_rules! fatal {
11 ( $($tt:tt)* ) => {{
12 eprintln!($($tt)*);
13 std::process::exit(1);
14 }};
15}
16
17#[derive(Deserialize)] struct Metadata { packages: Vec<Package> }
18#[derive(Deserialize)] struct Package { name: String, manifest_path: PathBuf }
19
20pub fn metabuild() {
21 if !std::env::var("TARGET").ok().unwrap_or(String::new()).ends_with("-msvc") {
22 return; }
24
25 let output = Command::new("cargo").arg("metadata").arg("--format-version").arg("1").stderr(Stdio::inherit()).output();
26 let output = output.unwrap_or_else(|err| fatal!("natvis-pdbs failed to execute `cargo metadata --format-version 1`: {}", err));
27 match output.status.code() {
28 Some(0) => {},
29 Some(n) => fatal!("`cargo metadata --format-version 1`: exit code {}", n),
30 None => fatal!("`cargo metadata --format-version 1`: terminated by signal"),
31 }
32
33 let metadata : Metadata = serde_json::from_slice(&output.stdout[..]).unwrap_or_else(|err| fatal!("natvis-pdbs failed to parse `cargo metadata --format-version 1`: {}", err));
34
35 println!("cargo:rerun-if-env-changed=LINK");
36 let mut link_args = std::env::var_os("LINK").unwrap_or(OsString::new());
37 let mut link_args_changed = false;
38
39 for package in metadata.packages.iter() {
40 let root = if let Some(p) = package.manifest_path.parent() {
41 p
42 } else {
43 println!("cargo:warning=Package {:?}'s manifest_path {:?} has no parent directory, skipping in search for natvis files...", &package.name, &package.manifest_path);
44 continue
45 };
46
47 let src = root.join("src");
48
49 let dm = root.join("debug_metadata");
50 for (dir, warn_if_missing ) in [
54 (root, true ),
55 (src.as_path(), false ),
56 (dm.as_path(), false ),
57 ].iter().copied() {
58 let entries = if let Ok(e) = fs::read_dir(dir) {
59 e
60 } else if warn_if_missing {
61 println!("cargo:warning={:?} not readable, skipping in search for natvis files...", dir);
62 continue
63 } else {
64 continue
67 };
68
69 println!("cargo:rerun-if-changed={}", dir.display());
70
71 for entry in entries {
72 let entry = if let Ok(e) = entry { e } else { continue };
73 let path = entry.path();
74 if !path.is_file() { continue }
75 let ext = if let Some(e) = path.extension().and_then(|os| os.to_str()) { e } else { continue };
76 if !ext.eq_ignore_ascii_case("natvis") { continue }
77
78 let path = path.canonicalize();
81 let path = if let Some(p) = path.as_ref().ok().and_then(|p| p.to_str()) {
82 if p.starts_with("\\\\?\\") { &p[4..] } else { p } } else {
84 println!("cargo:warning={:?} cannot be canonicalized, skipping embedding this natvis file...", path);
85 continue;
86 };
87
88 if link_args.len() != 0 {
89 link_args.push(" ");
90 }
91 link_args.push("\"/NATVIS:");
92 link_args.push(path);
93 link_args.push("\"");
94 link_args_changed = true;
95 println!("cargo:rerun-if-changed={}", path);
96 }
97 }
98 }
99
100 if link_args_changed {
101 std::env::set_var("LINK", &link_args);
102 println!("cargo:rustc-env=LINK={}", link_args.to_string_lossy());
103 }
104}