cargo/core/compiler/
build_config.rs

1use crate::core::compiler::{CompileKind, CompileTarget};
2use crate::core::interning::InternedString;
3use crate::util::ProcessBuilder;
4use crate::util::{CargoResult, Config, RustfixDiagnosticServer};
5use serde::ser;
6use std::cell::RefCell;
7
8/// Configuration information for a rustc build.
9#[derive(Debug)]
10pub struct BuildConfig {
11    /// The requested kind of compilation for this session
12    pub requested_kind: CompileKind,
13    /// Number of rustc jobs to run in parallel.
14    pub jobs: u32,
15    /// Build profile
16    pub requested_profile: InternedString,
17    /// The mode we are compiling in.
18    pub mode: CompileMode,
19    /// `true` to print stdout in JSON format (for machine reading).
20    pub message_format: MessageFormat,
21    /// Force Cargo to do a full rebuild and treat each target as changed.
22    pub force_rebuild: bool,
23    /// Output a build plan to stdout instead of actually compiling.
24    pub build_plan: bool,
25    /// Output the unit graph to stdout instead of actually compiling.
26    pub unit_graph: bool,
27    /// An optional override of the rustc process for primary units
28    pub primary_unit_rustc: Option<ProcessBuilder>,
29    pub rustfix_diagnostic_server: RefCell<Option<RustfixDiagnosticServer>>,
30}
31
32impl BuildConfig {
33    /// Parses all config files to learn about build configuration. Currently
34    /// configured options are:
35    ///
36    /// * `build.jobs`
37    /// * `build.target`
38    /// * `target.$target.ar`
39    /// * `target.$target.linker`
40    /// * `target.$target.libfoo.metadata`
41    pub fn new(
42        config: &Config,
43        jobs: Option<u32>,
44        requested_target: &Option<String>,
45        mode: CompileMode,
46    ) -> CargoResult<BuildConfig> {
47        let cfg = config.build_config()?;
48        let requested_kind = match requested_target {
49            Some(s) => CompileKind::Target(CompileTarget::new(s)?),
50            None => match &cfg.target {
51                Some(val) => {
52                    let value = if val.raw_value().ends_with(".json") {
53                        let path = val.clone().resolve_path(config);
54                        path.to_str().expect("must be utf-8 in toml").to_string()
55                    } else {
56                        val.raw_value().to_string()
57                    };
58                    CompileKind::Target(CompileTarget::new(&value)?)
59                }
60                None => CompileKind::Host,
61            },
62        };
63
64        if jobs == Some(0) {
65            anyhow::bail!("jobs must be at least 1")
66        }
67        if jobs.is_some() && config.jobserver_from_env().is_some() {
68            config.shell().warn(
69                "a `-j` argument was passed to Cargo but Cargo is \
70                 also configured with an external jobserver in \
71                 its environment, ignoring the `-j` parameter",
72            )?;
73        }
74        let jobs = jobs.or(cfg.jobs).unwrap_or(::num_cpus::get() as u32);
75
76        Ok(BuildConfig {
77            requested_kind,
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        })
88    }
89
90    /// Whether or not the *user* wants JSON output. Whether or not rustc
91    /// actually uses JSON is decided in `add_error_format`.
92    pub fn emit_json(&self) -> bool {
93        match self.message_format {
94            MessageFormat::Json { .. } => true,
95            _ => false,
96        }
97    }
98
99    pub fn test(&self) -> bool {
100        self.mode == CompileMode::Test || self.mode == CompileMode::Bench
101    }
102}
103
104#[derive(Clone, Copy, Debug, PartialEq, Eq)]
105pub enum MessageFormat {
106    Human,
107    Json {
108        /// Whether rustc diagnostics are rendered by cargo or included into the
109        /// output stream.
110        render_diagnostics: bool,
111        /// Whether the `rendered` field of rustc diagnostics are using the
112        /// "short" rendering.
113        short: bool,
114        /// Whether the `rendered` field of rustc diagnostics embed ansi color
115        /// codes.
116        ansi: bool,
117    },
118    Short,
119}
120
121/// The general "mode" for what to do.
122/// This is used for two purposes. The commands themselves pass this in to
123/// `compile_ws` to tell it the general execution strategy. This influences
124/// the default targets selected. The other use is in the `Unit` struct
125/// to indicate what is being done with a specific target.
126#[derive(Clone, Copy, PartialEq, Debug, Eq, Hash, PartialOrd, Ord)]
127pub enum CompileMode {
128    /// A target being built for a test.
129    Test,
130    /// Building a target with `rustc` (lib or bin).
131    Build,
132    /// Building a target with `rustc` to emit `rmeta` metadata only. If
133    /// `test` is true, then it is also compiled with `--test` to check it like
134    /// a test.
135    Check { test: bool },
136    /// Used to indicate benchmarks should be built. This is not used in
137    /// `Unit`, because it is essentially the same as `Test` (indicating
138    /// `--test` should be passed to rustc) and by using `Test` instead it
139    /// allows some de-duping of Units to occur.
140    Bench,
141    /// A target that will be documented with `rustdoc`.
142    /// If `deps` is true, then it will also document all dependencies.
143    Doc { deps: bool },
144    /// A target that will be tested with `rustdoc`.
145    Doctest,
146    /// A marker for Units that represent the execution of a `build.rs` script.
147    RunCustomBuild,
148}
149
150impl ser::Serialize for CompileMode {
151    fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
152    where
153        S: ser::Serializer,
154    {
155        use self::CompileMode::*;
156        match *self {
157            Test => "test".serialize(s),
158            Build => "build".serialize(s),
159            Check { .. } => "check".serialize(s),
160            Bench => "bench".serialize(s),
161            Doc { .. } => "doc".serialize(s),
162            Doctest => "doctest".serialize(s),
163            RunCustomBuild => "run-custom-build".serialize(s),
164        }
165    }
166}
167
168impl CompileMode {
169    /// Returns `true` if the unit is being checked.
170    pub fn is_check(self) -> bool {
171        match self {
172            CompileMode::Check { .. } => true,
173            _ => false,
174        }
175    }
176
177    /// Returns `true` if this is generating documentation.
178    pub fn is_doc(self) -> bool {
179        match self {
180            CompileMode::Doc { .. } => true,
181            _ => false,
182        }
183    }
184
185    /// Returns `true` if this a doc test.
186    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).
192    pub fn is_any_test(self) -> bool {
193        match self {
194            CompileMode::Test
195            | CompileMode::Bench
196            | CompileMode::Check { test: true }
197            | CompileMode::Doctest => true,
198            _ => false,
199        }
200    }
201
202    /// Returns `true` if this is something that passes `--test` to rustc.
203    pub fn is_rustc_test(self) -> bool {
204        match self {
205            CompileMode::Test | CompileMode::Bench | CompileMode::Check { test: true } => true,
206            _ => false,
207        }
208    }
209
210    /// Returns `true` if this is the *execution* of a `build.rs` script.
211    pub fn is_run_custom_build(self) -> bool {
212        self == CompileMode::RunCustomBuild
213    }
214
215    /// List of all modes (currently used by `cargo clean -p` for computing
216    /// all possible outputs).
217    pub fn all_modes() -> &'static [CompileMode] {
218        static ALL: [CompileMode; 9] = [
219            CompileMode::Test,
220            CompileMode::Build,
221            CompileMode::Check { test: true },
222            CompileMode::Check { test: false },
223            CompileMode::Bench,
224            CompileMode::Doc { deps: true },
225            CompileMode::Doc { deps: false },
226            CompileMode::Doctest,
227            CompileMode::RunCustomBuild,
228        ];
229        &ALL
230    }
231}