Skip to content

Commit

Permalink
build a sysroot when compiling natively
Browse files Browse the repository at this point in the history
closes #106
  • Loading branch information
Jorge Aparicio committed Jan 3, 2017
1 parent 8a5adfb commit ecb4cb8
Show file tree
Hide file tree
Showing 9 changed files with 235 additions and 62 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

### Added

- Support for building a custom sysroot when compiling natively.

## [v0.3.2] - 2017-01-03

### Changed
Expand Down
36 changes: 36 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ tempdir = "0.3.5"
toml = "0.2.1"
walkdir = "1.0.3"

[dev-dependencies.parking_lot]
features = ["nightly"]
version = "0.3.6"

[features]
# Causes Xargo to always build the sysroot using the dev profile
# This is mainly for shorter test times
dev = []
4 changes: 0 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,6 @@ $ xargo build --target msp430-none-elf
because `std` and other standard crates depend on unstable features so it's
not possible to build the sysroot with stable or beta.

- Because of how sysroots work, `xargo` *can't*, and won't, build a sysroot for
the HOST. IOW, `xargo` will only build/use sysroots when you are cross
compiling.

- As of nightly-2016-12-19, `std` can't be compiled from the `rust-src`
component *without* patching the source.

Expand Down
69 changes: 53 additions & 16 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ extern crate tempdir;
extern crate toml;
extern crate walkdir;

use std::hash::{Hash, Hasher};
use std::io::Write;
use std::path::{Path, PathBuf};
use std::process::ExitStatus;
Expand All @@ -30,6 +31,44 @@ mod sysroot;
mod util;
mod xargo;

// We use a different sysroot for Native compilation to avoid file locking
//
// Cross compilation requires `lib/rustlib/$HOST` to match `rustc`'s sysroot,
// whereas Native compilation wants to use a custom `lib/rustlib/$HOST`. If each
// mode has its own sysroot then we avoid sharing that directory and thus file
// locking it.
pub enum CompilationMode {
Cross(Target),
Native(String),
}

impl CompilationMode {
fn hash<H>(&self, hasher: &mut H) -> Result<()>
where H: Hasher
{
match *self {
CompilationMode::Cross(ref target) => target.hash(hasher)?,
CompilationMode::Native(ref triple) => triple.hash(hasher),
}

Ok(())
}

fn triple(&self) -> &str {
match *self {
CompilationMode::Cross(ref target) => target.triple(),
CompilationMode::Native(ref triple) => triple,
}
}

fn is_native(&self) -> bool {
match *self {
CompilationMode::Native(_) => true,
_ => false,
}
}
}

