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/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!()
+}