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#[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 #[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 #[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 #[arg(long, help_heading = heading::MANIFEST_OPTIONS)]
43 #[cfg_attr(feature = "serde", serde(default))]
44 pub ignore_rust_version: bool,
45
46 #[arg(long, help_heading = heading::COMPILATION_OPTIONS)]
48 #[cfg_attr(feature = "serde", serde(default))]
49 pub unit_graph: bool,
50
51 #[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 #[arg(long, help_heading = heading::TARGET_SELECTION)]
65 #[cfg_attr(feature = "serde", serde(default))]
66 pub lib: bool,
67
68 #[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 #[arg(long, help_heading = heading::TARGET_SELECTION)]
81 #[cfg_attr(feature = "serde", serde(default))]
82 pub bins: bool,
83
84 #[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 #[arg(long, help_heading = heading::TARGET_SELECTION)]
97 #[cfg_attr(feature = "serde", serde(default))]
98 pub examples: bool,
99
100 #[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 #[arg(long, help_heading = heading::TARGET_SELECTION)]
112 #[cfg_attr(feature = "serde", serde(default))]
113 pub tests: bool,
114
115 #[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 #[arg(long, help_heading = heading::TARGET_SELECTION)]
127 #[cfg_attr(feature = "serde", serde(default))]
128 pub benches: bool,
129
130 #[arg(long, help_heading = heading::TARGET_SELECTION)]
132 #[cfg_attr(feature = "serde", serde(default))]
133 pub all_targets: bool,
134
135 #[arg(long, value_name = "INFO")]
137 #[cfg_attr(feature = "serde", serde(default))]
138 pub print: Option<String>,
139
140 #[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 #[arg(long)]
152 #[cfg_attr(feature = "serde", serde(default))]
153 pub future_incompat_report: bool,
154
155 #[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 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}