extern crate toml;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate clap;
extern crate fs_extra;
use clap::{App, AppSettings, Arg, SubCommand};
use std::env;
use std::fs;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str;
mod config;
mod util;
use crate::config::*;
use crate::util::*;
fn parse_args() -> Option<String> {
let args = App::new(crate_name!())
.version(crate_version!())
.about(crate_description!())
.bin_name("cargo")
.setting(AppSettings::SubcommandRequiredElseHelp)
.setting(AppSettings::GlobalVersion)
.subcommand(
SubCommand::with_name("sysroot")
.about(crate_description!())
.arg(
Arg::with_name("target")
.long("target")
.empty_values(false)
.takes_value(true),
),
).get_matches();
args.subcommand_matches("sysroot")
.and_then(|x| x.value_of("target").map(|s| s.to_string()))
}
fn get_target() -> PathBuf {
let cargo = Path::new("Cargo.toml");
let toml = {
let mut s = String::new();
fs::File::open(cargo)
.unwrap()
.read_to_string(&mut s)
.unwrap();
s
};
let target: CargoToml = toml::from_str(&toml).unwrap();
target.package.metadata.cargo_sysroot.target
}
struct BuildConfig {
rust_src: PathBuf,
local_sysroot: PathBuf,
target: PathBuf,
target_dir: PathBuf,
output_dir: PathBuf,
}
impl BuildConfig {
fn new() -> Self {
let sysroot = get_local_sysroot_dir();
let target = match parse_args() {
Some(x) => PathBuf::from(x),
None => get_target(),
};
Self {
rust_src: get_rust_src_dir(),
target_dir: get_target_dir(sysroot.clone()),
output_dir: get_output_dir(sysroot.clone(), &target),
local_sysroot: sysroot,
target: target,
}
}
}
fn build(name: &str, features: Option<&[&str]>, cfg: &BuildConfig) {
let lib = {
let mut x = cfg.rust_src.clone();
x.push(name);
x.push("Cargo.toml");
x
};
let features: Vec<_> = {
match features {
Some(fs) => fs.into_iter().collect(),
None => Default::default(),
}
};
let mut cmd = Command::new(env::var_os("CARGO").unwrap());
cmd.arg("rustc") .arg("--release")
.arg("--target")
.arg(&cfg.target)
.arg("--target-dir")
.arg(&cfg.target_dir)
.arg("--manifest-path")
.arg(lib)
.arg("-Z")
.arg("unstable-options");
if !features.is_empty() {
cmd.arg("--features");
let mut s = String::new();
features.into_iter().for_each(|x| s.push_str(x));
cmd.arg(s);
}
cmd.arg("--") .arg("-Z")
.arg("no-landing-pads");
let _ = cmd.status().unwrap();
let rlib = {
let mut x = cfg.target_dir.clone();
x.push(cfg.target.file_stem().unwrap());
x.push("release");
x.push(name);
x.set_extension("rlib");
x
};
let out = {
let mut x = cfg.output_dir.clone();
x.push(name);
x.set_extension("rlib");
x
};
let _ = fs::copy(rlib, out).unwrap();
}
fn generate_cargo_config(cfg: &BuildConfig) {
let path = PathBuf::from(".cargo/config");
fs::create_dir_all(path.parent().unwrap()).unwrap();
if path.exists() {
return;
}
let config = CargoBuild {
build: Build {
target: cfg.target.canonicalize().unwrap(),
rustflags: vec![
"--sysroot".to_owned(),
format!("{}", cfg.local_sysroot.to_str().unwrap()),
],
},
};
let toml = toml::to_string(&config).unwrap();
let mut f = fs::OpenOptions::new()
.write(true)
.create_new(true)
.open(path)
.unwrap();
f.write_all(toml.as_bytes()).unwrap();
}
fn main() {
let cfg = BuildConfig::new();
println!("Checking libcore and libcompiler_builtins");
generate_cargo_config(&cfg);
build("libcore", None, &cfg);
build("libcompiler_builtins", Some(&["mem"]), &cfg);
copy_host_tools(cfg.local_sysroot.clone());
}