blob: 9824c9fc2a22f03d5ee60f74122df028677e0168 [file] [log] [blame]
use std::cell::RefCell;
use serde::ser;
use crate::core::compiler::{CompileKind, CompileTarget};
use crate::util::ProcessBuilder;
use crate::util::{CargoResult, Config, RustfixDiagnosticServer};
#[derive(Debug, Clone)]
pub enum ProfileKind {
Dev,
Release,
Custom(String),
}
impl ProfileKind {
pub fn name(&self) -> &str {
match self {
ProfileKind::Dev => "dev",
ProfileKind::Release => "release",
ProfileKind::Custom(name) => name,
}
}
}
/// Configuration information for a rustc build.
#[derive(Debug)]
pub struct BuildConfig {
/// The requested kind of compilation for this session
pub requested_kind: CompileKind,
/// Number of rustc jobs to run in parallel.
pub jobs: u32,
/// Build profile
pub profile_kind: ProfileKind,
/// The mode we are compiling in.
pub mode: CompileMode,
/// `true` to print stdout in JSON format (for machine reading).
pub message_format: MessageFormat,
/// Force Cargo to do a full rebuild and treat each target as changed.
pub force_rebuild: bool,
/// Output a build plan to stdout instead of actually compiling.
pub build_plan: bool,
/// An optional override of the rustc path for primary units only
pub primary_unit_rustc: Option<ProcessBuilder>,
pub rustfix_diagnostic_server: RefCell<Option<RustfixDiagnosticServer>>,
}
impl BuildConfig {
/// Parses all config files to learn about build configuration. Currently
/// configured options are:
///
/// * `build.jobs`
/// * `build.target`
/// * `target.$target.ar`
/// * `target.$target.linker`
/// * `target.$target.libfoo.metadata`
pub fn new(
config: &Config,
jobs: Option<u32>,
requested_target: &Option<String>,
mode: CompileMode,
) -> CargoResult<BuildConfig> {
let cfg = config.build_config()?;
let requested_kind = match requested_target {
Some(s) => CompileKind::Target(CompileTarget::new(s)?),
None => match &cfg.target {
Some(val) => {
let value = if val.raw_value().ends_with(".json") {
let path = val.clone().resolve_path(config);
path.to_str().expect("must be utf-8 in toml").to_string()
} else {
val.raw_value().to_string()
};
CompileKind::Target(CompileTarget::new(&value)?)
}
None => CompileKind::Host,
},
};
if jobs == Some(0) {
failure::bail!("jobs must be at least 1")
}
if jobs.is_some() && config.jobserver_from_env().is_some() {
config.shell().warn(
"a `-j` argument was passed to Cargo but Cargo is \
also configured with an external jobserver in \
its environment, ignoring the `-j` parameter",
)?;
}
let jobs = jobs.or(cfg.jobs).unwrap_or(::num_cpus::get() as u32);
Ok(BuildConfig {
requested_kind,
jobs,
profile_kind: ProfileKind::Dev,
mode,
message_format: MessageFormat::Human,
force_rebuild: false,
build_plan: false,
primary_unit_rustc: None,
rustfix_diagnostic_server: RefCell::new(None),
})
}
/// Whether or not the *user* wants JSON output. Whether or not rustc
/// actually uses JSON is decided in `add_error_format`.
pub fn emit_json(&self) -> bool {
match self.message_format {
MessageFormat::Json { .. } => true,
_ => false,
}
}
pub fn profile_name(&self) -> &str {
self.profile_kind.name()
}
pub fn test(&self) -> bool {
self.mode == CompileMode::Test || self.mode == CompileMode::Bench
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum MessageFormat {
Human,
Json {
/// Whether rustc diagnostics are rendered by cargo or included into the
/// output stream.
render_diagnostics: bool,
/// Whether the `rendered` field of rustc diagnostics are using the
/// "short" rendering.
short: bool,
/// Whether the `rendered` field of rustc diagnostics embed ansi color
/// codes.
ansi: bool,
},
Short,
}
/// The general "mode" for what to do.
/// This is used for two purposes. The commands themselves pass this in to
/// `compile_ws` to tell it the general execution strategy. This influences
/// the default targets selected. The other use is in the `Unit` struct
/// to indicate what is being done with a specific target.
#[derive(Clone, Copy, PartialEq, Debug, Eq, Hash, PartialOrd, Ord)]
pub enum CompileMode {
/// A target being built for a test.
Test,
/// Building a target with `rustc` (lib or bin).
Build,
/// Building a target with `rustc` to emit `rmeta` metadata only. If
/// `test` is true, then it is also compiled with `--test` to check it like
/// a test.
Check { test: bool },
/// Used to indicate benchmarks should be built. This is not used in
/// `Unit`, because it is essentially the same as `Test` (indicating
/// `--test` should be passed to rustc) and by using `Test` instead it
/// allows some de-duping of Units to occur.
Bench,
/// A target that will be documented with `rustdoc`.
/// If `deps` is true, then it will also document all dependencies.
Doc { deps: bool },
/// A target that will be tested with `rustdoc`.
Doctest,
/// A marker for Units that represent the execution of a `build.rs` script.
RunCustomBuild,
}
impl ser::Serialize for CompileMode {
fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
use self::CompileMode::*;
match *self {
Test => "test".serialize(s),
Build => "build".serialize(s),
Check { .. } => "check".serialize(s),
Bench => "bench".serialize(s),
Doc { .. } => "doc".serialize(s),
Doctest => "doctest".serialize(s),
RunCustomBuild => "run-custom-build".serialize(s),
}
}
}
impl CompileMode {
/// Returns `true` if the unit is being checked.
pub fn is_check(self) -> bool {
match self {
CompileMode::Check { .. } => true,
_ => false,
}
}
/// Returns `true` if this is generating documentation.
pub fn is_doc(self) -> bool {
match self {
CompileMode::Doc { .. } => true,
_ => false,
}
}
/// Returns `true` if this a doc test.
pub fn is_doc_test(self) -> bool {
self == CompileMode::Doctest
}
/// Returns `true` if this is any type of test (test, benchmark, doc test, or
/// check test).
pub fn is_any_test(self) -> bool {
match self {
CompileMode::Test
| CompileMode::Bench
| CompileMode::Check { test: true }
| CompileMode::Doctest => true,
_ => false,
}
}
/// Returns `true` if this is something that passes `--test` to rustc.
pub fn is_rustc_test(self) -> bool {
match self {
CompileMode::Test | CompileMode::Bench | CompileMode::Check { test: true } => true,
_ => false,
}
}
/// Returns `true` if this is the *execution* of a `build.rs` script.
pub fn is_run_custom_build(self) -> bool {
self == CompileMode::RunCustomBuild
}
/// List of all modes (currently used by `cargo clean -p` for computing
/// all possible outputs).
pub fn all_modes() -> &'static [CompileMode] {
static ALL: [CompileMode; 9] = [
CompileMode::Test,
CompileMode::Build,
CompileMode::Check { test: true },
CompileMode::Check { test: false },
CompileMode::Bench,
CompileMode::Doc { deps: true },
CompileMode::Doc { deps: false },
CompileMode::Doctest,
CompileMode::RunCustomBuild,
];
&ALL
}
}