Skip to content

Commit

Permalink
Auto merge of #6892 - Goirad:doctest-xcompile, r=alexcrichton
Browse files Browse the repository at this point in the history
Added ability to crosscompile doctests

This commit adds the ability to cross-compile and run doctests.
Like before cargo checks if target == host, the difference is that if there is a runtool defined in config.toml, it passes the information forward to rustdoc so that it can run the doctests with that tool. If no tool is defined and the target != host, cargo instead displays a message that doctests will not be compiled because of the missing runtool.

See [here](rust-lang/rust#60387) for the companion PR in the rust project that modifies rustdoc to accept the relevant options as well as allow ignoring doctests on a per target level.
Partially resolves [#6460](#6460)

See [here](#7040) for the tracking issue.
  • Loading branch information
bors committed Sep 18, 2019
2 parents e2ed0d0 + a2209fc commit eadbaec
Show file tree
Hide file tree
Showing 4 changed files with 254 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/cargo/core/compiler/compilation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ impl<'cfg> Compilation<'cfg> {
self.fill_env(process(cmd), pkg, true)
}

fn target_runner(&self) -> &Option<(PathBuf, Vec<String>)> {
pub fn target_runner(&self) -> &Option<(PathBuf, Vec<String>)> {
&self.target_runner
}

Expand Down
2 changes: 2 additions & 0 deletions src/cargo/core/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ pub struct CliUnstable {
pub binary_dep_depinfo: bool,
pub build_std: Option<Vec<String>>,
pub timings: Option<Vec<String>>,
pub doctest_xcompile: bool,
}

impl CliUnstable {
Expand Down Expand Up @@ -393,6 +394,7 @@ impl CliUnstable {
self.build_std = Some(crate::core::compiler::standard_lib::parse_unstable_flag(v))
}
"timings" => self.timings = Some(parse_timings(v)),
"doctest-xcompile" => self.doctest_xcompile = true,
_ => failure::bail!("unknown `-Z` flag specified: {}", k),
}

Expand Down
24 changes: 21 additions & 3 deletions src/cargo/ops/cargo_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,14 @@ fn run_doc_tests(
let mut errors = Vec::new();
let config = options.compile_opts.config;

// We don't build/run doc tests if `target` does not equal `host`.
if compilation.host != compilation.target {
// The unstable doctest-xcompile feature enables both per-target-ignores and
// cross-compiling doctests. As a side effect, this feature also gates running
// doctests with runtools when target == host.
let doctest_xcompile = config.cli_unstable().doctest_xcompile;
let mut runtool: &Option<(std::path::PathBuf, Vec<String>)> = &None;
if doctest_xcompile {
runtool = compilation.target_runner();
} else if compilation.host != compilation.target {
return Ok((Test::Doc, errors));
}

Expand All @@ -158,6 +164,19 @@ fn run_doc_tests(
.arg("--crate-name")
.arg(&target.crate_name());

if doctest_xcompile {
p.arg("--target").arg(&compilation.target);
p.arg("-Zunstable-options");
p.arg("--enable-per-target-ignores");
}

runtool.as_ref().map(|(runtool, runtool_args)| {
p.arg("--runtool").arg(runtool);
for arg in runtool_args {
p.arg("--runtool-arg").arg(arg);
}
});

for &rust_dep in &[&compilation.deps_output] {
let mut arg = OsString::from("dependency=");
arg.push(rust_dep);
Expand Down Expand Up @@ -194,7 +213,6 @@ fn run_doc_tests(
if let Some(flags) = compilation.rustdocflags.get(&package.package_id()) {
p.args(flags);
}

config
.shell()
.verbose(|shell| shell.status("Running", p.to_string()))?;
Expand Down
230 changes: 230 additions & 0 deletions tests/testsuite/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use cargo_test_support::registry::Package;
use cargo_test_support::{
basic_bin_manifest, basic_lib_manifest, basic_manifest, cargo_exe, project,
};
use cargo_test_support::{cross_compile, is_nightly, paths};
use cargo_test_support::{rustc_host, sleep_ms};

#[cargo_test]
Expand Down Expand Up @@ -3660,3 +3661,232 @@ fn test_dep_with_dev() {
)
.run();
}

#[cargo_test]
fn cargo_test_doctest_xcompile_ignores() {
if !is_nightly() {
return;
}
let p = project()
.file("Cargo.toml", &basic_lib_manifest("foo"))
.file(
"src/lib.rs",
r#"
///```ignore-x86_64
///assert!(cfg!(not(target_arch = "x86_64")));
///```
pub fn foo() -> u8 {
4
}
"#,
)
.build();

p.cargo("build").run();
#[cfg(not(target_arch = "x86_64"))]
p.cargo("test")
.with_stdout_contains(
"\
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out\
",
)
.run();
#[cfg(target_arch = "x86_64")]
p.cargo("test")
.with_status(101)
.with_stdout_contains(
"\
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out\
",
)
.run();

#[cfg(not(target_arch = "x86_64"))]
p.cargo("test -Zdoctest-xcompile")
.masquerade_as_nightly_cargo()
.with_stdout_contains(
"\
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out\
",
)
.run();

#[cfg(target_arch = "x86_64")]
p.cargo("test -Zdoctest-xcompile")
.masquerade_as_nightly_cargo()
.with_stdout_contains(
"\
test result: ok. 0 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out\
",
)
.run();
}

#[cargo_test]
fn cargo_test_doctest_xcompile() {
if !is_nightly() {
return;
}
let p = project()
.file("Cargo.toml", &basic_lib_manifest("foo"))
.file(
"src/lib.rs",
r#"
///```
///assert!(1 == 1);
///```
pub fn foo() -> u8 {
4
}
"#,
)
.build();

p.cargo("build").run();
p.cargo(&format!("test --target {}", cross_compile::alternate()))
.with_stdout_contains(
"\
running 0 tests\
",
)
.run();
p.cargo(&format!(
"test --target {} -Zdoctest-xcompile",
cross_compile::alternate()
))
.masquerade_as_nightly_cargo()
.with_stdout_contains(
"\
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out\
",
)
.run();
}

#[cargo_test]
fn cargo_test_doctest_xcompile_runner() {
use std::fs;
if !is_nightly() {
return;
}

let runner = project()
.file("Cargo.toml", &basic_bin_manifest("runner"))
.file(
"src/main.rs",
r#"
pub fn main() {
eprintln!("this is a runner");
let args: Vec<String> = std::env::args().collect();
std::process::Command::new(&args[1]).spawn();
}
"#,
)
.build();

runner.cargo("build").run();
assert!(runner.bin("runner").is_file());
let runner_path = paths::root().join("runner");
fs::copy(&runner.bin("runner"), &runner_path).unwrap();

let config = paths::root().join(".cargo/config");

fs::create_dir_all(config.parent().unwrap()).unwrap();
File::create(config)
.unwrap()
.write_all(
format!(
r#"
[target.'cfg(target_arch = "x86")']
runner = "{}"
"#,
runner_path.to_str().unwrap()
)
.as_bytes(),
)
.unwrap();

let p = project()
.file("Cargo.toml", &basic_lib_manifest("foo"))
.file(
"src/lib.rs",
r#"
///```
///assert!(cfg!(target_arch = "x86"));
///```
pub fn foo() -> u8 {
4
}
"#,
)
.build();

p.cargo("build").run();
p.cargo(&format!("test --target {}", cross_compile::alternate()))
.with_stdout_contains(
"\
running 0 tests\
",
)
.run();
p.cargo(&format!(
"test --target {} -Zdoctest-xcompile",
cross_compile::alternate()
))
.masquerade_as_nightly_cargo()
.with_stdout_contains(
"\
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out\
",
)
.with_stderr_contains(
"\
this is a runner\
",
)
.run();
}

#[cargo_test]
fn cargo_test_doctest_xcompile_no_runner() {
if !is_nightly() {
return;
}

let p = project()
.file("Cargo.toml", &basic_lib_manifest("foo"))
.file(
"src/lib.rs",
r#"
///```
///assert!(cfg!(target_arch = "x86"));
///```
pub fn foo() -> u8 {
4
}
"#,
)
.build();

p.cargo("build").run();
p.cargo(&format!("test --target {}", cross_compile::alternate()))
.with_stdout_contains(
"\
running 0 tests\
",
)
.run();
p.cargo(&format!(
"test --target {} -Zdoctest-xcompile",
cross_compile::alternate()
))
.masquerade_as_nightly_cargo()
.with_stdout_contains(
"\
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out\
",
)
.run();
}

0 comments on commit eadbaec

Please sign in to comment.