cargo_options/
build.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 local package and all of its dependencies
14#[derive(Clone, Debug, Default, Parser)]
15#[command(
16    display_order = 1,
17    after_help = "Run `cargo help build` for more detailed information."
18)]
19#[group(skip)]
20#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
21pub struct Build {
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 all packages in the workspace
59    #[arg(long, help_heading = heading::PACKAGE_SELECTION)]
60    #[cfg_attr(feature = "serde", serde(default))]
61    pub workspace: bool,
62
63    /// Exclude packages from the build
64    #[arg(
65        long,
66        value_name = "SPEC",
67        action = ArgAction::Append,
68        help_heading = heading::PACKAGE_SELECTION,
69    )]
70    #[cfg_attr(feature = "serde", serde(default))]
71    pub exclude: Vec<String>,
72
73    /// Alias for workspace (deprecated)
74    #[arg(long, help_heading = heading::PACKAGE_SELECTION)]
75    #[cfg_attr(feature = "serde", serde(default))]
76    pub all: bool,
77
78    /// Build only this package's library
79    #[arg(long, help_heading = heading::TARGET_SELECTION)]
80    #[cfg_attr(feature = "serde", serde(default))]
81    pub lib: bool,
82
83    /// Build only the specified binary
84    #[arg(
85        long,
86        value_name = "NAME",
87        action = ArgAction::Append,
88        num_args=0..=1,
89        help_heading = heading::TARGET_SELECTION,
90    )]
91    #[cfg_attr(feature = "serde", serde(default))]
92    pub bin: Vec<String>,
93
94    /// Build all binaries
95    #[arg(long, help_heading = heading::TARGET_SELECTION)]
96    #[cfg_attr(feature = "serde", serde(default))]
97    pub bins: bool,
98
99    /// Build only the specified example
100    #[arg(
101        long,
102        value_name = "NAME",
103        action = ArgAction::Append,
104        num_args=0..=1,
105        help_heading = heading::TARGET_SELECTION,
106    )]
107    #[cfg_attr(feature = "serde", serde(default))]
108    pub example: Vec<String>,
109
110    /// Build all examples
111    #[arg(long, help_heading = heading::TARGET_SELECTION)]
112    #[cfg_attr(feature = "serde", serde(default))]
113    pub examples: bool,
114
115    /// Build only the specified test 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 test: Vec<String>,
124
125    /// Build all tests
126    #[arg(long, help_heading = heading::TARGET_SELECTION)]
127    #[cfg_attr(feature = "serde", serde(default))]
128    pub tests: bool,
129
130    /// Build only the specified bench target
131    #[arg(
132        long,
133        value_name = "NAME",
134        action = ArgAction::Append,
135        help_heading = heading::TARGET_SELECTION,
136    )]
137    #[cfg_attr(feature = "serde", serde(default))]
138    pub bench: Vec<String>,
139
140    /// Build all benches
141    #[arg(long, help_heading = heading::TARGET_SELECTION)]
142    #[cfg_attr(feature = "serde", serde(default))]
143    pub benches: bool,
144
145    /// Build all targets
146    #[arg(long, help_heading = heading::TARGET_SELECTION)]
147    #[cfg_attr(feature = "serde", serde(default))]
148    pub all_targets: bool,
149
150    /// Copy final artifacts to this directory (unstable)
151    #[arg(long, alias = "out-dir", value_name = "PATH", help_heading = heading::COMPILATION_OPTIONS)]
152    #[cfg_attr(feature = "serde", serde(default))]
153    pub artifact_dir: Option<PathBuf>,
154
155    /// Output the build plan in JSON (unstable)
156    #[arg(long, help_heading = heading::COMPILATION_OPTIONS)]
157    #[cfg_attr(feature = "serde", serde(default))]
158    pub build_plan: bool,
159
160    /// Outputs a future incompatibility report at the end of the build (unstable)
161    #[arg(long)]
162    #[cfg_attr(feature = "serde", serde(default))]
163    pub future_incompat_report: bool,
164}
165
166impl Build {
167    /// Build a `cargo build` command
168    pub fn command(&self) -> Command {
169        let mut cmd = CommonOptions::cargo_command();
170        cmd.arg("build");
171
172        self.common.apply(&mut cmd);
173
174        if let Some(path) = self.manifest_path.as_ref() {
175            cmd.arg("--manifest-path").arg(path);
176        }
177        if self.release {
178            cmd.arg("--release");
179        }
180        if self.ignore_rust_version {
181            cmd.arg("--ignore-rust-version");
182        }
183        if self.unit_graph {
184            cmd.arg("--unit-graph");
185        }
186        for pkg in &self.packages {
187            cmd.arg("--package").arg(pkg);
188        }
189        if self.workspace {
190            cmd.arg("--workspace");
191        }
192        for item in &self.exclude {
193            cmd.arg("--exclude").arg(item);
194        }
195        if self.all {
196            cmd.arg("--all");
197        }
198        if self.lib {
199            cmd.arg("--lib");
200        }
201        for bin in &self.bin {
202            cmd.arg("--bin").arg(bin);
203        }
204        if self.bins {
205            cmd.arg("--bins");
206        }
207        for example in &self.example {
208            cmd.arg("--example").arg(example);
209        }
210        if self.examples {
211            cmd.arg("--examples");
212        }
213        for test in &self.test {
214            cmd.arg("--test").arg(test);
215        }
216        if self.tests {
217            cmd.arg("--tests");
218        }
219        for bench in &self.bench {
220            cmd.arg("--bench").arg(bench);
221        }
222        if self.benches {
223            cmd.arg("--benches");
224        }
225        if self.all_targets {
226            cmd.arg("--all-targets");
227        }
228        if let Some(dir) = self.artifact_dir.as_ref() {
229            cmd.arg("--artifact-dir").arg(dir);
230        }
231        if self.build_plan {
232            cmd.arg("--build-plan");
233        }
234        if self.future_incompat_report {
235            cmd.arg("--future-incompat-report");
236        }
237
238        cmd
239    }
240}
241
242impl Deref for Build {
243    type Target = CommonOptions;
244
245    fn deref(&self) -> &Self::Target {
246        &self.common
247    }
248}
249
250impl DerefMut for Build {
251    fn deref_mut(&mut self) -> &mut Self::Target {
252        &mut self.common
253    }
254}
255
256#[cfg(test)]
257mod test {
258    use super::Build;
259    use clap::CommandFactory;
260
261    #[test]
262    fn verify_cli() {
263        <Build as CommandFactory>::command().debug_assert()
264    }
265}