use std::collections::HashMap;
use std::env;
-use std::fs::File;
+use std::fs::{self, File};
use std::io::prelude::*;
use std::path::PathBuf;
use std::process;
use num_cpus;
-use rustc_serialize::Decodable;
-use toml::{Parser, Decoder, Value};
+use toml;
use util::{exe, push_exe_path};
/// Global configuration for the entire build and/or bootstrap.
pub llvm_static_stdcpp: bool,
pub llvm_link_shared: bool,
pub llvm_targets: Option<String>,
+ pub llvm_experimental_targets: Option<String>,
pub llvm_link_jobs: Option<u32>,
pub llvm_clean_rebuild: bool,
pub build: String,
pub host: Vec<String>,
pub target: Vec<String>,
- pub rustc: Option<PathBuf>,
- pub cargo: Option<PathBuf>,
pub local_rebuild: bool,
// dist misc
pub python: Option<PathBuf>,
pub configure_args: Vec<String>,
pub openssl_static: bool,
+
+
+ // These are either the stage0 downloaded binaries or the locally installed ones.
+ pub initial_cargo: PathBuf,
+ pub initial_rustc: PathBuf,
+
}
/// Per-target configuration stored in the global configuration structure.
#[derive(Default)]
pub struct Target {
+ /// Some(path to llvm-config) if using an external LLVM.
pub llvm_config: Option<PathBuf>,
pub jemalloc: Option<PathBuf>,
pub cc: Option<PathBuf>,
/// This structure uses `Decodable` to automatically decode a TOML configuration
/// file into this format, and then this is traversed and written into the above
/// `Config` structure.
-#[derive(RustcDecodable, Default)]
+#[derive(Deserialize, Default)]
+#[serde(deny_unknown_fields)]
+#[serde(rename_all = "kebab-case")]
struct TomlConfig {
build: Option<Build>,
install: Option<Install>,
}
/// TOML representation of various global build decisions.
-#[derive(RustcDecodable, Default, Clone)]
+#[derive(Deserialize, Default, Clone)]
+#[serde(deny_unknown_fields)]
+#[serde(rename_all = "kebab-case")]
struct Build {
build: Option<String>,
+ #[serde(default)]
host: Vec<String>,
+ #[serde(default)]
target: Vec<String>,
cargo: Option<String>,
rustc: Option<String>,
}
/// TOML representation of various global install decisions.
-#[derive(RustcDecodable, Default, Clone)]
+#[derive(Deserialize, Default, Clone)]
+#[serde(deny_unknown_fields)]
+#[serde(rename_all = "kebab-case")]
struct Install {
prefix: Option<String>,
sysconfdir: Option<String>,
}
/// TOML representation of how the LLVM build is configured.
-#[derive(RustcDecodable, Default)]
+#[derive(Deserialize, Default)]
+#[serde(deny_unknown_fields)]
+#[serde(rename_all = "kebab-case")]
struct Llvm {
ccache: Option<StringOrBool>,
ninja: Option<bool>,
version_check: Option<bool>,
static_libstdcpp: Option<bool>,
targets: Option<String>,
+ experimental_targets: Option<String>,
link_jobs: Option<u32>,
clean_rebuild: Option<bool>,
}
-#[derive(RustcDecodable, Default, Clone)]
+#[derive(Deserialize, Default, Clone)]
+#[serde(deny_unknown_fields)]
+#[serde(rename_all = "kebab-case")]
struct Dist {
sign_folder: Option<String>,
gpg_password_file: Option<String>,
src_tarball: Option<bool>,
}
-#[derive(RustcDecodable)]
+#[derive(Deserialize)]
+#[serde(untagged)]
enum StringOrBool {
String(String),
Bool(bool),
}
/// TOML representation of how the Rust build is configured.
-#[derive(RustcDecodable, Default)]
+#[derive(Deserialize, Default)]
+#[serde(deny_unknown_fields)]
+#[serde(rename_all = "kebab-case")]
struct Rust {
optimize: Option<bool>,
codegen_units: Option<u32>,
}
/// TOML representation of how each build target is configured.
-#[derive(RustcDecodable, Default)]
+#[derive(Deserialize, Default)]
+#[serde(deny_unknown_fields)]
+#[serde(rename_all = "kebab-case")]
struct TomlTarget {
llvm_config: Option<String>,
jemalloc: Option<String>,
let toml = file.map(|file| {
let mut f = t!(File::open(&file));
- let mut toml = String::new();
- t!(f.read_to_string(&mut toml));
- let mut p = Parser::new(&toml);
- let table = match p.parse() {
- Some(table) => table,
- None => {
- println!("failed to parse TOML configuration '{}':", file.to_str().unwrap());
- for err in p.errors.iter() {
- let (loline, locol) = p.to_linecol(err.lo);
- let (hiline, hicol) = p.to_linecol(err.hi);
- println!("{}:{}-{}:{}: {}", loline, locol, hiline,
- hicol, err.desc);
- }
- process::exit(2);
- }
- };
- let mut d = Decoder::new(Value::Table(table));
- match Decodable::decode(&mut d) {
- Ok(cfg) => cfg,
- Err(e) => {
- println!("failed to decode TOML: {}", e);
+ let mut contents = String::new();
+ t!(f.read_to_string(&mut contents));
+ match toml::from_str(&contents) {
+ Ok(table) => table,
+ Err(err) => {
+ println!("failed to parse TOML configuration '{}': {}",
+ file.display(), err);
process::exit(2);
}
}
config.target.push(target.clone());
}
}
- config.rustc = build.rustc.map(PathBuf::from);
- config.cargo = build.cargo.map(PathBuf::from);
config.nodejs = build.nodejs.map(PathBuf::from);
config.gdb = build.gdb.map(PathBuf::from);
config.python = build.python.map(PathBuf::from);
set(&mut config.llvm_static_stdcpp, llvm.static_libstdcpp);
set(&mut config.llvm_clean_rebuild, llvm.clean_rebuild);
config.llvm_targets = llvm.targets.clone();
+ config.llvm_experimental_targets = llvm.experimental_targets.clone();
config.llvm_link_jobs = llvm.link_jobs;
}
set(&mut config.rust_dist_src, t.src_tarball);
}
- return config
+ let cwd = t!(env::current_dir());
+ let out = cwd.join("build");
+
+ let stage0_root = out.join(&config.build).join("stage0/bin");
+ config.initial_rustc = match build.rustc {
+ Some(s) => PathBuf::from(s),
+ None => stage0_root.join(exe("rustc", &config.build)),
+ };
+ config.initial_cargo = match build.cargo {
+ Some(s) => PathBuf::from(s),
+ None => stage0_root.join(exe("cargo", &config.build)),
+ };
+
+ // compat with `./configure` while we're still using that
+ if fs::metadata("config.mk").is_ok() {
+ config.update_with_config_mk();
+ }
+
+ config
}
/// "Temporary" routine to parse `config.mk` into this configuration.
/// While we still have `./configure` this implements the ability to decode
/// that configuration into this. This isn't exactly a full-blown makefile
/// parser, but hey it gets the job done!
- pub fn update_with_config_mk(&mut self) {
+ fn update_with_config_mk(&mut self) {
let mut config = String::new();
File::open("config.mk").unwrap().read_to_string(&mut config).unwrap();
for line in config.lines() {
"CFG_TARGET" if value.len() > 0 => {
self.target.extend(value.split(" ").map(|s| s.to_string()));
}
+ "CFG_EXPERIMENTAL_TARGETS" if value.len() > 0 => {
+ self.llvm_experimental_targets = Some(value.to_string());
+ }
"CFG_MUSL_ROOT" if value.len() > 0 => {
self.musl_root = Some(parse_configure_path(value));
}
}
"CFG_LOCAL_RUST_ROOT" if value.len() > 0 => {
let path = parse_configure_path(value);
- self.rustc = Some(push_exe_path(path.clone(), &["bin", "rustc"]));
- self.cargo = Some(push_exe_path(path, &["bin", "cargo"]));
+ self.initial_rustc = push_exe_path(path.clone(), &["bin", "rustc"]);
+ self.initial_cargo = push_exe_path(path, &["bin", "cargo"]);
}
"CFG_PYTHON" if value.len() > 0 => {
let path = parse_configure_path(value);