Skip to content

Commit 459e03e

Browse files
Merge #721
721: Add preliminary support for running doctests. r=Emilgardis a=Alexhuszagh This partially addresses #225. This only works on nightly, due to the use of the unstable feature [doctest-xcompile](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#doctest-xcompile) The relevant tracking issues are: - rust-lang/cargo#7040 - rust-lang/rust#64245 If the subcommand is `test` and the compiler is nightly, we provide the `-Zdoctest-xcompile` flag if `CROSS_UNSTABLE_ENABLE_DOCTESTS=true`. Co-authored-by: Alex Huszagh <[email protected]>
2 parents 10da657 + e4f896c commit 459e03e

File tree

5 files changed

+45
-10
lines changed

5 files changed

+45
-10
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
66
## [Unreleased]
77

88
- #722 - boolean environment variables are evaluated as truthy or falsey.
9+
- #721 - add support for running doctests on nightly if `CROSS_UNSTABLE_ENABLE_DOCTESTS=true`.
910
- #718 - remove deb subcommand.
1011
- #714 - use host target directory when falling back to host cargo.
1112
- #713 - convert relative target directories to absolute paths.

README.md

+9
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,15 @@ passthrough = [
207207
]
208208
```
209209

210+
### Unstable Features
211+
212+
Certain unstable features can enable additional functionality useful to
213+
cross-compiling. Note that these are unstable, and may be removed at any
214+
time (particularly if the feature is stabilized or removed), and will
215+
only be used on a nightly channel.
216+
217+
- `CROSS_UNSTABLE_ENABLE_DOCTESTS=true`: also run doctests.
218+
210219
### Mounting volumes into the build environment
211220

212221
In addition to passing environment variables, you can also specify environment

src/cli.rs

+5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub struct Args {
1414
pub target: Option<Target>,
1515
pub target_dir: Option<PathBuf>,
1616
pub docker_in_docker: bool,
17+
pub enable_doctests: bool,
1718
}
1819

1920
// Fix for issue #581. target_dir must be absolute.
@@ -85,6 +86,9 @@ pub fn parse(target_list: &TargetList) -> Result<Args> {
8586
let docker_in_docker = env::var("CROSS_DOCKER_IN_DOCKER")
8687
.map(|s| bool_from_envvar(&s))
8788
.unwrap_or_default();
89+
let enable_doctests = env::var("CROSS_UNSTABLE_ENABLE_DOCTESTS")
90+
.map(|s| bool_from_envvar(&s))
91+
.unwrap_or_default();
8892

8993
Ok(Args {
9094
all,
@@ -93,5 +97,6 @@ pub fn parse(target_list: &TargetList) -> Result<Args> {
9397
target,
9498
target_dir,
9599
docker_in_docker,
100+
enable_doctests,
96101
})
97102
}

src/main.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use std::path::PathBuf;
2121
use std::process::ExitStatus;
2222

2323
use config::Config;
24+
use rustc_version::Channel;
2425
use serde::Deserialize;
2526

2627
use self::cargo::{Root, Subcommand};
@@ -314,20 +315,22 @@ fn run() -> Result<ExitStatus> {
314315
default_toolchain.to_string()
315316
};
316317
sysroot.set_file_name(&toolchain);
318+
let mut is_nightly = toolchain.contains("nightly");
317319

318320
let installed_toolchains = rustup::installed_toolchains(verbose)?;
319321

320322
if !installed_toolchains.into_iter().any(|t| t == toolchain) {
321323
rustup::install_toolchain(&toolchain, verbose)?;
322324
}
323325
// TODO: Provide a way to pick/match the toolchain version as a consumer of `cross`.
324-
if let Some((rustc_version, rustc_commit)) = rustup::rustc_version(&sysroot)? {
326+
if let Some((rustc_version, channel, rustc_commit)) = rustup::rustc_version(&sysroot)? {
325327
warn_host_version_mismatch(
326328
&host_version_meta,
327329
&toolchain,
328330
&rustc_version,
329331
&rustc_commit,
330332
)?;
333+
is_nightly = channel == Channel::Nightly;
331334
}
332335

333336
let available_targets = rustup::available_targets(&toolchain, verbose)?;
@@ -358,7 +361,7 @@ fn run() -> Result<ExitStatus> {
358361
.map(|sc| sc.needs_interpreter())
359362
.unwrap_or(false);
360363

361-
let filtered_args = if args
364+
let mut filtered_args = if args
362365
.subcommand
363366
.map_or(false, |s| !s.needs_target_in_command())
364367
{
@@ -384,6 +387,14 @@ fn run() -> Result<ExitStatus> {
384387
args.all.clone()
385388
};
386389

390+
let is_test = args
391+
.subcommand
392+
.map(|sc| sc == Subcommand::Test)
393+
.unwrap_or(false);
394+
if is_test && args.enable_doctests && is_nightly {
395+
filtered_args.push("-Zdoctest-xcompile".to_string());
396+
}
397+
387398
if target.needs_docker() && args.subcommand.map(|sc| sc.needs_docker()).unwrap_or(false)
388399
{
389400
if host_version_meta.needs_interpreter()

src/rustup.rs

+17-8
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::path::Path;
22
use std::process::Command;
33

4-
use rustc_version::Version;
4+
use rustc_version::{Channel, Version};
55

66
use crate::errors::*;
77
use crate::extensions::CommandExt;
@@ -101,7 +101,17 @@ pub fn component_is_installed(component: &str, toolchain: &str, verbose: bool) -
101101
.any(|l| l.starts_with(component) && l.contains("installed")))
102102
}
103103

104-
pub fn rustc_version(toolchain_path: &Path) -> Result<Option<(Version, String)>> {
104+
fn rustc_channel(version: &Version) -> Result<Channel> {
105+
match version.pre.split('.').next().unwrap() {
106+
"" => Ok(Channel::Stable),
107+
"dev" => Ok(Channel::Dev),
108+
"beta" => Ok(Channel::Beta),
109+
"nightly" => Ok(Channel::Nightly),
110+
x => eyre::bail!("unknown prerelease tag {x}"),
111+
}
112+
}
113+
114+
pub fn rustc_version(toolchain_path: &Path) -> Result<Option<(Version, Channel, String)>> {
105115
let path = toolchain_path.join("lib/rustlib/multirust-channel-manifest.toml");
106116
if path.exists() {
107117
let contents = std::fs::read(&path)
@@ -115,12 +125,11 @@ pub fn rustc_version(toolchain_path: &Path) -> Result<Option<(Version, String)>>
115125
{
116126
// Field is `"{version} ({commit} {date})"`
117127
if let Some((version, meta)) = rust_version.split_once(' ') {
118-
return Ok(Some((
119-
Version::parse(version).wrap_err_with(|| {
120-
format!("invalid rust version found in {}", path.display())
121-
})?,
122-
meta.to_owned(),
123-
)));
128+
let version = Version::parse(version).wrap_err_with(|| {
129+
format!("invalid rust version found in {}", path.display())
130+
})?;
131+
let channel = rustc_channel(&version)?;
132+
return Ok(Some((version, channel, meta.to_owned())));
124133
}
125134
}
126135
}

0 commit comments

Comments
 (0)