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(short = 'r', long, help_heading = heading::COMPILATION_OPTIONS)]
33 #[cfg_attr(feature = "serde", serde(default))]
34 pub release: bool,
35
36 #[arg(long)]
38 #[cfg_attr(feature = "serde", serde(default))]
39 pub ignore_rust_version: bool,
40
41 #[arg(long, help_heading = heading::COMPILATION_OPTIONS)]
43 #[cfg_attr(feature = "serde", serde(default))]
44 pub unit_graph: bool,
45
46 #[arg(
48 short = 'p',
49 long = "package",
50 value_name = "SPEC",
51 action = ArgAction::Append,
52 num_args=0..=1,
53 help_heading = heading::PACKAGE_SELECTION,
54 )]
55 #[cfg_attr(feature = "serde", serde(default))]
56 pub packages: Vec<String>,
57
58 #[arg(long, help_heading = heading::TARGET_SELECTION)]
60 #[cfg_attr(feature = "serde", serde(default))]
61 pub lib: bool,
62
63 #[arg(
65 long,
66 value_name = "NAME",
67 action = ArgAction::Append,
68 num_args=0..=1,
69 help_heading = heading::TARGET_SELECTION,
70 )]
71 #[cfg_attr(feature = "serde", serde(default))]
72 pub bin: Vec<String>,
73
74 #[arg(long)]
76 #[cfg_attr(feature = "serde", serde(default))]
77 pub bins: bool,
78
79 #[arg(
81 long,
82 value_name = "NAME",
83 action = ArgAction::Append,
84 num_args=0..=1,
85 help_heading = heading::TARGET_SELECTION,
86 )]
87 #[cfg_attr(feature = "serde", serde(default))]
88 pub example: Vec<String>,
89
90 #[arg(long, help_heading = heading::TARGET_SELECTION)]
92 #[cfg_attr(feature = "serde", serde(default))]
93 pub examples: bool,
94
95 #[arg(
97 long,
98 value_name = "NAME",
99 action = ArgAction::Append,
100 help_heading = heading::TARGET_SELECTION,
101 )]
102 #[cfg_attr(feature = "serde", serde(default))]
103 pub test: Vec<String>,
104
105 #[arg(long, help_heading = heading::TARGET_SELECTION)]
107 #[cfg_attr(feature = "serde", serde(default))]
108 pub tests: bool,
109
110 #[arg(
112 long,
113 value_name = "NAME",
114 action = ArgAction::Append,
115 help_heading = heading::TARGET_SELECTION,
116 )]
117 #[cfg_attr(feature = "serde", serde(default))]
118 pub bench: Vec<String>,
119
120 #[arg(long, help_heading = heading::TARGET_SELECTION)]
122 #[cfg_attr(feature = "serde", serde(default))]
123 pub benches: bool,
124
125 #[arg(long, help_heading = heading::TARGET_SELECTION)]
127 #[cfg_attr(feature = "serde", serde(default))]
128 pub all_targets: bool,
129
130 #[arg(long, value_name = "INFO")]
132 #[cfg_attr(feature = "serde", serde(default))]
133 pub print: Option<String>,
134
135 #[arg(long, value_name = "CRATE-TYPE", action = ArgAction::Append)]
137 #[cfg_attr(feature = "serde", serde(default))]
138 pub crate_type: Vec<String>,
139
140 #[arg(long)]
142 #[cfg_attr(feature = "serde", serde(default))]
143 pub future_incompat_report: bool,
144
145 #[arg(value_name = "args", trailing_var_arg = true, num_args = 0..)]
147 #[cfg_attr(feature = "serde", serde(default))]
148 pub args: Vec<String>,
149}
150
151impl Rustc {
152 pub fn command(&self) -> Command {
154 let mut cmd = CommonOptions::cargo_command();
155 cmd.arg("rustc");
156
157 self.common.apply(&mut cmd);
158
159 if let Some(path) = self.manifest_path.as_ref() {
160 cmd.arg("--manifest-path").arg(path);
161 }
162 if self.release {
163 cmd.arg("--release");
164 }
165 if self.ignore_rust_version {
166 cmd.arg("--ignore-rust-version");
167 }
168 if self.unit_graph {
169 cmd.arg("--unit-graph");
170 }
171 for pkg in &self.packages {
172 cmd.arg("--package").arg(pkg);
173 }
174 if self.lib {
175 cmd.arg("--lib");
176 }
177 for bin in &self.bin {
178 cmd.arg("--bin").arg(bin);
179 }
180 if self.bins {
181 cmd.arg("--bins");
182 }
183 for example in &self.example {
184 cmd.arg("--example").arg(example);
185 }
186 if self.examples {
187 cmd.arg("--examples");
188 }
189 for test in &self.test {
190 cmd.arg("--test").arg(test);
191 }
192 if self.tests {
193 cmd.arg("--tests");
194 }
195 for bench in &self.bench {
196 cmd.arg("--bench").arg(bench);
197 }
198 if self.benches {
199 cmd.arg("--benches");
200 }
201 if self.all_targets {
202 cmd.arg("--all-targets");
203 }
204 if let Some(print) = self.print.as_ref() {
205 cmd.arg("--print").arg(print);
206 }
207 if !self.crate_type.is_empty() {
208 cmd.arg("--crate-type").arg(self.crate_type.join(","));
209 }
210 if self.future_incompat_report {
211 cmd.arg("--future-incompat-report");
212 }
213 if !self.args.is_empty() {
214 cmd.arg("--").args(&self.args);
215 }
216
217 cmd
218 }
219}
220
221impl Deref for Rustc {
222 type Target = CommonOptions;
223
224 fn deref(&self) -> &Self::Target {
225 &self.common
226 }
227}
228
229impl DerefMut for Rustc {
230 fn deref_mut(&mut self) -> &mut Self::Target {
231 &mut self.common
232 }
233}
234
235#[cfg(test)]
236mod test {
237 use super::Rustc;
238 use clap::CommandFactory;
239
240 #[test]
241 fn verify_cli() {
242 <Rustc as CommandFactory>::command().debug_assert()
243 }
244}