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 /// An example or library that will be scraped for function calls by `rustdoc`. 153 Docscrape, 154 /// A marker for Units that represent the execution of a `build.rs` script. 155 RunCustomBuild, 156 } 157 158 impl ser::Serialize for CompileMode { serialize<S>(&self, s: S) -> Result<S::Ok, S::Error> where S: ser::Serializer,159 fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error> 160 where 161 S: ser::Serializer, 162 { 163 use self::CompileMode::*; 164 match *self { 165 Test => "test".serialize(s), 166 Build => "build".serialize(s), 167 Check { .. } => "check".serialize(s), 168 Bench => "bench".serialize(s), 169 Doc { .. } => "doc".serialize(s), 170 Doctest => "doctest".serialize(s), 171 Docscrape => "docscrape".serialize(s), 172 RunCustomBuild => "run-custom-build".serialize(s), 173 } 174 } 175 } 176 177 impl CompileMode { 178 /// Returns `true` if the unit is being checked. is_check(self) -> bool179 pub fn is_check(self) -> bool { 180 matches!(self, CompileMode::Check { .. }) 181 } 182 183 /// Returns `true` if this is generating documentation. is_doc(self) -> bool184 pub fn is_doc(self) -> bool { 185 matches!(self, CompileMode::Doc { .. }) 186 } 187 188 /// Returns `true` if this a doc test. is_doc_test(self) -> bool189 pub fn is_doc_test(self) -> bool { 190 self == CompileMode::Doctest 191 } 192 193 /// Returns `true` if this is scraping examples for documentation. is_doc_scrape(self) -> bool194 pub fn is_doc_scrape(self) -> bool { 195 self == CompileMode::Docscrape 196 } 197 198 /// Returns `true` if this is any type of test (test, benchmark, doc test, or 199 /// check test). is_any_test(self) -> bool200 pub fn is_any_test(self) -> bool { 201 matches!( 202 self, 203 CompileMode::Test 204 | CompileMode::Bench 205 | CompileMode::Check { test: true } 206 | CompileMode::Doctest 207 ) 208 } 209 210 /// Returns `true` if this is something that passes `--test` to rustc. is_rustc_test(self) -> bool211 pub fn is_rustc_test(self) -> bool { 212 matches!( 213 self, 214 CompileMode::Test | CompileMode::Bench | CompileMode::Check { test: true } 215 ) 216 } 217 218 /// Returns `true` if this is the *execution* of a `build.rs` script. is_run_custom_build(self) -> bool219 pub fn is_run_custom_build(self) -> bool { 220 self == CompileMode::RunCustomBuild 221 } 222 } 223