extern crate phf_codegen;
use std::fs::File;
use std::io::{BufWriter, Write};
use std::path::Path;
use std::process::{Command, Stdio};
use std::fmt::Write as FmtWrite;
fn main(){
let mut cmd = std::env::var_os("RUSTC")
.map(|c| Command::new(c))
.unwrap_or(Command::new("rustc"));
let c = cmd
.args(&["--print=target-list"])
.stdout(Stdio::piped())
.spawn()
.expect("Could not spawn rustc!");
let targets = c.wait_with_output().expect("could not wait for rustc to exit");
if !targets.status.success() {
println!("rustc --print=target-list did not exit successfully");
std::process::exit(1);
}
let output = Path::new(&::std::env::var_os("OUT_DIR").expect("OUT_DIR")).join("builtins.rs");
let mut file = BufWriter::new(File::create(&output).expect("builtins.rs file"));
let stdout = String::from_utf8_lossy(&targets.stdout);
write!(&mut file, "static BUILTINS: phf::Map<&'static str, TargetInfo> = ").unwrap();
let mut map = phf_codegen::Map::new();
for line in stdout.lines() {
let cfg = cfg_for_target(line);
if !cfg.is_empty() {
map.entry(line, &cfg);
}
}
map.build(&mut file).unwrap();
write!(&mut file, ";").unwrap();
}
fn cfg_for_target(target: &str) -> String {
let mut cmd = std::env::var_os("RUSTC")
.map(|c| Command::new(c))
.unwrap_or(Command::new("rustc"));
let c = cmd
.args(&["--target", target, "--print=cfg"])
.stdout(Stdio::piped())
.spawn().and_then(|c| c.wait_with_output());
if let Ok(o) = c {
if o.status.success() {
let string = String::from_utf8_lossy(&o.stdout);
let mut switches = Vec::new();
let mut other_keys = Vec::new();
let (mut arch, mut os, mut env, mut endian, mut ptrw) = ("", "", "", "", "");
for (k, v) in parse(&string) {
match (k, v) {
("target_arch", Some(v)) => arch = v,
("target_os", Some(v)) => os = v,
("target_env", Some(v)) => env = v,
("target_endian", Some(v)) => endian = v,
("target_pointer_width", Some(v)) => ptrw = v,
(_, None) => match k {
"unix" |
"windows" |
"target_thread_local" => switches.push(k),
_ => println!("Switch `{}` blacklisted", k),
},
(k, Some(v)) => other_keys.push((k, v)),
}
}
let mut switches_fmt = String::with_capacity(1024);
let mut other_keys_fmt = String::with_capacity(4096);
switches_fmt.push_str("[");
for switch in switches {
write!(switches_fmt, "B({:?}), ", switch).expect("writes to String do not fail");
}
switches_fmt.push_str("]");
other_keys_fmt.push_str("[");
for (k, v) in other_keys {
write!(other_keys_fmt, "(B({:?}), B({:?})), ", k, v)
.expect("writes to String do not fail");
}
other_keys_fmt.push_str("]");
format!("TargetInfo {{ \
arch: B({:?}), \
os: B({:?}), \
env: B({:?}), \
endian: B({:?}), \
pointer_width: B({:?}), \
switches: B(&{}), \
other_keys: B(&{}) \
}}", arch, os, env, endian, ptrw, switches_fmt, other_keys_fmt)
} else {
println!("rustc --print=cfg --target={} did not exit successfully", target);
String::new()
}
} else {
String::new()
}
}
fn parse(i: &str) -> Vec<(&str, Option<&str>)> {
i.lines().map(|line| {
let mut split = line.split('=');
let key = split.next().expect("probably bug");
let val = split.next().map(|v| v.trim().trim_matches('"'));
debug_assert!(split.next().is_none());
(key, val)
}).collect()
}