diff --git a/CHANGELOG.md b/CHANGELOG.md index 58dc08ee7..db745520d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] - #722 - boolean environment variables are evaluated as truthy or falsey. +- #721 - add support for running doctests on nightly if `CROSS_UNSTABLE_ENABLE_DOCTESTS=true`. - #718 - remove deb subcommand. - #714 - use host target directory when falling back to host cargo. - #713 - convert relative target directories to absolute paths. diff --git a/README.md b/README.md index 80f6f437a..fb76f317f 100644 --- a/README.md +++ b/README.md @@ -207,6 +207,15 @@ passthrough = [ ] ``` +### Unstable Features + +Certain unstable features can enable additional functionality useful to +cross-compiling. Note that these are unstable, and may be removed at any +time (particularly if the feature is stabilized or removed), and will +only be used on a nightly channel. + +- `CROSS_UNSTABLE_ENABLE_DOCTESTS=true`: also run doctests. + ### Mounting volumes into the build environment In addition to passing environment variables, you can also specify environment diff --git a/src/cli.rs b/src/cli.rs index 6221324f8..6b747ebc8 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -14,6 +14,7 @@ pub struct Args { pub target: Option, pub target_dir: Option, pub docker_in_docker: bool, + pub enable_doctests: bool, } // Fix for issue #581. target_dir must be absolute. @@ -85,6 +86,9 @@ pub fn parse(target_list: &TargetList) -> Result { let docker_in_docker = env::var("CROSS_DOCKER_IN_DOCKER") .map(|s| bool_from_envvar(&s)) .unwrap_or_default(); + let enable_doctests = env::var("CROSS_UNSTABLE_ENABLE_DOCTESTS") + .map(|s| bool_from_envvar(&s)) + .unwrap_or_default(); Ok(Args { all, @@ -93,5 +97,6 @@ pub fn parse(target_list: &TargetList) -> Result { target, target_dir, docker_in_docker, + enable_doctests, }) } diff --git a/src/main.rs b/src/main.rs index ad7ca7f11..29f3ffb3b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,6 +21,7 @@ use std::path::PathBuf; use std::process::ExitStatus; use config::Config; +use rustc_version::Channel; use serde::Deserialize; use self::cargo::{Root, Subcommand}; @@ -314,6 +315,7 @@ fn run() -> Result { default_toolchain.to_string() }; sysroot.set_file_name(&toolchain); + let mut is_nightly = toolchain.contains("nightly"); let installed_toolchains = rustup::installed_toolchains(verbose)?; @@ -321,13 +323,14 @@ fn run() -> Result { rustup::install_toolchain(&toolchain, verbose)?; } // TODO: Provide a way to pick/match the toolchain version as a consumer of `cross`. - if let Some((rustc_version, rustc_commit)) = rustup::rustc_version(&sysroot)? { + if let Some((rustc_version, channel, rustc_commit)) = rustup::rustc_version(&sysroot)? { warn_host_version_mismatch( &host_version_meta, &toolchain, &rustc_version, &rustc_commit, )?; + is_nightly = channel == Channel::Nightly; } let available_targets = rustup::available_targets(&toolchain, verbose)?; @@ -358,7 +361,7 @@ fn run() -> Result { .map(|sc| sc.needs_interpreter()) .unwrap_or(false); - let filtered_args = if args + let mut filtered_args = if args .subcommand .map_or(false, |s| !s.needs_target_in_command()) { @@ -384,6 +387,14 @@ fn run() -> Result { args.all.clone() }; + let is_test = args + .subcommand + .map(|sc| sc == Subcommand::Test) + .unwrap_or(false); + if is_test && args.enable_doctests && is_nightly { + filtered_args.push("-Zdoctest-xcompile".to_string()); + } + if target.needs_docker() && args.subcommand.map(|sc| sc.needs_docker()).unwrap_or(false) { if host_version_meta.needs_interpreter() diff --git a/src/rustup.rs b/src/rustup.rs index a3ca05511..5b78006af 100644 --- a/src/rustup.rs +++ b/src/rustup.rs @@ -1,7 +1,7 @@ use std::path::Path; use std::process::Command; -use rustc_version::Version; +use rustc_version::{Channel, Version}; use crate::errors::*; use crate::extensions::CommandExt; @@ -101,7 +101,17 @@ pub fn component_is_installed(component: &str, toolchain: &str, verbose: bool) - .any(|l| l.starts_with(component) && l.contains("installed"))) } -pub fn rustc_version(toolchain_path: &Path) -> Result> { +fn rustc_channel(version: &Version) -> Result { + match version.pre.split('.').next().unwrap() { + "" => Ok(Channel::Stable), + "dev" => Ok(Channel::Dev), + "beta" => Ok(Channel::Beta), + "nightly" => Ok(Channel::Nightly), + x => eyre::bail!("unknown prerelease tag {x}"), + } +} + +pub fn rustc_version(toolchain_path: &Path) -> Result> { let path = toolchain_path.join("lib/rustlib/multirust-channel-manifest.toml"); if path.exists() { let contents = std::fs::read(&path) @@ -115,12 +125,11 @@ pub fn rustc_version(toolchain_path: &Path) -> Result> { // Field is `"{version} ({commit} {date})"` if let Some((version, meta)) = rust_version.split_once(' ') { - return Ok(Some(( - Version::parse(version).wrap_err_with(|| { - format!("invalid rust version found in {}", path.display()) - })?, - meta.to_owned(), - ))); + let version = Version::parse(version).wrap_err_with(|| { + format!("invalid rust version found in {}", path.display()) + })?; + let channel = rustc_channel(&version)?; + return Ok(Some((version, channel, meta.to_owned()))); } } }