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