]> git.proxmox.com Git - rustc.git/blame - src/bootstrap/flags.rs
New upstream version 1.17.0+dfsg1
[rustc.git] / src / bootstrap / flags.rs
CommitLineData
7453a54e
SL
1// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
a7813a04
XL
11//! Command-line interface of the rustbuild build system.
12//!
13//! This module implements the command-line parsing of the build system which
14//! has various flags to configure how it's run.
15
c30ab7b3 16use std::env;
7453a54e
SL
17use std::fs;
18use std::path::PathBuf;
19use std::process;
7453a54e 20
c30ab7b3
SL
21use getopts::{Matches, Options};
22
23use Build;
24use config::Config;
25use metadata;
26use step;
7453a54e 27
a7813a04 28/// Deserialized version of all flags for this compile.
7453a54e 29pub struct Flags {
32a655c1 30 pub verbose: usize, // verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose
8bb4bdeb 31 pub on_fail: Option<String>,
7453a54e 32 pub stage: Option<u32>,
476ff2be 33 pub keep_stage: Option<u32>,
7453a54e 34 pub build: String,
c30ab7b3
SL
35 pub host: Vec<String>,
36 pub target: Vec<String>,
7453a54e
SL
37 pub config: Option<PathBuf>,
38 pub src: Option<PathBuf>,
39 pub jobs: Option<u32>,
c30ab7b3 40 pub cmd: Subcommand,
32a655c1
SL
41 pub incremental: bool,
42}
43
44impl Flags {
45 pub fn verbose(&self) -> bool {
46 self.verbose > 0
47 }
48
49 pub fn very_verbose(&self) -> bool {
50 self.verbose > 1
51 }
7453a54e
SL
52}
53
c30ab7b3
SL
54pub enum Subcommand {
55 Build {
56 paths: Vec<PathBuf>,
57 },
58 Doc {
59 paths: Vec<PathBuf>,
60 },
61 Test {
62 paths: Vec<PathBuf>,
63 test_args: Vec<String>,
64 },
476ff2be
SL
65 Bench {
66 paths: Vec<PathBuf>,
67 test_args: Vec<String>,
68 },
c30ab7b3
SL
69 Clean,
70 Dist {
32a655c1 71 paths: Vec<PathBuf>,
c30ab7b3
SL
72 install: bool,
73 },
7453a54e
SL
74}
75
76impl Flags {
77 pub fn parse(args: &[String]) -> Flags {
78 let mut opts = Options::new();
32a655c1
SL
79 opts.optflagmulti("v", "verbose", "use verbose output (-vv for very verbose)");
80 opts.optflag("i", "incremental", "use incremental compilation");
7453a54e 81 opts.optopt("", "config", "TOML configuration file for build", "FILE");
c30ab7b3 82 opts.optopt("", "build", "build target of the stage0 compiler", "BUILD");
7453a54e 83 opts.optmulti("", "host", "host targets to build", "HOST");
c30ab7b3 84 opts.optmulti("", "target", "target targets to build", "TARGET");
8bb4bdeb 85 opts.optopt("", "on-fail", "command to run on failure", "CMD");
7453a54e 86 opts.optopt("", "stage", "stage to build", "N");
476ff2be 87 opts.optopt("", "keep-stage", "stage to keep without recompiling", "N");
c30ab7b3 88 opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
7453a54e 89 opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
7453a54e
SL
90 opts.optflag("h", "help", "print this help message");
91
c30ab7b3
SL
92 let usage = |n, opts: &Options| -> ! {
93 let command = args.get(0).map(|s| &**s);
94 let brief = format!("Usage: x.py {} [options] [<args>...]",
95 command.unwrap_or("<command>"));
96
97 println!("{}", opts.usage(&brief));
98 match command {
99 Some("build") => {
100 println!("\
101Arguments:
102 This subcommand accepts a number of positional arguments of directories to
103 the crates and/or artifacts to compile. For example:
104
105 ./x.py build src/libcore
106 ./x.py build src/libproc_macro
107 ./x.py build src/libstd --stage 1
108
109 If no arguments are passed then the complete artifacts for that stage are
110 also compiled.
111
112 ./x.py build
113 ./x.py build --stage 1
114
115 For a quick build with a usable compile, you can pass:
116
117 ./x.py build --stage 1 src/libtest
118");
119 }
120
121 Some("test") => {
122 println!("\
123Arguments:
124 This subcommand accepts a number of positional arguments of directories to
125 tests that should be compiled and run. For example:
126
127 ./x.py test src/test/run-pass
c30ab7b3
SL
128 ./x.py test src/libstd --test-args hash_map
129 ./x.py test src/libstd --stage 0
130
131 If no arguments are passed then the complete artifacts for that stage are
132 compiled and tested.
133
134 ./x.py test
135 ./x.py test --stage 1
136");
137 }
138
139 Some("doc") => {
140 println!("\
141Arguments:
142 This subcommand accepts a number of positional arguments of directories of
143 documentation to build. For example:
144
145 ./x.py doc src/doc/book
146 ./x.py doc src/doc/nomicon
147 ./x.py doc src/libstd
148
149 If no arguments are passed then everything is documented:
150
151 ./x.py doc
152 ./x.py doc --stage 1
153");
154 }
155
156 _ => {}
157 }
158
159 if let Some(command) = command {
160 if command == "build" ||
161 command == "dist" ||
162 command == "doc" ||
163 command == "test" ||
476ff2be 164 command == "bench" ||
c30ab7b3
SL
165 command == "clean" {
166 println!("Available invocations:");
167 if args.iter().any(|a| a == "-v") {
168 let flags = Flags::parse(&["build".to_string()]);
169 let mut config = Config::default();
170 config.build = flags.build.clone();
171 let mut build = Build::new(flags, config);
172 metadata::build(&mut build);
173 step::build_rules(&build).print_help(command);
174 } else {
175 println!(" ... elided, run `./x.py {} -h -v` to see",
176 command);
177 }
178
179 println!("");
180 }
181 }
182
183println!("\
184Subcommands:
185 build Compile either the compiler or libraries
186 test Build and run some test suites
476ff2be 187 bench Build and run some benchmarks
c30ab7b3
SL
188 doc Build documentation
189 clean Clean out build directories
190 dist Build and/or install distribution artifacts
191
192To learn more about a subcommand, run `./x.py <command> -h`
193");
194
7453a54e
SL
195 process::exit(n);
196 };
c30ab7b3
SL
197 if args.len() == 0 {
198 println!("a command must be passed");
199 usage(1, &opts);
7453a54e 200 }
c30ab7b3
SL
201 let parse = |opts: &Options| {
202 let m = opts.parse(&args[1..]).unwrap_or_else(|e| {
203 println!("failed to parse options: {}", e);
204 usage(1, opts);
205 });
206 if m.opt_present("h") {
207 usage(0, opts);
208 }
209 return m
210 };
211
212 let cwd = t!(env::current_dir());
213 let remaining_as_path = |m: &Matches| {
214 m.free.iter().map(|p| cwd.join(p)).collect::<Vec<_>>()
215 };
216
217 let m: Matches;
218 let cmd = match &args[0][..] {
219 "build" => {
220 m = parse(&opts);
221 Subcommand::Build { paths: remaining_as_path(&m) }
222 }
223 "doc" => {
224 m = parse(&opts);
225 Subcommand::Doc { paths: remaining_as_path(&m) }
226 }
227 "test" => {
228 opts.optmulti("", "test-args", "extra arguments", "ARGS");
229 m = parse(&opts);
230 Subcommand::Test {
231 paths: remaining_as_path(&m),
232 test_args: m.opt_strs("test-args"),
233 }
234 }
476ff2be
SL
235 "bench" => {
236 opts.optmulti("", "test-args", "extra arguments", "ARGS");
237 m = parse(&opts);
238 Subcommand::Bench {
239 paths: remaining_as_path(&m),
240 test_args: m.opt_strs("test-args"),
241 }
242 }
c30ab7b3
SL
243 "clean" => {
244 m = parse(&opts);
245 if m.free.len() > 0 {
246 println!("clean takes no arguments");
247 usage(1, &opts);
248 }
249 Subcommand::Clean
250 }
251 "dist" => {
252 opts.optflag("", "install", "run installer as well");
253 m = parse(&opts);
254 Subcommand::Dist {
32a655c1 255 paths: remaining_as_path(&m),
c30ab7b3
SL
256 install: m.opt_present("install"),
257 }
258 }
476ff2be 259 "--help" => usage(0, &opts),
c30ab7b3
SL
260 cmd => {
261 println!("unknown command: {}", cmd);
262 usage(1, &opts);
263 }
264 };
265
7453a54e 266
7453a54e
SL
267 let cfg_file = m.opt_str("config").map(PathBuf::from).or_else(|| {
268 if fs::metadata("config.toml").is_ok() {
269 Some(PathBuf::from("config.toml"))
270 } else {
271 None
272 }
273 });
274
32a655c1
SL
275 let mut stage = m.opt_str("stage").map(|j| j.parse().unwrap());
276
277 let incremental = m.opt_present("i");
278
279 if incremental {
280 if stage.is_none() {
281 stage = Some(1);
282 }
283 }
284
7453a54e 285 Flags {
32a655c1
SL
286 verbose: m.opt_count("v"),
287 stage: stage,
8bb4bdeb 288 on_fail: m.opt_str("on-fail"),
476ff2be 289 keep_stage: m.opt_str("keep-stage").map(|j| j.parse().unwrap()),
c30ab7b3
SL
290 build: m.opt_str("build").unwrap_or_else(|| {
291 env::var("BUILD").unwrap()
292 }),
32a655c1
SL
293 host: split(m.opt_strs("host")),
294 target: split(m.opt_strs("target")),
7453a54e
SL
295 config: cfg_file,
296 src: m.opt_str("src").map(PathBuf::from),
297 jobs: m.opt_str("jobs").map(|j| j.parse().unwrap()),
c30ab7b3 298 cmd: cmd,
32a655c1 299 incremental: incremental,
7453a54e
SL
300 }
301 }
302}
303
c30ab7b3
SL
304impl Subcommand {
305 pub fn test_args(&self) -> Vec<&str> {
306 match *self {
476ff2be
SL
307 Subcommand::Test { ref test_args, .. } |
308 Subcommand::Bench { ref test_args, .. } => {
c30ab7b3
SL
309 test_args.iter().flat_map(|s| s.split_whitespace()).collect()
310 }
311 _ => Vec::new(),
312 }
7453a54e
SL
313 }
314}
32a655c1
SL
315
316fn split(s: Vec<String>) -> Vec<String> {
317 s.iter().flat_map(|s| s.split(',')).map(|s| s.to_string()).collect()
318}