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(short = 'r', long, help_heading = heading::COMPILATION_OPTIONS)]
33    #[cfg_attr(feature = "serde", serde(default))]
34    pub release: bool,
35
36    /// Ignore `rust-version` specification in packages
37    #[arg(long)]
38    #[cfg_attr(feature = "serde", serde(default))]
39    pub ignore_rust_version: bool,
40
41    /// Output build graph in JSON (unstable)
42    #[arg(long, help_heading = heading::COMPILATION_OPTIONS)]
43    #[cfg_attr(feature = "serde", serde(default))]
44    pub unit_graph: bool,
45
46    /// Package to build (see `cargo help pkgid`)
47    #[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    /// Build only this package's library
59    #[arg(long, help_heading = heading::TARGET_SELECTION)]
60    #[cfg_attr(feature = "serde", serde(default))]
61    pub lib: bool,
62
63    /// Build only the specified binary
64    #[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    /// Build all binaries
75    #[arg(long)]
76    #[cfg_attr(feature = "serde", serde(default))]
77    pub bins: bool,
78
79    /// Build only the specified example
80    #[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    /// Build all examples
91    #[arg(long, help_heading = heading::TARGET_SELECTION)]
92    #[cfg_attr(feature = "serde", serde(default))]
93    pub examples: bool,
94
95    /// Build only the specified test target
96    #[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    /// Build all tests
106    #[arg(long, help_heading = heading::TARGET_SELECTION)]
107    #[cfg_attr(feature = "serde", serde(default))]
108    pub tests: bool,
109
110    /// Build only the specified bench target
111    #[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    /// Build all benches
121    #[arg(long, help_heading = heading::TARGET_SELECTION)]
122    #[cfg_attr(feature = "serde", serde(default))]
123    pub benches: bool,
124
125    /// Build all targets
126    #[arg(long, help_heading = heading::TARGET_SELECTION)]
127    #[cfg_attr(feature = "serde", serde(default))]
128    pub all_targets: bool,
129
130    /// Output compiler information without compiling
131    #[arg(long, value_name = "INFO")]
132    #[cfg_attr(feature = "serde", serde(default))]
133    pub print: Option<String>,
134
135    /// Comma separated list of types of crates for the compiler to emit
136    #[arg(long, value_name = "CRATE-TYPE", action = ArgAction::Append)]
137    #[cfg_attr(feature = "serde", serde(default))]
138    pub crate_type: Vec<String>,
139
140    /// Outputs a future incompatibility report at the end of the build (unstable)
141    #[arg(long)]
142    #[cfg_attr(feature = "serde", serde(default))]
143    pub future_incompat_report: bool,
144
145    /// Rustc flags
146    #[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    /// Build a `cargo rustc` command
153    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}