Copy path View file

Large diffs are not rendered by default.

Oops, something went wrong.
Copy path View file
@@ -0,0 +1,267 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::any::{Any, TypeId};
use std::borrow::Borrow;
use std::cell::RefCell;
use std::collections::HashMap;
use std::convert::AsRef;
use std::ffi::OsStr;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
use std::path::{Path, PathBuf};
use std::sync::Mutex;

use builder::Step;

pub struct Interned<T>(usize, PhantomData<*const T>);

This comment has been minimized.

@aidanhs

aidanhs Jul 16, 2017

Member

Why not a T rather than a *const T?

This comment has been minimized.

@Mark-Simulacrum

Mark-Simulacrum Jul 16, 2017

Author Member

We don't own the T here, and I think this is how to indicate that -- the T is owned by the TyInterner. Correct me if I'm wrong, though.

This comment has been minimized.

@aidanhs

aidanhs Jul 17, 2017

Member

It's a phantomdata so I don't know that matters? Unless it's a convention thing.


impl Default for Interned<String> {
fn default() -> Self {
INTERNER.intern_string(String::default())
}
}

impl Default for Interned<PathBuf> {
fn default() -> Self {
INTERNER.intern_path(PathBuf::default())
}
}

impl<T> Copy for Interned<T> {}
impl<T> Clone for Interned<T> {
fn clone(&self) -> Interned<T> {
*self
}
}

impl<T> PartialEq for Interned<T> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<T> Eq for Interned<T> {}

impl PartialEq<str> for Interned<String> {
fn eq(&self, other: &str) -> bool {
*self == other
}
}
impl<'a> PartialEq<&'a str> for Interned<String> {
fn eq(&self, other: &&str) -> bool {
**self == **other
}
}
impl<'a, T> PartialEq<&'a Interned<T>> for Interned<T> {
fn eq(&self, other: &&Self) -> bool {
self.0 == other.0
}
}
impl<'a, T> PartialEq<Interned<T>> for &'a Interned<T> {
fn eq(&self, other: &Interned<T>) -> bool {
self.0 == other.0
}
}

unsafe impl<T> Send for Interned<T> {}
unsafe impl<T> Sync for Interned<T> {}

impl fmt::Display for Interned<String> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s: &str = &*self;
f.write_str(s)
}
}

impl fmt::Debug for Interned<String> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s: &str = &*self;
f.write_fmt(format_args!("{:?}", s))
}
}
impl fmt::Debug for Interned<PathBuf> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let s: &Path = &*self;
f.write_fmt(format_args!("{:?}", s))
}
}

impl Hash for Interned<String> {
fn hash<H: Hasher>(&self, state: &mut H) {
let l = INTERNER.strs.lock().unwrap();
l.get(*self).hash(state)
}
}

impl Hash for Interned<PathBuf> {
fn hash<H: Hasher>(&self, state: &mut H) {
let l = INTERNER.paths.lock().unwrap();
l.get(*self).hash(state)
}
}

impl Deref for Interned<String> {
type Target = str;
fn deref(&self) -> &'static str {
let l = INTERNER.strs.lock().unwrap();
unsafe { mem::transmute::<&str, &'static str>(l.get(*self)) }
}
}

impl Deref for Interned<PathBuf> {
type Target = Path;
fn deref(&self) -> &'static Path {
let l = INTERNER.paths.lock().unwrap();
unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self)) }
}
}

impl AsRef<Path> for Interned<PathBuf> {
fn as_ref(&self) -> &'static Path {
let l = INTERNER.paths.lock().unwrap();
unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self)) }
}
}

impl AsRef<Path> for Interned<String> {
fn as_ref(&self) -> &'static Path {
let l = INTERNER.strs.lock().unwrap();
unsafe { mem::transmute::<&Path, &'static Path>(l.get(*self).as_ref()) }
}
}

impl AsRef<OsStr> for Interned<PathBuf> {
fn as_ref(&self) -> &'static OsStr {
let l = INTERNER.paths.lock().unwrap();
unsafe { mem::transmute::<&OsStr, &'static OsStr>(l.get(*self).as_ref()) }
}
}

impl AsRef<OsStr> for Interned<String> {
fn as_ref(&self) -> &'static OsStr {
let l = INTERNER.strs.lock().unwrap();
unsafe { mem::transmute::<&OsStr, &'static OsStr>(l.get(*self).as_ref()) }
}
}


struct TyIntern<T> {
items: Vec<T>,
set: HashMap<T, Interned<T>>,
}

impl<T: Hash + Clone + Eq> TyIntern<T> {
fn new() -> TyIntern<T> {
TyIntern {
items: Vec::new(),
set: HashMap::new(),
}
}

fn intern_borrow<B>(&mut self, item: &B) -> Interned<T>
where
B: Eq + Hash + ToOwned<Owned=T> + ?Sized,
T: Borrow<B>,
{
if let Some(i) = self.set.get(&item) {
return *i;
}
let item = item.to_owned();
let interned = Interned(self.items.len(), PhantomData::<*const T>);
self.set.insert(item.clone(), interned);
self.items.push(item);
interned
}

fn intern(&mut self, item: T) -> Interned<T> {
if let Some(i) = self.set.get(&item) {
return *i;
}
let interned = Interned(self.items.len(), PhantomData::<*const T>);
self.set.insert(item.clone(), interned);
self.items.push(item);
interned
}

fn get(&self, i: Interned<T>) -> &T {
&self.items[i.0]
}
}

pub struct Interner {
strs: Mutex<TyIntern<String>>,
paths: Mutex<TyIntern<PathBuf>>,
}

impl Interner {
fn new() -> Interner {
Interner {
strs: Mutex::new(TyIntern::new()),
paths: Mutex::new(TyIntern::new()),
}
}

pub fn intern_str(&self, s: &str) -> Interned<String> {
self.strs.lock().unwrap().intern_borrow(s)
}
pub fn intern_string(&self, s: String) -> Interned<String> {
self.strs.lock().unwrap().intern(s)
}

pub fn intern_path(&self, s: PathBuf) -> Interned<PathBuf> {
self.paths.lock().unwrap().intern(s)
}
}

