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