1 use crate::core::compiler::CompileKind; 2 use crate::util::interning::InternedString; 3 use crate::util::{CargoResult, Config, RustfixDiagnosticServer}; 4 use anyhow::bail; 5 use cargo_util::ProcessBuilder; 6 use serde::ser; 7 use std::cell::RefCell; 8 use std::path::PathBuf; 9 10 /// Configuration information for a rustc build. 11 #[derive(Debug)] 12 pub struct BuildConfig { 13 /// The requested kind of compilation for this session 14 pub requested_kinds: Vec<CompileKind>, 15 /// Number of rustc jobs to run in parallel. 16 pub jobs: u32, 17 /// Build profile 18 pub requested_profile: InternedString, 19 /// The mode we are compiling in. 20 pub mode: CompileMode, 21 /// `true` to print stdout in JSON format (for machine reading). 22 pub message_format: MessageFormat, 23 /// Force Cargo to do a full rebuild and treat each target as changed. 24 pub force_rebuild: bool, 25 /// Output a build plan to stdout instead of actually compiling. 26 pub build_plan: bool, 27 /// Output the unit graph to stdout instead of actually compiling. 28 pub unit_graph: bool, 29 /// An optional override of the rustc process for primary units 30 pub primary_unit_rustc: Option<ProcessBuilder>, 31 /// A thread used by `cargo fix` to receive messages on a socket regarding 32 /// the success/failure of applying fixes. 33 pub rustfix_diagnostic_server: RefCell<Option<RustfixDiagnosticServer>>, 34 /// The directory to copy final artifacts to. Note that even if `out_dir` is 35 /// set, a copy of artifacts still could be found a `target/(debug\release)` 36 /// as usual. 37 // Note that, although the cmd-line flag name is `out-dir`, in code we use 38 // `export_dir`, to avoid confusion with out dir at `target/debug/deps`. 39 pub export_dir: Option<PathBuf>, 40 /// `true` to output a future incompatibility report at the end of the build 41 pub future_incompat_report: bool, 42 } 43 44 impl BuildConfig { 45 /// Parses all config files to learn about build configuration. Currently 46 /// configured options are: 47 /// 48 /// * `build.jobs` 49 /// * `build.target` 50 /// * `target.$target.ar` 51 /// * `target.$target.linker` 52 /// * `target.$target.libfoo.metadata` new( config: &Config, jobs: Option<u32>, requested_targets: &[String], mode: CompileMode, ) -> CargoResult<BuildConfig>53 pub fn new( 54 config: &Config, 55 jobs: Option<u32>, 56 requested_targets: &[String], 57 mode: CompileMode, 58 ) -> CargoResult<BuildConfig> { 59 let cfg = config.build_config()?; 60 let requested_kinds = CompileKind::from_requested_targets(config, requested_targets)?; 61 if jobs == Some(0) { 62 anyhow::bail!("jobs must be at least 1") 63 } 64 if jobs.is_some() && config.jobserver_from_env().is_some() { 65 config.shell().warn( 66 "a `-j` argument was passed to Cargo but Cargo is \ 67 also configured with an external jobserver in \ 68 its environment, ignoring the `-j` parameter", 69 )?; 70 } 71 let jobs = jobs.or(cfg.jobs).unwrap_or(::num_cpus::get() as u32); 72 if jobs == 0 { 73 anyhow::bail!("jobs may not be 0"); 74 } 75 76 Ok(BuildConfig { 77 requested_kinds, 78 jobs, 79 requested_profile: InternedString::new("dev"), 80 mode, 81 message_format: MessageFormat::Human, 82 force_rebuild: false, 83 build_plan: false, 84 unit_graph: false, 85 primary_unit_rustc: None, 86 rustfix_diagnostic_server: RefCell::new(None), 87 export_dir: None, 88 future_incompat_report: false, 89 }) 90 } 91 92 /// Whether or not the *user* wants JSON output. Whether or not rustc 93 /// actually uses JSON is decided in `add_error_format`. emit_json(&self) -> bool94 pub fn emit_json(&self) -> bool { 95 matches!(self.message_format, MessageFormat::Json { .. }) 96 } 97 test(&self) -> bool98 pub fn test(&self) -> bool { 99 self.mode == CompileMode::Test || self.mode == CompileMode::Bench 100 } 101 single_requested_kind(&self) -> CargoResult<CompileKind>102 pub fn single_requested_kind(&self) -> CargoResult<CompileKind> { 103 match self.requested_kinds.len() { 104 1 => Ok(self.requested_kinds[0]), 105 _ => bail!("only one `--target` argument is supported"), 106 } 107 } 108 } 109 110 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 111 pub enum MessageFormat { 112 Human, 113 Json { 114 /// Whether rustc diagnostics are rendered by cargo or included into the 115 /// output stream. 116 render_diagnostics: bool, 117 /// Whether the `rendered` field of rustc diagnostics are using the 118 /// "short" rendering. 119 short: bool, 120 /// Whether the `rendered` field of rustc diagnostics embed ansi color 121 /// codes. 122 ansi: bool, 123 }, 124 Short, 125 } 126 127 /// The general "mode" for what to do. 128 /// This is used for two purposes. The commands themselves pass this in to 129 /// `compile_ws` to tell it the general execution strategy. This influences 130 /// the default targets selected. The other use is in the `Unit` struct 131 /// to indicate what is being done with a specific target. 132 #[derive(Clone, Copy, PartialEq, Debug, Eq, Hash, PartialOrd, Ord)] 133 pub enum CompileMode { 134 /// A target being built for a test. 135 Test, 136 /// Building a target with `rustc` (lib or bin). 137 Build, 138 /// Building a target with `rustc` to emit `rmeta` metadata only. If 139 /// `test` is true, then it is also compiled with `--test` to check it like 140 /// a test. 141 Check { test: bool }, 142 /// Used to indicate benchmarks should be built. This is not used in 143 /// `Unit`, because it is essentially the same as `Test` (indicating 144 /// `--test` should be passed to rustc) and by using `Test` instead it 145 /// allows some de-duping of Units to occur. 146 Bench, 147 /// A target that will be documented with `rustdoc`. 148 /// If `deps` is true, then it will also document all dependencies. 149 Doc { deps: bool }, 150 /// A target that will be tested with `rustdoc`. 151 Doctest, 152 /// A marker for Units that represent the execution of a `build.rs` script. 153 RunCustomBuild, 154 } 155 156 impl ser::Serialize for CompileMode { serialize<S>(&self, s: S) -> Result<S::Ok, S::Error> where S: ser::Serializer,157 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error> 158 where 159 S: ser::Serializer, 160 { 161 use self::CompileMode::*; 162 match *self { 163 Test => "test".serialize(s), 164 Build => "build".serialize(s), 165 Check { .. } => "check".serialize(s), 166 Bench => "bench".serialize(s), 167 Doc { .. } => "doc".serialize(s), 168 Doctest => "doctest".serialize(s), 169 RunCustomBuild => "run-custom-build".serialize(s), 170 } 171 } 172 } 173 174 impl CompileMode { 175 /// Returns `true` if the unit is being checked. is_check(self) -> bool176 pub fn is_check(self) -> bool { 177 matches!(self, CompileMode::Check { .. }) 178 } 179 180 /// Returns `true` if this is generating documentation. is_doc(self) -> bool181 pub fn is_doc(self) -> bool { 182 matches!(self, CompileMode::Doc { .. }) 183 } 184 185 /// Returns `true` if this a doc test. is_doc_test(self) -> bool186 pub fn is_doc_test(self) -> bool { 187 self == CompileMode::Doctest 188 } 189 190 /// Returns `true` if this is any type of test (test, benchmark, doc test, or 191 /// check test). is_any_test(self) -> bool192 pub fn is_any_test(self) -> bool { 193 matches!( 194 self, 195 CompileMode::Test 196 | CompileMode::Bench 197 | CompileMode::Check { test: true } 198 | CompileMode::Doctest 199 ) 200 } 201 202 /// Returns `true` if this is something that passes `--test` to rustc. is_rustc_test(self) -> bool203 pub fn is_rustc_test(self) -> bool { 204 matches!( 205 self, 206 CompileMode::Test | CompileMode::Bench | CompileMode::Check { test: true } 207 ) 208 } 209 210 /// Returns `true` if this is the *execution* of a `build.rs` script. is_run_custom_build(self) -> bool211 pub fn is_run_custom_build(self) -> bool { 212 self == CompileMode::RunCustomBuild 213 } 214 } 215