lazy_static! {
pub static ref INTERNER: Interner = Interner::new();

This comment has been minimized.

@alexcrichton

alexcrichton Jul 17, 2017

Member

Out of curiosity, is this really necessary? I'd figure that Rc<String> is more than good enough for rustbuild.

This comment has been minimized.

@Mark-Simulacrum

Mark-Simulacrum Jul 17, 2017

Author Member

Well, sort of. Rc<String> is less ergonomic since we have to call clone on it, whereas Interned<String> is Copy. I'm open to either though.

This comment has been minimized.

@aidanhs

aidanhs Jul 17, 2017

Member

Clone pollution is pretty ugly, e.g. Mark-Simulacrum@b61ee03#diff-1060b80265828cceb0977458cb33083cL1238.

I'm +1 on leaving it as Copy.

This comment has been minimized.

@alexcrichton

alexcrichton Jul 19, 2017

Member

Ah right yeah forgot to remove this comment as I figured out why as I was reading further, This seems ok.

}

/// This is essentially a HashMap which allows storing any type in its input and
/// any type in its output. It is a write-once cache; values are never evicted,
/// which means that references to the value can safely be returned from the
/// get() method.
#[derive(Debug)]
pub struct Cache(
RefCell<HashMap<
TypeId,
Box<Any>, // actually a HashMap<Step, Interned<Step::Output>>
>>
);

impl Cache {
pub fn new() -> Cache {
Cache(RefCell::new(HashMap::new()))
}

pub fn put<S: Step>(&self, step: S, value: S::Output) {
let mut cache = self.0.borrow_mut();
let type_id = TypeId::of::<S>();
let stepcache = cache.entry(type_id)
.or_insert_with(|| Box::new(HashMap::<S, S::Output>::new()))
.downcast_mut::<HashMap<S, S::Output>>()
.expect("invalid type mapped");
assert!(!stepcache.contains_key(&step), "processing {:?} a second time", step);
stepcache.insert(step, value);
}

pub fn get<S: Step>(&self, step: &S) -> Option<S::Output> {
let mut cache = self.0.borrow_mut();
let type_id = TypeId::of::<S>();
let stepcache = cache.entry(type_id)
.or_insert_with(|| Box::new(HashMap::<S, S::Output>::new()))
.downcast_mut::<HashMap<S, S::Output>>()
.expect("invalid type mapped");
stepcache.get(step).cloned()
}
}
Copy path View file
@@ -38,6 +38,7 @@ use gcc;

use Build;
use config::Target;
use cache::Interned;

