Skip to main content

cargo_options/
rustc.rs

1use std::ops::{Deref, DerefMut};
2use std::path::PathBuf;
3use std::process::Command;
4
5use clap::{ArgAction, Parser};
6
7#[cfg(feature = "serde")]
8use serde::{Deserialize, Serialize};
9
10use crate::common::CommonOptions;
11use crate::heading;
12
13/// Compile a package, and pass extra options to the compiler
14#[derive(Clone, Debug, Default, Parser)]
15#[command(
16    display_order = 1,
17    after_help = "Run `cargo help rustc` for more detailed information."
18)]
19#[group(skip)]
20#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
21pub struct Rustc {
22    #[command(flatten)]
23    #[cfg_attr(feature = "serde", serde(flatten))]
24    pub common: CommonOptions,
25
26    /// Path to Cargo.toml
27    #[arg(long, value_name = "PATH", help_heading = heading::MANIFEST_OPTIONS)]
28    #[cfg_attr(feature = "serde", serde(default))]
29    pub manifest_path: Option<PathBuf>,
30
31    /// Build artifacts in release mode, with optimizations
32    #[arg(
33        short = 'r',
34        long,
35        conflicts_with = "profile",
36        help_heading = heading::COMPILATION_OPTIONS,
37    )]
38    #[cfg_attr(feature = "serde", serde(default))]
39    pub release: bool,
40
41    /// Ignore `rust-version` specification in packages
42    #[arg(long, help_heading = heading::MANIFEST_OPTIONS)]
43    #[cfg_attr(feature = "serde", serde(default))]
44    pub ignore_rust_version: bool,
45
46    /// Output build graph in JSON (unstable)
47    #[arg(long, help_heading = heading::COMPILATION_OPTIONS)]
48    #[cfg_attr(feature = "serde", serde(default))]
49    pub unit_graph: bool,
50
51    /// Package to build
52    #[arg(
53        short = 'p',
54        long = "package",
55        value_name = "SPEC",
56        action = ArgAction::Append,
57        num_args=0..=1,
58        help_heading = heading::PACKAGE_SELECTION,
59    )]
60    #[cfg_attr(feature = "serde", serde(default))]
61    pub packages: Vec<String>,
62
63    /// Build only this package's library
64    #[arg(long, help_heading = heading::TARGET_SELECTION)]
65    #[cfg_attr(feature = "serde", serde(default))]
66    pub lib: bool,
67
68    /// Build only the specified binary
69    #[arg(
70        long,
71        value_name = "NAME",
72        action = ArgAction::Append,
73        num_args=0..=1,
74        help_heading = heading::TARGET_SELECTION,
75    )]
76    #[cfg_attr(feature = "serde", serde(default))]
77    pub bin: Vec<String>,
78
79    /// Build all binaries
80    #[arg(long, help_heading = heading::TARGET_SELECTION)]
81    #[cfg_attr(feature = "serde", serde(default))]
82    pub bins: bool,
83
84    /// Build only the specified example
85    #[arg(
86        long,
87        value_name = "NAME",
88        action = ArgAction::Append,
89        num_args=0..=1,
90        help_heading = heading::TARGET_SELECTION,
91    )]
92    #[cfg_attr(feature = "serde", serde(default))]
93    pub example: Vec<String>,
94
95    /// Build all examples
96    #[arg(long, help_heading = heading::TARGET_SELECTION)]
97    #[cfg_attr(feature = "serde", serde(default))]
98    pub examples: bool,
99
100    /// Build only the specified test target
101    #[arg(
102        long,
103        value_name = "NAME",
104        action = ArgAction::Append,
105        help_heading = heading::TARGET_SELECTION,
106    )]
107    #[cfg_attr(feature = "serde", serde(default))]
108    pub test: Vec<String>,
109
110    /// Build all targets that have `test = true` set
111    #[arg(long, help_heading = heading::TARGET_SELECTION)]
112    #[cfg_attr(feature = "serde", serde(default))]
113    pub tests: bool,
114
115    /// Build only the specified bench target
116    #[arg(
117        long,
118        value_name = "NAME",
119        action = ArgAction::Append,
120        help_heading = heading::TARGET_SELECTION,
121    )]
122    #[cfg_attr(feature = "serde", serde(default))]
123    pub bench: Vec<String>,
124
125    /// Build all targets that have `bench = true` set
126    #[arg(long, help_heading = heading::TARGET_SELECTION)]
127    #[cfg_attr(feature = "serde", serde(default))]
128    pub benches: bool,
129
130    /// Build all targets
131    #[arg(long, help_heading = heading::TARGET_SELECTION)]
132    #[cfg_attr(feature = "serde", serde(default))]
133    pub all_targets: bool,
134
135    /// Output compiler information without compiling
136    #[arg(long, value_name = "INFO")]
137    #[cfg_attr(feature = "serde", serde(default))]
138    pub print: Option<String>,
139
140    /// Comma separated list of types of crates for the compiler to emit
141    #[arg(
142        long,
143        value_name = "CRATE-TYPE",
144        action = ArgAction::Append,
145        value_delimiter = ',',
146    )]
147    #[cfg_attr(feature = "serde", serde(default))]
148    pub crate_type: Vec<String>,
149
150    /// Outputs a future incompatibility report at the end of the build
151    #[arg(long)]
152    #[cfg_attr(feature = "serde", serde(default))]
153    pub future_incompat_report: bool,
154
155    /// Extra rustc flags
156    #[arg(value_name = "ARGS", trailing_var_arg = true, num_args = 0..)]
157    #[cfg_attr(feature = "serde", serde(default))]
158    pub args: Vec<String>,
159}
160
161impl Rustc {
162    /// Build a `cargo rustc` command
163    pub fn command(&self) -> Command {
164        let mut cmd = CommonOptions::cargo_command();
165        cmd.arg("rustc");
166
167        self.common.apply(&mut cmd);
168
169        if let Some(path) = self.manifest_path.as_ref() {
170            cmd.arg("--manifest-path").arg(path);
171        }
172        if self.release {
173            cmd.arg("--release");
174        }
175        if self.ignore_rust_version {
176            cmd.arg("--ignore-rust-version");
177        }
178        if self.unit_graph {
179            cmd.arg("--unit-graph");
180        }
181        for pkg in &self.packages {
182            cmd.arg("--package").arg(pkg);
183        }
184        if self.lib {
185            cmd.arg("--lib");
186        }
187        for bin in &self.bin {
188            cmd.arg("--bin").arg(bin);
189        }
190        if self.bins {
191            cmd.arg("--bins");
192        }
193        for example in &self.example {
194            cmd.arg("--example").arg(example);
195        }
196        if self.examples {
197            cmd.arg("--examples");
198        }
199        for test in &self.test {
200            cmd.arg("--test").arg(test);
201        }
202        if self.tests {
203            cmd.arg("--tests");
204        }
205        for bench in &self.bench {
206            cmd.arg("--bench").arg(bench);
207        }
208        if self.benches {
209            cmd.arg("--benches");
210        }
211        if self.all_targets {
212            cmd.arg("--all-targets");
213        }
214        if let Some(print) = self.print.as_ref() {
215            cmd.arg("--print").arg(print);
216        }
217        if !self.crate_type.is_empty() {
218            cmd.arg("--crate-type").arg(self.crate_type.join(","));
219        }
220        if self.future_incompat_report {
221            cmd.arg("--future-incompat-report");
222        }
223        if !self.args.is_empty() {
224            cmd.arg("--").args(&self.args);
225        }
226
227        cmd
228    }
229}
230
231impl Deref for Rustc {
232    type Target = CommonOptions;
233
234    fn deref(&self) -> &Self::Target {
235        &self.common
236    }
237}
238
239impl DerefMut for Rustc {
240    fn deref_mut(&mut self) -> &mut Self::Target {
241        &mut self.common
242    }
243}
244
245#[cfg(test)]
246mod test {
247    use super::Rustc;
248    use clap::CommandFactory;
249
250    #[test]
251    fn verify_cli() {
252        <Rustc as CommandFactory>::command().debug_assert()
253    }
254}