1 use std::path::PathBuf;
2 
3 use cargo::util::command_prelude::AppExt;
4 use cargo::util::command_prelude::{multi_opt, opt};
5 use cargo::util::{CliError, CliResult};
6 
7 use cargo_util::{ProcessBuilder, ProcessError};
8 use structopt::clap::*;
9 use structopt::StructOpt;
10 
11 // TODO: convert to a function using cargo opt()
12 #[allow(dead_code)]
13 #[derive(Clone, Debug, StructOpt)]
14 struct Common {
15     /// Path to directory where target should be copied to
16     #[structopt(long = "destdir", parse(from_os_str))]
17     destdir: Option<PathBuf>,
18     /// Directory path used to construct default values of
19     /// includedir, libdir, bindir, pkgconfigdir
20     #[structopt(long = "prefix", parse(from_os_str))]
21     prefix: Option<PathBuf>,
22     /// Path to directory for installing generated library files
23     #[structopt(long = "libdir", parse(from_os_str))]
24     libdir: Option<PathBuf>,
25     /// Path to directory for installing generated headers files
26     #[structopt(long = "includedir", parse(from_os_str))]
27     includedir: Option<PathBuf>,
28     /// Path to directory for installing generated executable files
29     #[structopt(long = "bindir", parse(from_os_str))]
30     bindir: Option<PathBuf>,
31     /// Path to directory for installing generated pkg-config .pc files
32     #[structopt(long = "pkgconfigdir", parse(from_os_str))]
33     pkgconfigdir: Option<PathBuf>,
34     /// Path to directory for installing read-only data (defaults to {prefix}/share)
35     #[structopt(long = "datarootdir", parse(from_os_str))]
36     datarootdir: Option<PathBuf>,
37     /// Path to directory for installing read-only application-specific data
38     /// (defaults to {datarootdir})
39     #[structopt(long = "datadir", parse(from_os_str))]
40     datadir: Option<PathBuf>,
41     #[structopt(long = "dlltool", parse(from_os_str))]
42     /// Use the provided dlltool when building for the windows-gnu targets.
43     dlltool: Option<PathBuf>,
44     #[structopt(long = "crt-static")]
45     /// Build the library embedding the C runtime
46     crt_static: bool,
47 }
48 
base_cli() -> App<'static, 'static>49 fn base_cli() -> App<'static, 'static> {
50     Common::clap()
51         .setting(AppSettings::ColoredHelp)
52         .arg(opt("version", "Print version info and exit").short("V"))
53         .arg(
54             opt(
55                 "verbose",
56                 "Use verbose output (-vv very verbose/build.rs output)",
57             )
58             .short("v")
59             .multiple(true)
60             .global(true),
61         )
62         .arg(opt("quiet", "No output printed to stdout").short("q"))
63         .arg(
64             opt("color", "Coloring: auto, always, never")
65                 .value_name("WHEN")
66                 .global(true),
67         )
68         .arg(opt("frozen", "Require Cargo.lock and cache are up to date").global(true))
69         .arg(opt("locked", "Require Cargo.lock is up to date").global(true))
70         .arg(opt("offline", "Run without accessing the network").global(true))
71         .arg(
72             multi_opt("config", "KEY=VALUE", "Override a configuration value")
73                 .global(true)
74                 .hidden(true),
75         )
76         .arg_jobs()
77         .arg_profile("Build artifacts with the specified profile")
78         .arg_features()
79         .arg_target_triple("Build for the target triple")
80         .arg_target_dir()
81         .arg_manifest_path()
82         .arg_message_format()
83         .arg_build_plan()
84 }
85 
subcommand_build(name: &str, about: &'static str) -> App<'static, 'static>86 pub fn subcommand_build(name: &str, about: &'static str) -> App<'static, 'static> {
87     base_cli()
88         .name(name)
89         .about(about)
90         .arg(
91             multi_opt(
92                 "library-type",
93                 "LIBRARY-TYPE",
94                 "Build only a type of library",
95             )
96             .global(true)
97             .case_insensitive(true)
98             .possible_values(&["cdylib", "staticlib"]),
99         )
100         .arg_release("Build artifacts in release mode, with optimizations")
101         .arg_package_spec_no_all(
102             "Package to build (see `cargo help pkgid`)",
103             "Build all packages in the workspace",
104             "Exclude packages from the build",
105         )
106         .after_help(
107             "
108 Compilation can be configured via the use of profiles which are configured in
109 the manifest. The default profile for this command is `dev`, but passing
110 the --release flag will use the `release` profile instead.
111 ",
112         )
113 }
114 
subcommand_install(name: &str, about: &'static str) -> App<'static, 'static>115 pub fn subcommand_install(name: &str, about: &'static str) -> App<'static, 'static> {
116     base_cli()
117         .name(name)
118         .about(about)
119         .arg(
120             multi_opt(
121                 "library-type",
122                 "LIBRARY-TYPE",
123                 "Build only a type of library",
124             )
125             .global(true)
126             .case_insensitive(true)
127             .possible_values(&["cdylib", "staticlib"]),
128         )
129         .arg(opt("debug", "Build in debug mode instead of release mode"))
130         .arg_release(
131             "Build artifacts in release mode, with optimizations. This is the default behavior.",
132         )
133         .arg_package_spec_no_all(
134             "Package to install (see `cargo help pkgid`)",
135             "Install all packages in the workspace",
136             "Exclude packages from being installed",
137         )
138         .after_help(
139             "
140 Compilation can be configured via the use of profiles which are configured in
141 the manifest. The default profile for this command is `release`, but passing
142 the --debug flag will use the `dev` profile instead.
143 ",
144         )
145 }
146 
subcommand_test(name: &str) -> App<'static, 'static>147 pub fn subcommand_test(name: &str) -> App<'static, 'static> {
148     base_cli()
149         .settings(&[AppSettings::TrailingVarArg])
150         .name(name)
151         .about("Test the crate C-API")
152         .arg(
153             Arg::with_name("args")
154                 .help("Arguments for the test binary")
155                 .multiple(true)
156                 .last(true),
157         )
158         .arg_release("Build artifacts in release mode, with optimizations")
159         .arg_package_spec_no_all(
160             "Package to run tests for",
161             "Test all packages in the workspace",
162             "Exclude packages from the test",
163         )
164         .arg(opt("no-run", "Compile, but don't run tests"))
165         .arg(opt("no-fail-fast", "Run all tests regardless of failure"))
166 }
167 
run_cargo_fallback(subcommand: &str, subcommand_args: &ArgMatches) -> CliResult168 pub fn run_cargo_fallback(subcommand: &str, subcommand_args: &ArgMatches) -> CliResult {
169     let cargo = std::env::var("CARGO_C_CARGO").unwrap_or_else(|_| "cargo".to_owned());
170     let mut args = vec![subcommand];
171 
172     args.extend(subcommand_args.values_of("").unwrap_or_default());
173     let err = match ProcessBuilder::new(&cargo).args(&args).exec_replace() {
174         Ok(()) => return Ok(()),
175         Err(e) => e,
176     };
177 
178     if let Some(perr) = err.downcast_ref::<ProcessError>() {
179         if let Some(code) = perr.code {
180             return Err(CliError::code(code));
181         }
182     }
183     Err(CliError::new(err, 101))
184 }
185