pub fn find(build: &mut Build) {
// For all targets we're going to need a C compiler for building some shims
@@ -50,11 +51,11 @@ pub fn find(build: &mut Build) {
cfg.cargo_metadata(false).opt_level(0).debug(false)
.target(target).host(&build.build);

let config = build.config.target_config.get(target);
let config = build.config.target_config.get(&target);
if let Some(cc) = config.and_then(|c| c.cc.as_ref()) {
cfg.compiler(cc);
} else {
set_compiler(&mut cfg, "gcc", target, config, build);
set_compiler(&mut cfg, "gcc", *target, config, build);
}

let compiler = cfg.get_compiler();
@@ -63,7 +64,7 @@ pub fn find(build: &mut Build) {
if let Some(ref ar) = ar {
build.verbose(&format!("AR_{} = {:?}", target, ar));
}
build.cc.insert(target.to_string(), (compiler, ar));
build.cc.insert(*target, (compiler, ar));
}

// For all host triples we need to find a C++ compiler as well
@@ -78,20 +79,20 @@ pub fn find(build: &mut Build) {
if let Some(cxx) = config.and_then(|c| c.cxx.as_ref()) {
cfg.compiler(cxx);
} else {
set_compiler(&mut cfg, "g++", host, config, build);
set_compiler(&mut cfg, "g++", *host, config, build);
}
let compiler = cfg.get_compiler();
build.verbose(&format!("CXX_{} = {:?}", host, compiler.path()));
build.cxx.insert(host.to_string(), compiler);
build.cxx.insert(*host, compiler);
}
}

fn set_compiler(cfg: &mut gcc::Config,
gnu_compiler: &str,
target: &str,
target: Interned<String>,
config: Option<&Target>,
build: &Build) {
match target {
match &*target {
// When compiling for android we may have the NDK configured in the
// config.toml in which case we look there. Otherwise the default
// compiler already takes into account the triple in question.
Copy path View file

Large diffs are not rendered by default.

Oops, something went wrong.
Copy path View file

Large diffs are not rendered by default.

Oops, something went wrong.
Copy path View file
@@ -21,9 +21,9 @@ 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};
use cache::{INTERNER, Interned};

/// Global configuration for the entire build and/or bootstrap.
///
@@ -46,7 +46,7 @@ pub struct Config {
pub docs: bool,
pub locked_deps: bool,
pub vendor: bool,
pub target_config: HashMap<String, Target>,
pub target_config: HashMap<Interned<String>, Target>,
pub full_bootstrap: bool,
pub extended: bool,
pub sanitizers: bool,
@@ -78,9 +78,9 @@ pub struct Config {
pub rust_debuginfo_tests: bool,
pub rust_dist_src: bool,

pub build: String,
pub host: Vec<String>,
pub target: Vec<String>,
pub build: Interned<String>,
pub host: Vec<Interned<String>>,
pub target: Vec<Interned<String>>,
pub local_rebuild: bool,

// dist misc
@@ -138,7 +138,8 @@ pub struct Target {
/// 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, rename_all = "kebab-case")]
struct TomlConfig {
build: Option<Build>,
install: Option<Install>,
@@ -149,10 +150,13 @@ struct TomlConfig {
}

/// TOML representation of various global build decisions.
#[derive(RustcDecodable, Default, Clone)]
#[derive(Deserialize, Default, Clone)]
#[serde(deny_unknown_fields, 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>,
@@ -174,7 +178,8 @@ struct Build {
}

/// TOML representation of various global install decisions.
#[derive(RustcDecodable, Default, Clone)]
#[derive(Deserialize, Default, Clone)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
struct Install {
prefix: Option<String>,
sysconfdir: Option<String>,
@@ -185,7 +190,8 @@ struct Install {
}

/// TOML representation of how the LLVM build is configured.
#[derive(RustcDecodable, Default)]
#[derive(Deserialize, Default)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
struct Llvm {
ccache: Option<StringOrBool>,
ninja: Option<bool>,
@@ -200,15 +206,17 @@ struct Llvm {
clean_rebuild: Option<bool>,
}

#[derive(RustcDecodable, Default, Clone)]
#[derive(Deserialize, Default, Clone)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
struct Dist {
sign_folder: Option<String>,
gpg_password_file: Option<String>,
upload_addr: Option<String>,
src_tarball: Option<bool>,
}

#[derive(RustcDecodable)]
#[derive(Deserialize)]
#[serde(untagged)]
enum StringOrBool {
String(String),
Bool(bool),
@@ -221,7 +229,8 @@ impl Default for StringOrBool {
}

/// TOML representation of how the Rust build is configured.
#[derive(RustcDecodable, Default)]
#[derive(Deserialize, Default)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
struct Rust {
optimize: Option<bool>,
codegen_units: Option<u32>,
@@ -243,7 +252,8 @@ struct Rust {
}

/// TOML representation of how each build target is configured.
#[derive(RustcDecodable, Default)]
#[derive(Deserialize, Default)]
#[serde(deny_unknown_fields, rename_all = "kebab-case")]
struct TomlTarget {
llvm_config: Option<String>,
jemalloc: Option<String>,
@@ -266,50 +276,39 @@ impl Config {
config.docs = true;
config.rust_rpath = true;
config.rust_codegen_units = 1;
config.build = build.to_string();
config.build = INTERNER.intern_str(build);
config.channel = "dev".to_string();
config.codegen_tests = true;
config.rust_dist_src = true;

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);
}
}
}).unwrap_or_else(|| TomlConfig::default());

let build = toml.build.clone().unwrap_or(Build::default());
set(&mut config.build, build.build.clone());
set(&mut config.build, build.build.clone().map(|x| INTERNER.intern_string(x)));
config.host.push(config.build.clone());
for host in build.host.iter() {
if !config.host.contains(host) {
config.host.push(host.clone());
let host = INTERNER.intern_str(host);
if !config.host.contains(&host) {
config.host.push(host);
}
}
for target in config.host.iter().chain(&build.target) {
if !config.target.contains(target) {
config.target.push(target.clone());
for target in config.host.iter().cloned()
.chain(build.target.iter().map(|s| INTERNER.intern_str(s)))
{
if !config.target.contains(&target) {
config.target.push(target);
}
}
config.nodejs = build.nodejs.map(PathBuf::from);
@@ -402,7 +401,7 @@ impl Config {
target.musl_root = cfg.musl_root.clone().map(PathBuf::from);
target.qemu_rootfs = cfg.qemu_rootfs.clone().map(PathBuf::from);

config.target_config.insert(triple.clone(), target);
config.target_config.insert(INTERNER.intern_string(triple.clone()), target);
}
}

@@ -504,13 +503,13 @@ impl Config {
}

match key {
"CFG_BUILD" if value.len() > 0 => self.build = value.to_string(),
"CFG_BUILD" if value.len() > 0 => self.build = INTERNER.intern_str(value),
"CFG_HOST" if value.len() > 0 => {
self.host.extend(value.split(" ").map(|s| s.to_string()));
self.host.extend(value.split(" ").map(|s| INTERNER.intern_str(s)));

}
"CFG_TARGET" if value.len() > 0 => {
self.target.extend(value.split(" ").map(|s| s.to_string()));
self.target.extend(value.split(" ").map(|s| INTERNER.intern_str(s)));
}
"CFG_EXPERIMENTAL_TARGETS" if value.len() > 0 => {
self.llvm_experimental_targets = Some(value.to_string());
@@ -519,33 +518,28 @@ impl Config {
self.musl_root = Some(parse_configure_path(value));
}
"CFG_MUSL_ROOT_X86_64" if value.len() > 0 => {
let target = "x86_64-unknown-linux-musl".to_string();
let target = self.target_config.entry(target)
.or_insert(Target::default());
let target = INTERNER.intern_str("x86_64-unknown-linux-musl");
let target = self.target_config.entry(target).or_insert(Target::default());
target.musl_root = Some(parse_configure_path(value));
}
"CFG_MUSL_ROOT_I686" if value.len() > 0 => {
let target = "i686-unknown-linux-musl".to_string();
let target = self.target_config.entry(target)
.or_insert(Target::default());
let target = INTERNER.intern_str("i686-unknown-linux-musl");
let target = self.target_config.entry(target).or_insert(Target::default());
target.musl_root = Some(parse_configure_path(value));
}
"CFG_MUSL_ROOT_ARM" if value.len() > 0 => {
let target = "arm-unknown-linux-musleabi".to_string();
let target = self.target_config.entry(target)
.or_insert(Target::default());
let target = INTERNER.intern_str("arm-unknown-linux-musleabi");
let target = self.target_config.entry(target).or_insert(Target::default());
target.musl_root = Some(parse_configure_path(value));
}
"CFG_MUSL_ROOT_ARMHF" if value.len() > 0 => {
let target = "arm-unknown-linux-musleabihf".to_string();
let target = self.target_config.entry(target)
.or_insert(Target::default());
let target = INTERNER.intern_str("arm-unknown-linux-musleabihf");
let target = self.target_config.entry(target).or_insert(Target::default());
target.musl_root = Some(parse_configure_path(value));
}
"CFG_MUSL_ROOT_ARMV7" if value.len() > 0 => {
let target = "armv7-unknown-linux-musleabihf".to_string();
let target = self.target_config.entry(target)
.or_insert(Target::default());
let target = INTERNER.intern_str("armv7-unknown-linux-musleabihf");
let target = self.target_config.entry(target).or_insert(Target::default());
target.musl_root = Some(parse_configure_path(value));
}
"CFG_DEFAULT_AR" if value.len() > 0 => {
@@ -593,33 +587,28 @@ impl Config {
target.jemalloc = Some(parse_configure_path(value).join("libjemalloc_pic.a"));
}
"CFG_ARM_LINUX_ANDROIDEABI_NDK" if value.len() > 0 => {
let target = "arm-linux-androideabi".to_string();
let target = self.target_config.entry(target)
.or_insert(Target::default());
let target = INTERNER.intern_str("arm-linux-androideabi");
let target = self.target_config.entry(target).or_insert(Target::default());
target.ndk = Some(parse_configure_path(value));
}
"CFG_ARMV7_LINUX_ANDROIDEABI_NDK" if value.len() > 0 => {
let target = "armv7-linux-androideabi".to_string();
let target = self.target_config.entry(target)
.or_insert(Target::default());
let target = INTERNER.intern_str("armv7-linux-androideabi");
let target = self.target_config.entry(target).or_insert(Target::default());
target.ndk = Some(parse_configure_path(value));
}
"CFG_I686_LINUX_ANDROID_NDK" if value.len() > 0 => {
let target = "i686-linux-android".to_string();
let target = self.target_config.entry(target)
.or_insert(Target::default());
let target = INTERNER.intern_str("i686-linux-android");
let target = self.target_config.entry(target).or_insert(Target::default());
target.ndk = Some(parse_configure_path(value));
}
"CFG_AARCH64_LINUX_ANDROID_NDK" if value.len() > 0 => {
let target = "aarch64-linux-android".to_string();
let target = self.target_config.entry(target)
.or_insert(Target::default());
let target = INTERNER.intern_str("aarch64-linux-android");
let target = self.target_config.entry(target).or_insert(Target::default());
target.ndk = Some(parse_configure_path(value));
}
"CFG_X86_64_LINUX_ANDROID_NDK" if value.len() > 0 => {
let target = "x86_64-linux-android".to_string();
let target = self.target_config.entry(target)
.or_insert(Target::default());
let target = INTERNER.intern_str("x86_64-linux-android");
let target = self.target_config.entry(target).or_insert(Target::default());
target.ndk = Some(parse_configure_path(value));
}
"CFG_LOCAL_RUST_ROOT" if value.len() > 0 => {
@@ -643,9 +632,8 @@ impl Config {
.collect();
}
"CFG_QEMU_ARMHF_ROOTFS" if value.len() > 0 => {
let target = "arm-unknown-linux-gnueabihf".to_string();
let target = self.target_config.entry(target)
.or_insert(Target::default());
let target = INTERNER.intern_str("arm-unknown-linux-gnueabihf");
let target = self.target_config.entry(target).or_insert(Target::default());
target.qemu_rootfs = Some(parse_configure_path(value));
}
_ => {}
Copy path View file

Large diffs are not rendered by default.

Oops, something went wrong.
Copy path View file

Large diffs are not rendered by default.

Oops, something went wrong.
Copy path View file
@@ -23,17 +23,19 @@ use getopts::Options;
use Build;
use config::Config;
use metadata;
use step;
use builder::Builder;

use cache::{Interned, INTERNER};

/// Deserialized version of all flags for this compile.
pub struct Flags {
pub verbose: usize, // verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose
pub on_fail: Option<String>,
pub stage: Option<u32>,
pub keep_stage: Option<u32>,
pub build: String,
pub host: Vec<String>,
pub target: Vec<String>,
pub build: Interned<String>,
pub host: Vec<Interned<String>>,
pub target: Vec<Interned<String>>,
pub config: Option<PathBuf>,
pub src: PathBuf,
pub jobs: Option<u32>,
@@ -246,10 +248,9 @@ Arguments:
config.build = flags.build.clone();
let mut build = Build::new(flags, config);
metadata::build(&mut build);
let maybe_rules_help = step::build_rules(&build).get_help(subcommand);
if maybe_rules_help.is_some() {
extra_help.push_str(maybe_rules_help.unwrap().as_str());
}

let maybe_rules_help = Builder::get_help(&build, subcommand.as_str());
extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str());
} else {
extra_help.push_str(format!("Run `./x.py {} -h -v` to see a list of available paths.",
subcommand).as_str());
@@ -319,11 +320,13 @@ Arguments:
stage: stage,
on_fail: matches.opt_str("on-fail"),
keep_stage: matches.opt_str("keep-stage").map(|j| j.parse().unwrap()),
build: matches.opt_str("build").unwrap_or_else(|| {
build: INTERNER.intern_string(matches.opt_str("build").unwrap_or_else(|| {
env::var("BUILD").unwrap()
}),
host: split(matches.opt_strs("host")),
target: split(matches.opt_strs("target")),
})),
host: split(matches.opt_strs("host"))
.into_iter().map(|x| INTERNER.intern_string(x)).collect::<Vec<_>>(),
target: split(matches.opt_strs("target"))
.into_iter().map(|x| INTERNER.intern_string(x)).collect::<Vec<_>>(),
config: cfg_file,
src: src,
jobs: matches.opt_str("jobs").map(|j| j.parse().unwrap()),
Copy path View file
@@ -18,121 +18,99 @@ use std::fs;
use std::path::{Path, PathBuf, Component};
use std::process::Command;

use Build;
use dist::{pkgname, sanitize_sh, tmpdir};

pub struct Installer<'a> {
build: &'a Build,
prefix: PathBuf,
sysconfdir: PathBuf,
docdir: PathBuf,
bindir: PathBuf,
libdir: PathBuf,
mandir: PathBuf,
empty_dir: PathBuf,
}
use dist::{self, pkgname, sanitize_sh, tmpdir};

impl<'a> Drop for Installer<'a> {
fn drop(&mut self) {
t!(fs::remove_dir_all(&self.empty_dir));
}
}
use builder::{Builder, RunConfig, ShouldRun, Step};
use cache::Interned;

impl<'a> Installer<'a> {
pub fn new(build: &'a Build) -> Installer<'a> {
let prefix_default = PathBuf::from("/usr/local");
let sysconfdir_default = PathBuf::from("/etc");
let docdir_default = PathBuf::from("share/doc/rust");
let bindir_default = PathBuf::from("bin");
let libdir_default = PathBuf::from("lib");
let mandir_default = PathBuf::from("share/man");
let prefix = build.config.prefix.as_ref().unwrap_or(&prefix_default);
let sysconfdir = build.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default);
let docdir = build.config.docdir.as_ref().unwrap_or(&docdir_default);
let bindir = build.config.bindir.as_ref().unwrap_or(&bindir_default);
let libdir = build.config.libdir.as_ref().unwrap_or(&libdir_default);
let mandir = build.config.mandir.as_ref().unwrap_or(&mandir_default);

let sysconfdir = prefix.join(sysconfdir);
let docdir = prefix.join(docdir);
let bindir = prefix.join(bindir);
let libdir = prefix.join(libdir);
let mandir = prefix.join(mandir);

let destdir = env::var_os("DESTDIR").map(PathBuf::from);

let prefix = add_destdir(&prefix, &destdir);
let sysconfdir = add_destdir(&sysconfdir, &destdir);
let docdir = add_destdir(&docdir, &destdir);
let bindir = add_destdir(&bindir, &destdir);
let libdir = add_destdir(&libdir, &destdir);
let mandir = add_destdir(&mandir, &destdir);

let empty_dir = build.out.join("tmp/empty_dir");

t!(fs::create_dir_all(&empty_dir));

Installer {
build,
prefix,
sysconfdir,
docdir,
bindir,
libdir,
mandir,
empty_dir,
}
}
pub fn install_docs(builder: &Builder, stage: u32, host: Interned<String>) {
install_sh(builder, "docs", "rust-docs", stage, Some(host));
}

pub fn install_docs(&self, stage: u32, host: &str) {
self.install_sh("docs", "rust-docs", stage, Some(host));
pub fn install_std(builder: &Builder, stage: u32) {
for target in builder.build.config.target.iter() {
install_sh(builder, "std", "rust-std", stage, Some(*target));
}
}

pub fn install_std(&self, stage: u32) {
for target in self.build.config.target.iter() {
self.install_sh("std", "rust-std", stage, Some(target));
}
}
pub fn install_cargo(builder: &Builder, stage: u32, host: Interned<String>) {
install_sh(builder, "cargo", "cargo", stage, Some(host));
}

pub fn install_cargo(&self, stage: u32, host: &str) {
self.install_sh("cargo", "cargo", stage, Some(host));
}
pub fn install_rls(builder: &Builder, stage: u32, host: Interned<String>) {
install_sh(builder, "rls", "rls", stage, Some(host));
}

pub fn install_rls(&self, stage: u32, host: &str) {
self.install_sh("rls", "rls", stage, Some(host));
}
pub fn install_analysis(builder: &Builder, stage: u32, host: Interned<String>) {
install_sh(builder, "analysis", "rust-analysis", stage, Some(host));
}

pub fn install_analysis(&self, stage: u32, host: &str) {
self.install_sh("analysis", "rust-analysis", stage, Some(host));
}
pub fn install_src(builder: &Builder, stage: u32) {
install_sh(builder, "src", "rust-src", stage, None);
}
pub fn install_rustc(builder: &Builder, stage: u32, host: Interned<String>) {
install_sh(builder, "rustc", "rustc", stage, Some(host));
}

pub fn install_src(&self, stage: u32) {
self.install_sh("src", "rust-src", stage, None);
}
pub fn install_rustc(&self, stage: u32, host: &str) {
self.install_sh("rustc", "rustc", stage, Some(host));
}
fn install_sh(
builder: &Builder,
package: &str,
name: &str,
stage: u32,
host: Option<Interned<String>>
) {
let build = builder.build;
println!("Install {} stage{} ({:?})", package, stage, host);

let prefix_default = PathBuf::from("/usr/local");
let sysconfdir_default = PathBuf::from("/etc");
let docdir_default = PathBuf::from("share/doc/rust");
let bindir_default = PathBuf::from("bin");
let libdir_default = PathBuf::from("lib");
let mandir_default = PathBuf::from("share/man");
let prefix = build.config.prefix.as_ref().unwrap_or(&prefix_default);
let sysconfdir = build.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default);
let docdir = build.config.docdir.as_ref().unwrap_or(&docdir_default);
let bindir = build.config.bindir.as_ref().unwrap_or(&bindir_default);
let libdir = build.config.libdir.as_ref().unwrap_or(&libdir_default);
let mandir = build.config.mandir.as_ref().unwrap_or(&mandir_default);

let sysconfdir = prefix.join(sysconfdir);
let docdir = prefix.join(docdir);
let bindir = prefix.join(bindir);
let libdir = prefix.join(libdir);
let mandir = prefix.join(mandir);

let destdir = env::var_os("DESTDIR").map(PathBuf::from);

let prefix = add_destdir(&prefix, &destdir);
let sysconfdir = add_destdir(&sysconfdir, &destdir);
let docdir = add_destdir(&docdir, &destdir);
let bindir = add_destdir(&bindir, &destdir);
let libdir = add_destdir(&libdir, &destdir);
let mandir = add_destdir(&mandir, &destdir);

let empty_dir = build.out.join("tmp/empty_dir");

t!(fs::create_dir_all(&empty_dir));
let package_name = if let Some(host) = host {
format!("{}-{}", pkgname(build, name), host)
} else {
pkgname(build, name)
};

fn install_sh(&self, package: &str, name: &str, stage: u32, host: Option<&str>) {
println!("Install {} stage{} ({:?})", package, stage, host);
let package_name = if let Some(host) = host {
format!("{}-{}", pkgname(self.build, name), host)
} else {
pkgname(self.build, name)
};

let mut cmd = Command::new("sh");
cmd.current_dir(&self.empty_dir)
.arg(sanitize_sh(&tmpdir(self.build).join(&package_name).join("install.sh")))
.arg(format!("--prefix={}", sanitize_sh(&self.prefix)))
.arg(format!("--sysconfdir={}", sanitize_sh(&self.sysconfdir)))
.arg(format!("--docdir={}", sanitize_sh(&self.docdir)))
.arg(format!("--bindir={}", sanitize_sh(&self.bindir)))
.arg(format!("--libdir={}", sanitize_sh(&self.libdir)))
.arg(format!("--mandir={}", sanitize_sh(&self.mandir)))
.arg("--disable-ldconfig");
self.build.run(&mut cmd);
}
let mut cmd = Command::new("sh");
cmd.current_dir(&empty_dir)
.arg(sanitize_sh(&tmpdir(build).join(&package_name).join("install.sh")))
.arg(format!("--prefix={}", sanitize_sh(&prefix)))
.arg(format!("--sysconfdir={}", sanitize_sh(&sysconfdir)))
.arg(format!("--docdir={}", sanitize_sh(&docdir)))
.arg(format!("--bindir={}", sanitize_sh(&bindir)))
.arg(format!("--libdir={}", sanitize_sh(&libdir)))
.arg(format!("--mandir={}", sanitize_sh(&mandir)))
.arg("--disable-ldconfig");
build.run(&mut cmd);
t!(fs::remove_dir_all(&empty_dir));
}

fn add_destdir(path: &Path, destdir: &Option<PathBuf>) -> PathBuf {
@@ -148,3 +126,82 @@ fn add_destdir(path: &Path, destdir: &Option<PathBuf>) -> PathBuf {
}
ret
}

macro_rules! install {
(($sel:ident, $builder:ident, $_config:ident),
$($name:ident,
$path:expr,
$default_cond:expr,
only_hosts: $only_hosts:expr,
$run_item:block $(, $c:ident)*;)+) => {
$(
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct $name {
pub stage: u32,
pub target: Interned<String>,
pub host: Interned<String>,
}

impl Step for $name {
type Output = ();
const DEFAULT: bool = true;
const ONLY_BUILD_TARGETS: bool = true;
const ONLY_HOSTS: bool = $only_hosts;
$(const $c: bool = true;)*

fn should_run(run: ShouldRun) -> ShouldRun {
let $_config = &run.builder.config;
run.path($path).default_condition($default_cond)
}

fn make_run(run: RunConfig) {
run.builder.ensure($name {
stage: run.builder.top_stage,
target: run.target,
host: run.host,
});
}

fn run($sel, $builder: &Builder) {
$run_item
}
})+
}
}

install!((self, builder, _config),
Docs, "src/doc", _config.docs, only_hosts: false, {
builder.ensure(dist::Docs { stage: self.stage, target: self.target });
install_docs(builder, self.stage, self.target);
};
Std, "src/libstd", true, only_hosts: true, {
builder.ensure(dist::Std {
compiler: builder.compiler(self.stage, self.host),
target: self.target
});
install_std(builder, self.stage);
};
Cargo, "cargo", _config.extended, only_hosts: true, {
builder.ensure(dist::Cargo { stage: self.stage, target: self.target });
install_cargo(builder, self.stage, self.target);
};
Rls, "rls", _config.extended, only_hosts: true, {
builder.ensure(dist::Rls { stage: self.stage, target: self.target });
install_rls(builder, self.stage, self.target);
};
Analysis, "analysis", _config.extended, only_hosts: false, {
builder.ensure(dist::Analysis {
compiler: builder.compiler(self.stage, self.host),
target: self.target
});
install_analysis(builder, self.stage, self.target);
};
Src, "src", _config.extended, only_hosts: true, {
builder.ensure(dist::Src);
install_src(builder, self.stage);
}, ONLY_BUILD;
Rustc, "src/librustc", _config.extended, only_hosts: true, {
builder.ensure(dist::Rustc { stage: self.stage, target: self.target });
install_rustc(builder, self.stage, self.target);
};
);
Copy path View file

Large diffs are not rendered by default.

Oops, something went wrong.
Copy path View file
@@ -13,17 +13,18 @@ use std::process::Command;
use std::path::PathBuf;

use build_helper::output;
use rustc_serialize::json;
use serde_json;

use {Build, Crate};
use cache::INTERNER;

#[derive(RustcDecodable)]
#[derive(Deserialize)]
struct Output {
packages: Vec<Package>,
resolve: Resolve,
}

#[derive(RustcDecodable)]
#[derive(Deserialize)]
struct Package {
id: String,
name: String,
@@ -32,12 +33,12 @@ struct Package {
manifest_path: String,
}

#[derive(RustcDecodable)]
#[derive(Deserialize)]
struct Resolve {
nodes: Vec<ResolveNode>,
}

#[derive(RustcDecodable)]
#[derive(Deserialize)]
struct ResolveNode {
id: String,
dependencies: Vec<String>,
@@ -61,19 +62,20 @@ fn build_krate(build: &mut Build, krate: &str) {
.arg("--format-version").arg("1")
.arg("--manifest-path").arg(build.src.join(krate).join("Cargo.toml"));
let output = output(&mut cargo);
let output: Output = json::decode(&output).unwrap();
let output: Output = serde_json::from_str(&output).unwrap();
let mut id2name = HashMap::new();
for package in output.packages {
if package.source.is_none() {
id2name.insert(package.id, package.name.clone());
let name = INTERNER.intern_string(package.name);
id2name.insert(package.id, name);
let mut path = PathBuf::from(package.manifest_path);
path.pop();
build.crates.insert(package.name.clone(), Crate {
build_step: format!("build-crate-{}", package.name),
doc_step: format!("doc-crate-{}", package.name),
test_step: format!("test-crate-{}", package.name),
bench_step: format!("bench-crate-{}", package.name),
name: package.name,
build.crates.insert(name, Crate {
build_step: format!("build-crate-{}", name),
doc_step: format!("doc-crate-{}", name),
test_step: format!("test-crate-{}", name),
bench_step: format!("bench-crate-{}", name),
name: name,
version: package.version,
deps: Vec::new(),
path: path,
@@ -93,7 +95,7 @@ fn build_krate(build: &mut Build, krate: &str) {
Some(dep) => dep,
None => continue,
};
krate.deps.push(dep.clone());
krate.deps.push(*dep);
}
}
}
Copy path View file

Large diffs are not rendered by default.

Oops, something went wrong.
Copy path View file
@@ -122,14 +122,14 @@ pub fn check(build: &mut Build) {
continue;
}

cmd_finder.must_have(build.cc(target));
if let Some(ar) = build.ar(target) {
cmd_finder.must_have(build.cc(*target));
if let Some(ar) = build.ar(*target) {
cmd_finder.must_have(ar);
}
}

for host in build.config.host.iter() {
cmd_finder.must_have(build.cxx(host).unwrap());
cmd_finder.must_have(build.cxx(*host).unwrap());

// The msvc hosts don't use jemalloc, turn it off globally to
// avoid packaging the dummy liballoc_jemalloc on that platform.
@@ -139,7 +139,7 @@ pub fn check(build: &mut Build) {
}

// Externally configured LLVM requires FileCheck to exist
let filecheck = build.llvm_filecheck(&build.build);
let filecheck = build.llvm_filecheck(build.build);
if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
panic!("FileCheck executable {:?} does not exist", filecheck);
}
@@ -153,7 +153,7 @@ pub fn check(build: &mut Build) {

// Make sure musl-root is valid if specified
if target.contains("musl") && !target.contains("mips") {
match build.musl_root(target) {
match build.musl_root(*target) {
Some(root) => {
if fs::metadata(root.join("lib/libc.a")).is_err() {
panic!("couldn't find libc.a in musl dir: {}",
Copy path View file

This file was deleted.

Oops, something went wrong.
Copy path View file
@@ -0,0 +1,353 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::env;
use std::path::PathBuf;
use std::process::Command;

use Mode;
use Compiler;
use builder::{Step, RunConfig, ShouldRun, Builder};
use util::{exe, add_lib_path};
use compile::{self, libtest_stamp, libstd_stamp, librustc_stamp};
use native;
use channel::GitInfo;
use cache::Interned;

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct CleanTools {
pub stage: u32,
pub target: Interned<String>,
pub mode: Mode,
}

impl Step for CleanTools {
type Output = ();

fn should_run(run: ShouldRun) -> ShouldRun {
run.never()
}

/// Build a tool in `src/tools`
///
/// This will build the specified tool with the specified `host` compiler in
/// `stage` into the normal cargo output directory.
fn run(self, builder: &Builder) {
let build = builder.build;
let stage = self.stage;
let target = self.target;
let mode = self.mode;

let compiler = builder.compiler(stage, build.build);

let stamp = match mode {
Mode::Libstd => libstd_stamp(build, compiler, target),
Mode::Libtest => libtest_stamp(build, compiler, target),
Mode::Librustc => librustc_stamp(build, compiler, target),
_ => panic!(),
};
let out_dir = build.cargo_out(compiler, Mode::Tool, target);
build.clear_if_dirty(&out_dir, &stamp);
}
}

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct ToolBuild {
pub stage: u32,
pub target: Interned<String>,
pub tool: &'static str,
pub mode: Mode,
}

impl Step for ToolBuild {
type Output = PathBuf;

fn should_run(run: ShouldRun) -> ShouldRun {
run.never()
}

/// Build a tool in `src/tools`
///
/// This will build the specified tool with the specified `host` compiler in
/// `stage` into the normal cargo output directory.
fn run(self, builder: &Builder) -> PathBuf {
let build = builder.build;
let stage = self.stage;
let target = self.target;
let tool = self.tool;

let compiler = builder.compiler(stage, build.build);
builder.ensure(CleanTools { stage, target, mode: self.mode });
match self.mode {
Mode::Libstd => builder.ensure(compile::Std { compiler, target }),
Mode::Libtest => builder.ensure(compile::Test { compiler, target }),
Mode::Librustc => builder.ensure(compile::Rustc { compiler, target }),
Mode::Tool => panic!("unexpected Mode::Tool for tool build")
}

let _folder = build.fold_output(|| format!("stage{}-{}", stage, tool));
println!("Building stage{} tool {} ({})", stage, tool, target);

let mut cargo = builder.cargo(compiler, Mode::Tool, target, "build");
let dir = build.src.join("src/tools").join(tool);
cargo.arg("--manifest-path").arg(dir.join("Cargo.toml"));

// We don't want to build tools dynamically as they'll be running across
// stages and such and it's just easier if they're not dynamically linked.
cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1");

if let Some(dir) = build.openssl_install_dir(target) {
cargo.env("OPENSSL_STATIC", "1");
cargo.env("OPENSSL_DIR", dir);
cargo.env("LIBZ_SYS_STATIC", "1");
}

cargo.env("CFG_RELEASE_CHANNEL", &build.config.channel);

let info = GitInfo::new(&dir);
if let Some(sha) = info.sha() {
cargo.env("CFG_COMMIT_HASH", sha);
}
if let Some(sha_short) = info.sha_short() {
cargo.env("CFG_SHORT_COMMIT_HASH", sha_short);
}
if let Some(date) = info.commit_date() {
cargo.env("CFG_COMMIT_DATE", date);
}

build.run(&mut cargo);
build.cargo_out(compiler, Mode::Tool, target).join(exe(tool, &compiler.host))
}
}

macro_rules! tool {
($($name:ident, $path:expr, $tool_name:expr, $mode:expr;)+) => {
#[derive(Copy, Clone)]
pub enum Tool {
$(
$name,
)+
}

impl<'a> Builder<'a> {
pub fn tool_exe(&self, tool: Tool) -> PathBuf {
match tool {
$(Tool::$name =>
self.ensure($name {
stage: 0,
target: self.build.build,
}),
)+
}
}
}

$(
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct $name {
pub stage: u32,
pub target: Interned<String>,
}

impl Step for $name {
type Output = PathBuf;

fn should_run(run: ShouldRun) -> ShouldRun {
run.path($path)
}

fn make_run(run: RunConfig) {
run.builder.ensure($name {
stage: run.builder.top_stage,
target: run.target,
});
}

fn run(self, builder: &Builder) -> PathBuf {
builder.ensure(ToolBuild {
stage: self.stage,
target: self.target,
tool: $tool_name,
mode: $mode,
})
}
}
)+
}
}

tool!(
Rustbook, "src/tools/rustbook", "rustbook", Mode::Librustc;
ErrorIndex, "src/tools/error_index_generator", "error_index_generator", Mode::Librustc;
UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen", Mode::Libstd;
Tidy, "src/tools/tidy", "tidy", Mode::Libstd;
Linkchecker, "src/tools/linkchecker", "linkchecker", Mode::Libstd;
CargoTest, "src/tools/cargotest", "cargotest", Mode::Libstd;
Compiletest, "src/tools/compiletest", "compiletest", Mode::Libtest;
BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::Librustc;
RemoteTestClient, "src/tools/remote-test-client", "remote-test-client", Mode::Libstd;
RustInstaller, "src/tools/rust-installer", "rust-installer", Mode::Libstd;
);

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct RemoteTestServer {
pub stage: u32,
pub target: Interned<String>,
}

impl Step for RemoteTestServer {
type Output = PathBuf;

fn should_run(run: ShouldRun) -> ShouldRun {
run.path("src/tools/remote-test-server")
}

fn make_run(run: RunConfig) {
run.builder.ensure(RemoteTestServer {
stage: run.builder.top_stage,
target: run.target,
});
}

fn run(self, builder: &Builder) -> PathBuf {
builder.ensure(ToolBuild {
stage: self.stage,
target: self.target,
tool: "remote-test-server",
mode: Mode::Libstd,
})
}
}

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Cargo {
pub stage: u32,
pub target: Interned<String>,
}

impl Step for Cargo {
type Output = PathBuf;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;

fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
run.path("src/tools/cargo").default_condition(builder.build.config.extended)
}

fn make_run(run: RunConfig) {
run.builder.ensure(Cargo {
stage: run.builder.top_stage,
target: run.target,
});
}

fn run(self, builder: &Builder) -> PathBuf {
builder.ensure(native::Openssl {
target: self.target,
});
// Cargo depends on procedural macros, which requires a full host
// compiler to be available, so we need to depend on that.
builder.ensure(compile::Rustc {
compiler: builder.compiler(self.stage, builder.build.build),
target: builder.build.build,
});
builder.ensure(ToolBuild {
stage: self.stage,
target: self.target,
tool: "cargo",
mode: Mode::Libstd,
})
}
}

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct Rls {
pub stage: u32,
pub target: Interned<String>,
}

impl Step for Rls {
type Output = PathBuf;
const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;

fn should_run(run: ShouldRun) -> ShouldRun {
let builder = run.builder;
run.path("src/tools/rls").default_condition(builder.build.config.extended)
}

fn make_run(run: RunConfig) {
run.builder.ensure(Rls {
stage: run.builder.top_stage,
target: run.target,
});
}

fn run(self, builder: &Builder) -> PathBuf {
builder.ensure(native::Openssl {
target: self.target,
});
// RLS depends on procedural macros, which requires a full host
// compiler to be available, so we need to depend on that.
builder.ensure(compile::Rustc {
compiler: builder.compiler(self.stage, builder.build.build),
target: builder.build.build,
});
builder.ensure(ToolBuild {
stage: self.stage,
target: self.target,
tool: "rls",
mode: Mode::Librustc,
})
}
}

impl<'a> Builder<'a> {
/// Get a `Command` which is ready to run `tool` in `stage` built for
/// `host`.
pub fn tool_cmd(&self, tool: Tool) -> Command {
let mut cmd = Command::new(self.tool_exe(tool));
let compiler = self.compiler(0, self.build.build);
self.prepare_tool_cmd(compiler, &mut cmd);
cmd
}

/// Prepares the `cmd` provided to be able to run the `compiler` provided.
///
/// Notably this munges the dynamic library lookup path to point to the
/// right location to run `compiler`.
fn prepare_tool_cmd(&self, compiler: Compiler, cmd: &mut Command) {
let host = &compiler.host;
let mut paths: Vec<PathBuf> = vec![
PathBuf::from(&self.sysroot_libdir(compiler, compiler.host)),
self.cargo_out(compiler, Mode::Tool, *host).join("deps"),
];

// On MSVC a tool may invoke a C compiler (e.g. compiletest in run-make
// mode) and that C compiler may need some extra PATH modification. Do
// so here.
if compiler.host.contains("msvc") {
let curpaths = env::var_os("PATH").unwrap_or_default();
let curpaths = env::split_paths(&curpaths).collect::<Vec<_>>();
for &(ref k, ref v) in self.cc[&compiler.host].0.env() {
if k != "PATH" {
continue
}
for path in env::split_paths(v) {
if !curpaths.contains(&path) {
paths.push(path);
}
}
}
}
add_lib_path(paths, cmd);
}
}
Copy path View file
@@ -4,5 +4,6 @@ version = "0.1.0"
authors = ["Alex Crichton <alex@alexcrichton.com>"]

[dependencies]
toml = "0.1"
rustc-serialize = "0.3"
toml = "0.4"
serde = "1.0"
serde_derive = "1.0"
Copy path View file
@@ -9,7 +9,9 @@
// except according to those terms.

extern crate toml;
extern crate rustc_serialize;
#[macro_use]
extern crate serde_derive;
extern crate serde;

use std::collections::BTreeMap;
use std::env;
@@ -99,19 +101,21 @@ static MINGW: &'static [&'static str] = &[
"x86_64-pc-windows-gnu",
];

#[derive(Serialize)]
#[serde(rename_all = "kebab-case")]
struct Manifest {
manifest_version: String,
date: String,
pkg: BTreeMap<String, Package>,
}

#[derive(RustcEncodable)]
#[derive(Serialize)]
struct Package {
version: String,
target: BTreeMap<String, Target>,
}

#[derive(RustcEncodable)]
#[derive(Serialize)]
struct Target {
available: bool,
url: Option<String>,
@@ -136,7 +140,7 @@ impl Target {
}
}

#[derive(RustcEncodable)]
#[derive(Serialize)]
struct Component {
pkg: String,
target: String,
@@ -199,28 +203,16 @@ impl Builder {
self.rls_version = self.version("rls", "x86_64-unknown-linux-gnu");

self.digest_and_sign();
let Manifest { manifest_version, date, pkg } = self.build_manifest();

// Unfortunately we can't use derive(RustcEncodable) here because the
// version field is called `manifest-version`, not `manifest_version`.
// In lieu of that just create the table directly here with a `BTreeMap`
// and wrap it up in a `Value::Table`.
let mut manifest = BTreeMap::new();
manifest.insert("manifest-version".to_string(),
toml::Value::String(manifest_version));
manifest.insert("date".to_string(), toml::Value::String(date.clone()));
manifest.insert("pkg".to_string(), toml::encode(&pkg));
let manifest = toml::Value::Table(manifest).to_string();

let manifest = self.build_manifest();
let filename = format!("channel-rust-{}.toml", self.rust_release);
self.write_manifest(&manifest, &filename);
self.write_manifest(&toml::to_string(&manifest).unwrap(), &filename);

let filename = format!("channel-rust-{}-date.txt", self.rust_release);
self.write_date_stamp(&date, &filename);
self.write_date_stamp(&manifest.date, &filename);

if self.rust_release != "beta" && self.rust_release != "nightly" {
self.write_manifest(&manifest, "channel-rust-stable.toml");
self.write_date_stamp(&date, "channel-rust-stable-date.txt");
self.write_manifest(&toml::to_string(&manifest).unwrap(), "channel-rust-stable.toml");
self.write_date_stamp(&manifest.date, "channel-rust-stable-date.txt");
}
}