diff --git a/Cargo.toml b/Cargo.toml index 10b1f72..d7883cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ license = "MIT OR Apache-2.0" name = "xargo" repository = "https://github.com/japaric/xargo" version = "0.3.18" +default-run = "xargo" [dependencies] error-chain = "0.7.2" diff --git a/README.md b/README.md index 65facb0..6402e39 100644 --- a/README.md +++ b/README.md @@ -309,6 +309,18 @@ git = "https://github.com/japaric/steed" stage = 2 ``` +## Check-only sysroot build + +Xargo supports performing a 'check build' of the syroot +via the `xargo-check` command. This command is invoked exactly +like `xargo`, but will invoke `cargo check` instead of `cargo build` +when building the sysroot. + +This is only useful for very specialized applicationsm like Miri. +The resulting libstd will *not* be useable in a normal build, since codegen +will not be performed. You should almost always run `xargo check` (note the space), +which will perform a normal sysroot build, followed by a 'check' build of *your application* + ## Caveats / gotchas - Xargo won't build a sysroot when used with stable or beta Rust. This is diff --git a/ci/script.sh b/ci/script.sh index edee9f0..83fe957 100644 --- a/ci/script.sh +++ b/ci/script.sh @@ -3,8 +3,14 @@ set -euxo pipefail beginswith() { case $2 in "$1"*) true;; *) false;; esac; } main() { + # We test against Cargo versions that don't support 'default-run' + # As a workaround, we remove 'default-run' from the Cargo.toml + # on CI + # Unfortunately, we can't use 'sed -i', as this doesn't work on OS X + sed 's/default-run = "xargo"//g' Cargo.toml > Cargo.toml.new + mv Cargo.toml.new Cargo.toml cross build --target $TARGET --locked - cross run --target $TARGET -- -V + cross run --bin xargo --target $TARGET -- -V if beginswith nightly $TRAVIS_RUST_VERSION; then cargo test --features dev --target $TARGET diff --git a/src/bin/xargo-check.rs b/src/bin/xargo-check.rs new file mode 100644 index 0000000..619c12e --- /dev/null +++ b/src/bin/xargo-check.rs @@ -0,0 +1,3 @@ +fn main() { + xargo::main_inner(xargo::XargoMode::Check); +} diff --git a/src/bin/xargo.rs b/src/bin/xargo.rs new file mode 100644 index 0000000..663421e --- /dev/null +++ b/src/bin/xargo.rs @@ -0,0 +1,3 @@ +fn main() { + xargo::main_inner(xargo::XargoMode::Build); +} diff --git a/src/cargo.rs b/src/cargo.rs index b347bce..d7fbdcf 100644 --- a/src/cargo.rs +++ b/src/cargo.rs @@ -10,6 +10,7 @@ use cli::Args; use errors::*; use extensions::CommandExt; use util; +use sysroot::XargoMode; use xargo::Home; pub struct Rustflags { @@ -247,10 +248,15 @@ impl Root { } } -pub fn root() -> Result> { +pub fn root(mode: XargoMode) -> Result> { + // Don't require a 'Cargo.toml' to exist when 'xargo-check' is used + let name = match mode { + XargoMode::Build => "Cargo.toml", + XargoMode::Check => "Xargo.toml" + }; let cd = env::current_dir().chain_err(|| "couldn't get the current directory")?; - Ok(util::search(&cd, "Cargo.toml").map(|p| Root { path: p.to_owned() })) + Ok(util::search(&cd, name).map(|p| Root { path: p.to_owned() })) } #[derive(Clone, Copy, PartialEq)] diff --git a/src/main.rs b/src/lib.rs similarity index 84% rename from src/main.rs rename to src/lib.rs index 908336d..883bb67 100644 --- a/src/main.rs +++ b/src/lib.rs @@ -33,6 +33,8 @@ mod sysroot; mod util; mod xargo; +pub use sysroot::XargoMode; + // We use a different sysroot for Native compilation to avoid file locking // // Cross compilation requires `lib/rustlib/$HOST` to match `rustc`'s sysroot, @@ -72,12 +74,12 @@ impl CompilationMode { } } -pub fn main() { +pub fn main_inner(xargo_mode: XargoMode) { fn show_backtrace() -> bool { env::var("RUST_BACKTRACE").as_ref().map(|s| &s[..]) == Ok("1") } - match run() { + match run(xargo_mode) { Err(e) => { let stderr = io::stderr(); let mut stderr = stderr.lock(); @@ -98,13 +100,14 @@ pub fn main() { process::exit(1) } - Ok(status) => if !status.success() { + Ok(Some(status)) => if !status.success() { process::exit(status.code().unwrap_or(1)) }, + Ok(None) => {} } } -fn run() -> Result { +fn run(cargo_mode: XargoMode) -> Result> { let args = cli::args(); let verbose = args.verbose(); @@ -112,7 +115,7 @@ fn run() -> Result { if let Some(sc) = args.subcommand() { if !sc.needs_sysroot() { - return cargo::run(&args, verbose); + return cargo::run(&args, verbose).map(Some); } } else if args.version() { writeln!( @@ -121,13 +124,13 @@ fn run() -> Result { include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt")) ).ok(); - return cargo::run(&args, verbose); + return cargo::run(&args, verbose).map(Some); } let cd = CurrentDirectory::get()?; let config = cargo::config()?; - if let Some(root) = cargo::root()? { + if let Some(root) = cargo::root(cargo_mode)? { // We can't build sysroot with stable or beta due to unstable features let sysroot = rustc::sysroot(verbose)?; let src = match meta.channel { @@ -147,7 +150,7 @@ fn run() -> Result { Switch to nightly.", meta.channel ).ok(); - return cargo::run(&args, verbose); + return cargo::run(&args, verbose).map(Some); } }; @@ -187,21 +190,27 @@ fn run() -> Result { &src, &sysroot, verbose, - args.message_format() + args.message_format(), + cargo_mode, )?; - return xargo::run( - &args, - &cmode, - rustflags, - &home, - &meta, - config.as_ref(), - verbose, - ); + + if args.subcommand().is_some() || cargo_mode == XargoMode::Build { + return xargo::run( + &args, + &cmode, + rustflags, + &home, + &meta, + config.as_ref(), + verbose, + ).map(Some); + } else { + return Ok(None) + } } } - cargo::run(&args, verbose) + cargo::run(&args, verbose).map(Some) } pub struct CurrentDirectory { diff --git a/src/sysroot.rs b/src/sysroot.rs index e8a2715..418b437 100644 --- a/src/sysroot.rs +++ b/src/sysroot.rs @@ -31,14 +31,15 @@ fn profile() -> &'static str { fn build( cmode: &CompilationMode, blueprint: Blueprint, - ctoml: &cargo::Toml, + ctoml: &Option, home: &Home, rustflags: &Rustflags, src: &Src, sysroot: &Sysroot, hash: u64, verbose: bool, - message_format: Option<&str> + message_format: Option<&str>, + cargo_mode: XargoMode, ) -> Result<()> { const TOML: &'static str = r#" [package] @@ -96,8 +97,10 @@ version = "0.0.0" stoml.push_str(&Value::Table(map).to_string()); } - if let Some(profile) = ctoml.profile() { - stoml.push_str(&profile.to_string()) + if let Some(ctoml) = ctoml { + if let Some(profile) = ctoml.profile() { + stoml.push_str(&profile.to_string()) + } } // rust-src comes with a lockfile for libstd. Use it. @@ -165,7 +168,10 @@ version = "0.0.0" } } - cmd.arg("build"); + match cargo_mode { + XargoMode::Build => cmd.arg("build"), + XargoMode::Check => cmd.arg("check") + }; match () { #[cfg(feature = "dev")] @@ -234,7 +240,7 @@ fn hash( cmode: &CompilationMode, blueprint: &Blueprint, rustflags: &Rustflags, - ctoml: &cargo::Toml, + ctoml: &Option, meta: &VersionMeta, ) -> Result { let mut hasher = DefaultHasher::new(); @@ -245,8 +251,10 @@ fn hash( cmode.hash(&mut hasher)?; - if let Some(profile) = ctoml.profile() { - profile.hash(&mut hasher); + if let Some(ctoml) = ctoml { + if let Some(profile) = ctoml.profile() { + profile.hash(&mut hasher); + } } if let Some(ref hash) = meta.commit_hash { @@ -265,9 +273,20 @@ pub fn update( src: &Src, sysroot: &Sysroot, verbose: bool, - message_format: Option<&str> + message_format: Option<&str>, + cargo_mode: XargoMode, ) -> Result<()> { - let ctoml = cargo::toml(root)?; + let ctoml = match cargo_mode { + XargoMode::Build => Some(cargo::toml(root)?), + XargoMode::Check => { + if root.path().join("Cargo.toml").exists() { + Some(cargo::toml(root)?) + } else { + None + } + } + }; + let (xtoml_parent, xtoml) = xargo::toml(root)?; // As paths in the 'Xargo.toml' can be relative to the directory containing @@ -292,6 +311,7 @@ pub fn update( hash, verbose, message_format, + cargo_mode, )?; } @@ -344,6 +364,14 @@ pub struct Stage { patch: Table, } +/// Which mode to invoke `cargo` in when building the sysroot +/// Can be either `cargo build` or `cargo check` +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum XargoMode { + Build, + Check, +} + /// A sysroot that will be built in "stages" #[derive(Debug)] pub struct Blueprint { diff --git a/tests/smoke.rs b/tests/smoke.rs index 7610869..0c72e3c 100644 --- a/tests/smoke.rs +++ b/tests/smoke.rs @@ -121,6 +121,14 @@ fn xargo() -> Result { Ok(Command::new(p)) } +fn xargo_check() -> Result { + let mut p = env::current_exe().chain_err(|| "couldn't get path to current executable")?; + p.pop(); + p.pop(); + p.push("xargo-check"); + Ok(Command::new(p)) +} + trait CommandExt { fn run(&mut self) -> Result<()>; fn run_and_get_stderr(&mut self) -> Result; @@ -254,6 +262,7 @@ impl Project { Ok(()) } + /// Adds a `Xargo.toml` to the project fn xargo_toml(&self, toml: &str) -> Result<()> { write(&self.td.path().join("Xargo.toml"), false, toml) @@ -336,6 +345,18 @@ impl HProject { fn xargo_toml(&self, toml: &str) -> Result<()> { write(&self.td.path().join("Xargo.toml"), false, toml) } + + /// Runs `xargo-check` with the specified subcommand + fn xargo_check_subcommand(&self, subcommand: Option<&str>) -> Result { + let mut cmd = xargo_check()?; + if let Some(subcommand) = subcommand { + cmd.args(&[subcommand]); + } + cmd + .current_dir(self.td.path()) + .run_and_get_stderr() + } + } impl Drop for HProject { @@ -887,3 +908,33 @@ tag = "1.0.25" run!() } } + +#[cfg(feature = "dev")] +#[test] +fn cargo_check_check() { + fn run() -> Result<()> { + let project = HProject::new(false)?; + project.xargo_check_subcommand(Some("check"))?; + + Ok(()) + } + run!() +} + +#[cfg(feature = "dev")] +#[test] +fn cargo_check_check_no_ctoml() { + fn run() -> Result<()> { + let project = HProject::new(false)?; + // Make sure that 'Xargo.toml` exists + project.xargo_toml("")?; + std::fs::remove_file(project.td.path().join("Cargo.toml")) + .chain_err(|| format!("Could not remove Cargo.toml"))?; + + let stderr = project.xargo_check_subcommand(None)?; + assert!(stderr.contains("Checking core")); + + Ok(()) + } + run!() +}