pub fn main() {
fn show_backtrace() -> bool {
env::var("RUST_BACKTRACE").as_ref().map(|s| &s[..]) == Ok("1")
Expand Down Expand Up @@ -107,33 +146,31 @@ fn run() -> Result<ExitStatus> {
}
};

let target = if let Some(triple) = args.target() {
if triple != meta.host {
Target::new(triple, &cd, verbose)?
let cmode = if let Some(triple) = args.target() {
if triple == meta.host {
Some(CompilationMode::Native(meta.host.clone()))
} else {
None
Target::new(triple, &cd, verbose)?.map(CompilationMode::Cross)
}
} else {
if let Some(ref config) = config {
if let Some(triple) = config.target()? {
if triple != meta.host {
Target::new(triple, &cd, verbose)?
} else {
None
}
Target::new(triple, &cd, verbose)
?
.map(CompilationMode::Cross)
} else {
None
Some(CompilationMode::Native(meta.host.clone()))
}
} else {
None
Some(CompilationMode::Native(meta.host.clone()))
}
};

if let Some(target) = target {
let home = xargo::home()?;
let rustflags = cargo::rustflags(config.as_ref(), target.triple())?;
if let Some(cmode) = cmode {
let home = xargo::home(&cmode)?;
let rustflags = cargo::rustflags(config.as_ref(), cmode.triple())?;

sysroot::update(&target,
sysroot::update(&cmode,
&home,
&root,
&rustflags,
Expand All @@ -142,7 +179,7 @@ fn run() -> Result<ExitStatus> {
&sysroot,
verbose)?;
return xargo::run(&args,
&target,
&cmode,
rustflags,
&home,
&meta,
Expand Down
2 changes: 1 addition & 1 deletion src/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ impl Src {
}
}

/// Path to the original sysroot
/// Path to `rustc`'s sysroot
pub struct Sysroot {
path: PathBuf,
}
Expand Down
33 changes: 19 additions & 14 deletions src/sysroot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ use rustc_version::VersionMeta;
use tempdir::TempDir;
use toml::Value;

use CompilationMode;
use cargo::{Root, Rustflags};
use errors::*;
use extensions::CommandExt;
use rustc::{Src, Sysroot, Target};
use rustc::{Src, Sysroot};
use util;
use xargo::Home;
use {cargo, xargo};
Expand All @@ -27,7 +28,7 @@ fn profile() -> &'static str {
"release"
}

fn build(target: &Target,
fn build(cmode: &CompilationMode,
deps: &Dependencies,
ctoml: &cargo::Toml,
home: &Home,
Expand Down Expand Up @@ -73,7 +74,7 @@ version = "0.0.0"
}
cmd.arg("--manifest-path");
cmd.arg(td.join("Cargo.toml"));
cmd.args(&["--target", target.triple()]);
cmd.args(&["--target", cmode.triple()]);

if verbose {
cmd.arg("-v");
Expand All @@ -87,13 +88,13 @@ version = "0.0.0"
}

// Copy artifacts to Xargo sysroot
let rustlib = home.lock_rw(target.triple())?;
let rustlib = home.lock_rw(cmode.triple())?;
rustlib.remove_siblings()
.chain_err(|| format!("couldn't clear {}", rustlib.path().display()))?;
let dst = rustlib.parent().join("lib");
util::mkdir(&dst)?;
util::cp_r(&td.join("target")
.join(target.triple())
.join(cmode.triple())
.join(profile())
.join("deps"),
&dst)?;
Expand All @@ -104,9 +105,9 @@ version = "0.0.0"
Ok(())
}

fn old_hash(target: &str, home: &Home) -> Result<Option<u64>> {
fn old_hash(cmode: &CompilationMode, home: &Home) -> Result<Option<u64>> {
// FIXME this should be `lock_ro`
let lock = home.lock_rw(target)?;
let lock = home.lock_rw(cmode.triple())?;
let hfile = lock.parent().join(".hash");

if hfile.exists() {
Expand All @@ -125,7 +126,7 @@ fn old_hash(target: &str, home: &Home) -> Result<Option<u64>> {
/// - The target specification file, is any
/// - `[profile.release]` in `Cargo.toml`
/// - `rustc` commit hash
fn hash(target: &Target,
fn hash(cmode: &CompilationMode,
dependencies: &Dependencies,
rustflags: &Rustflags,
ctoml: &cargo::Toml,
Expand All @@ -137,7 +138,7 @@ fn hash(target: &Target,

rustflags.hash(&mut hasher);

target.hash(&mut hasher)?;
cmode.hash(&mut hasher)?;

if let Some(profile) = ctoml.profile() {
profile.hash(&mut hasher);
Expand All @@ -150,7 +151,7 @@ fn hash(target: &Target,
Ok(hasher.finish())
}

pub fn update(target: &Target,
pub fn update(cmode: &CompilationMode,
home: &Home,
root: &Root,
rustflags: &Rustflags,
Expand All @@ -162,15 +163,19 @@ pub fn update(target: &Target,
let ctoml = cargo::toml(root)?;
let xtoml = xargo::toml(root)?;

let deps = Dependencies::from(xtoml.as_ref(), target.triple(), &src)?;
let deps = Dependencies::from(xtoml.as_ref(), cmode.triple(), &src)?;

let hash = hash(target, &deps, rustflags, &ctoml, meta)?;
let hash = hash(cmode, &deps, rustflags, &ctoml, meta)?;

if old_hash(target.triple(), home)? != Some(hash) {
build(target, &deps, &ctoml, home, rustflags, hash, verbose)?;
if old_hash(cmode, home)? != Some(hash) {
build(cmode, &deps, &ctoml, home, rustflags, hash, verbose)?;
}

// copy host artifacts into the sysroot, if necessary
if cmode.is_native() {
return Ok(())
}

let lock = home.lock_rw(&meta.host)?;
let hfile = lock.parent().join(".hash");

Expand Down
Loading

0 comments on commit ecb4cb8

Please sign in to comment.