]> git.proxmox.com Git - rustc.git/blob - src/bootstrap/flags.rs
New upstream version 1.15.0+dfsg1
[rustc.git] / src / bootstrap / flags.rs
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
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
16 use std::env;
17 use std::fs;
18 use std::path::PathBuf;
19 use std::process;
20
21 use getopts::{Matches, Options};
22
23 use Build;
24 use config::Config;
25 use metadata;
26 use step;
27
28 /// Deserialized version of all flags for this compile.
29 pub struct Flags {
30 pub verbose: bool,
31 pub stage: Option<u32>,
32 pub keep_stage: Option<u32>,
33 pub build: String,
34 pub host: Vec<String>,
35 pub target: Vec<String>,
36 pub config: Option<PathBuf>,
37 pub src: Option<PathBuf>,
38 pub jobs: Option<u32>,
39 pub cmd: Subcommand,
40 }
41
42 pub enum Subcommand {
43 Build {
44 paths: Vec<PathBuf>,
45 },
46 Doc {
47 paths: Vec<PathBuf>,
48 },
49 Test {
50 paths: Vec<PathBuf>,
51 test_args: Vec<String>,
52 },
53 Bench {
54 paths: Vec<PathBuf>,
55 test_args: Vec<String>,
56 },
57 Clean,
58 Dist {
59 install: bool,
60 },
61 }
62
63 impl Flags {
64 pub fn parse(args: &[String]) -> Flags {
65 let mut opts = Options::new();
66 opts.optflag("v", "verbose", "use verbose output");
67 opts.optopt("", "config", "TOML configuration file for build", "FILE");
68 opts.optopt("", "build", "build target of the stage0 compiler", "BUILD");
69 opts.optmulti("", "host", "host targets to build", "HOST");
70 opts.optmulti("", "target", "target targets to build", "TARGET");
71 opts.optopt("", "stage", "stage to build", "N");
72 opts.optopt("", "keep-stage", "stage to keep without recompiling", "N");
73 opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
74 opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
75 opts.optflag("h", "help", "print this help message");
76
77 let usage = |n, opts: &Options| -> ! {
78 let command = args.get(0).map(|s| &**s);
79 let brief = format!("Usage: x.py {} [options] [<args>...]",
80 command.unwrap_or("<command>"));
81
82 println!("{}", opts.usage(&brief));
83 match command {
84 Some("build") => {
85 println!("\
86 Arguments:
87 This subcommand accepts a number of positional arguments of directories to
88 the crates and/or artifacts to compile. For example:
89
90 ./x.py build src/libcore
91 ./x.py build src/libproc_macro
92 ./x.py build src/libstd --stage 1
93
94 If no arguments are passed then the complete artifacts for that stage are
95 also compiled.
96
97 ./x.py build
98 ./x.py build --stage 1
99
100 For a quick build with a usable compile, you can pass:
101
102 ./x.py build --stage 1 src/libtest
103 ");
104 }
105
106 Some("test") => {
107 println!("\
108 Arguments:
109 This subcommand accepts a number of positional arguments of directories to
110 tests that should be compiled and run. For example:
111
112 ./x.py test src/test/run-pass
113 ./x.py test src/libstd --test-args hash_map
114 ./x.py test src/libstd --stage 0
115
116 If no arguments are passed then the complete artifacts for that stage are
117 compiled and tested.
118
119 ./x.py test
120 ./x.py test --stage 1
121 ");
122 }
123
124 Some("doc") => {
125 println!("\
126 Arguments:
127 This subcommand accepts a number of positional arguments of directories of
128 documentation to build. For example:
129
130 ./x.py doc src/doc/book
131 ./x.py doc src/doc/nomicon
132 ./x.py doc src/libstd
133
134 If no arguments are passed then everything is documented:
135
136 ./x.py doc
137 ./x.py doc --stage 1
138 ");
139 }
140
141 _ => {}
142 }
143
144 if let Some(command) = command {
145 if command == "build" ||
146 command == "dist" ||
147 command == "doc" ||
148 command == "test" ||
149 command == "bench" ||
150 command == "clean" {
151 println!("Available invocations:");
152 if args.iter().any(|a| a == "-v") {
153 let flags = Flags::parse(&["build".to_string()]);
154 let mut config = Config::default();
155 config.build = flags.build.clone();
156 let mut build = Build::new(flags, config);
157 metadata::build(&mut build);
158 step::build_rules(&build).print_help(command);
159 } else {
160 println!(" ... elided, run `./x.py {} -h -v` to see",
161 command);
162 }
163
164 println!("");
165 }
166 }
167
168 println!("\
169 Subcommands:
170 build Compile either the compiler or libraries
171 test Build and run some test suites
172 bench Build and run some benchmarks
173 doc Build documentation
174 clean Clean out build directories
175 dist Build and/or install distribution artifacts
176
177 To learn more about a subcommand, run `./x.py <command> -h`
178 ");
179
180 process::exit(n);
181 };
182 if args.len() == 0 {
183 println!("a command must be passed");
184 usage(1, &opts);
185 }
186 let parse = |opts: &Options| {
187 let m = opts.parse(&args[1..]).unwrap_or_else(|e| {
188 println!("failed to parse options: {}", e);
189 usage(1, opts);
190 });
191 if m.opt_present("h") {
192 usage(0, opts);
193 }
194 return m
195 };
196
197 let cwd = t!(env::current_dir());
198 let remaining_as_path = |m: &Matches| {
199 m.free.iter().map(|p| cwd.join(p)).collect::<Vec<_>>()
200 };
201
202 let m: Matches;
203 let cmd = match &args[0][..] {
204 "build" => {
205 m = parse(&opts);
206 Subcommand::Build { paths: remaining_as_path(&m) }
207 }
208 "doc" => {
209 m = parse(&opts);
210 Subcommand::Doc { paths: remaining_as_path(&m) }
211 }
212 "test" => {
213 opts.optmulti("", "test-args", "extra arguments", "ARGS");
214 m = parse(&opts);
215 Subcommand::Test {
216 paths: remaining_as_path(&m),
217 test_args: m.opt_strs("test-args"),
218 }
219 }
220 "bench" => {
221 opts.optmulti("", "test-args", "extra arguments", "ARGS");
222 m = parse(&opts);
223 Subcommand::Bench {
224 paths: remaining_as_path(&m),
225 test_args: m.opt_strs("test-args"),
226 }
227 }
228 "clean" => {
229 m = parse(&opts);
230 if m.free.len() > 0 {
231 println!("clean takes no arguments");
232 usage(1, &opts);
233 }
234 Subcommand::Clean
235 }
236 "dist" => {
237 opts.optflag("", "install", "run installer as well");
238 m = parse(&opts);
239 Subcommand::Dist {
240 install: m.opt_present("install"),
241 }
242 }
243 "--help" => usage(0, &opts),
244 cmd => {
245 println!("unknown command: {}", cmd);
246 usage(1, &opts);
247 }
248 };
249
250
251 let cfg_file = m.opt_str("config").map(PathBuf::from).or_else(|| {
252 if fs::metadata("config.toml").is_ok() {
253 Some(PathBuf::from("config.toml"))
254 } else {
255 None
256 }
257 });
258
259 Flags {
260 verbose: m.opt_present("v"),
261 stage: m.opt_str("stage").map(|j| j.parse().unwrap()),
262 keep_stage: m.opt_str("keep-stage").map(|j| j.parse().unwrap()),
263 build: m.opt_str("build").unwrap_or_else(|| {
264 env::var("BUILD").unwrap()
265 }),
266 host: m.opt_strs("host"),
267 target: m.opt_strs("target"),
268 config: cfg_file,
269 src: m.opt_str("src").map(PathBuf::from),
270 jobs: m.opt_str("jobs").map(|j| j.parse().unwrap()),
271 cmd: cmd,
272 }
273 }
274 }
275
276 impl Subcommand {
277 pub fn test_args(&self) -> Vec<&str> {
278 match *self {
279 Subcommand::Test { ref test_args, .. } |
280 Subcommand::Bench { ref test_args, .. } => {
281 test_args.iter().flat_map(|s| s.split_whitespace()).collect()
282 }
283 _ => Vec::new(),
284 }
285 }
286 }