]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2014 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 | //! Contains infrastructure for configuring the compiler, including parsing | |
12 | //! command line options. | |
13 | ||
14 | pub use self::EntryFnType::*; | |
15 | pub use self::CrateType::*; | |
16 | pub use self::Passes::*; | |
17 | pub use self::OptLevel::*; | |
18 | pub use self::OutputType::*; | |
19 | pub use self::DebugInfoLevel::*; | |
20 | ||
21 | use session::{early_error, early_warn, Session}; | |
22 | use session::search_paths::SearchPaths; | |
23 | ||
24 | use rustc_back::target::Target; | |
25 | use lint; | |
26 | use metadata::cstore; | |
27 | ||
28 | use syntax::ast; | |
29 | use syntax::ast::{IntTy, UintTy}; | |
30 | use syntax::attr; | |
31 | use syntax::attr::AttrMetaMethods; | |
32 | use syntax::diagnostic::{ColorConfig, Auto, Always, Never, SpanHandler}; | |
33 | use syntax::parse; | |
34 | use syntax::parse::token::InternedString; | |
35 | ||
85aaf69f | 36 | use getopts; |
1a4d82fc | 37 | use std::collections::HashMap; |
85aaf69f | 38 | use std::env; |
1a4d82fc | 39 | use std::fmt; |
c34b1796 | 40 | use std::path::PathBuf; |
1a4d82fc JJ |
41 | |
42 | use llvm; | |
43 | ||
44 | pub struct Config { | |
45 | pub target: Target, | |
46 | pub int_type: IntTy, | |
47 | pub uint_type: UintTy, | |
48 | } | |
49 | ||
50 | #[derive(Clone, Copy, PartialEq)] | |
51 | pub enum OptLevel { | |
52 | No, // -O0 | |
53 | Less, // -O1 | |
54 | Default, // -O2 | |
55 | Aggressive // -O3 | |
56 | } | |
57 | ||
58 | #[derive(Clone, Copy, PartialEq)] | |
59 | pub enum DebugInfoLevel { | |
60 | NoDebugInfo, | |
61 | LimitedDebugInfo, | |
62 | FullDebugInfo, | |
63 | } | |
64 | ||
65 | #[derive(Clone, Copy, PartialEq, PartialOrd, Ord, Eq)] | |
66 | pub enum OutputType { | |
67 | OutputTypeBitcode, | |
68 | OutputTypeAssembly, | |
69 | OutputTypeLlvmAssembly, | |
70 | OutputTypeObject, | |
71 | OutputTypeExe, | |
72 | OutputTypeDepInfo, | |
73 | } | |
74 | ||
75 | #[derive(Clone)] | |
76 | pub struct Options { | |
77 | // The crate config requested for the session, which may be combined | |
78 | // with additional crate configurations during the compile process | |
79 | pub crate_types: Vec<CrateType>, | |
80 | ||
81 | pub gc: bool, | |
82 | pub optimize: OptLevel, | |
c34b1796 | 83 | pub debug_assertions: bool, |
1a4d82fc JJ |
84 | pub debuginfo: DebugInfoLevel, |
85 | pub lint_opts: Vec<(String, lint::Level)>, | |
86 | pub describe_lints: bool, | |
85aaf69f | 87 | pub output_types: Vec<OutputType>, |
1a4d82fc JJ |
88 | // This was mutable for rustpkg, which updates search paths based on the |
89 | // parsed code. It remains mutable in case its replacements wants to use | |
90 | // this. | |
91 | pub search_paths: SearchPaths, | |
92 | pub libs: Vec<(String, cstore::NativeLibraryKind)>, | |
c34b1796 | 93 | pub maybe_sysroot: Option<PathBuf>, |
1a4d82fc JJ |
94 | pub target_triple: String, |
95 | // User-specified cfg meta items. The compiler itself will add additional | |
96 | // items to the crate config, and during parsing the entire crate config | |
97 | // will be added to the crate AST node. This should not be used for | |
98 | // anything except building the full crate config prior to parsing. | |
99 | pub cfg: ast::CrateConfig, | |
100 | pub test: bool, | |
101 | pub parse_only: bool, | |
102 | pub no_trans: bool, | |
c34b1796 | 103 | pub treat_err_as_bug: bool, |
1a4d82fc JJ |
104 | pub no_analysis: bool, |
105 | pub debugging_opts: DebuggingOptions, | |
106 | /// Whether to write dependency files. It's (enabled, optional filename). | |
c34b1796 | 107 | pub write_dependency_info: (bool, Option<PathBuf>), |
1a4d82fc JJ |
108 | pub prints: Vec<PrintRequest>, |
109 | pub cg: CodegenOptions, | |
110 | pub color: ColorConfig, | |
111 | pub show_span: Option<String>, | |
112 | pub externs: HashMap<String, Vec<String>>, | |
113 | pub crate_name: Option<String>, | |
114 | /// An optional name to use as the crate for std during std injection, | |
115 | /// written `extern crate std = "name"`. Default to "std". Used by | |
116 | /// out-of-tree drivers. | |
117 | pub alt_std_name: Option<String>, | |
118 | /// Indicates how the compiler should treat unstable features | |
119 | pub unstable_features: UnstableFeatures | |
120 | } | |
121 | ||
122 | #[derive(Clone, Copy)] | |
123 | pub enum UnstableFeatures { | |
124 | /// Hard errors for unstable features are active, as on | |
125 | /// beta/stable channels. | |
126 | Disallow, | |
127 | /// Use the default lint levels | |
128 | Default, | |
129 | /// Errors are bypassed for bootstrapping. This is required any time | |
130 | /// during the build that feature-related lints are set to warn or above | |
131 | /// because the build turns on warnings-as-errors and uses lots of unstable | |
132 | /// features. As a result, this this is always required for building Rust | |
133 | /// itself. | |
134 | Cheat | |
135 | } | |
136 | ||
137 | #[derive(Clone, PartialEq, Eq)] | |
1a4d82fc JJ |
138 | pub enum PrintRequest { |
139 | FileNames, | |
140 | Sysroot, | |
141 | CrateName, | |
142 | } | |
143 | ||
144 | pub enum Input { | |
145 | /// Load source from file | |
c34b1796 | 146 | File(PathBuf), |
1a4d82fc JJ |
147 | /// The string is the source |
148 | Str(String) | |
149 | } | |
150 | ||
151 | impl Input { | |
152 | pub fn filestem(&self) -> String { | |
153 | match *self { | |
c34b1796 AL |
154 | Input::File(ref ifile) => ifile.file_stem().unwrap() |
155 | .to_str().unwrap().to_string(), | |
1a4d82fc JJ |
156 | Input::Str(_) => "rust_out".to_string(), |
157 | } | |
158 | } | |
159 | } | |
160 | ||
161 | #[derive(Clone)] | |
162 | pub struct OutputFilenames { | |
c34b1796 | 163 | pub out_directory: PathBuf, |
1a4d82fc | 164 | pub out_filestem: String, |
c34b1796 | 165 | pub single_output_file: Option<PathBuf>, |
1a4d82fc JJ |
166 | pub extra: String, |
167 | } | |
168 | ||
169 | impl OutputFilenames { | |
c34b1796 | 170 | pub fn path(&self, flavor: OutputType) -> PathBuf { |
1a4d82fc JJ |
171 | match self.single_output_file { |
172 | Some(ref path) => return path.clone(), | |
173 | None => {} | |
174 | } | |
175 | self.temp_path(flavor) | |
176 | } | |
177 | ||
c34b1796 AL |
178 | pub fn temp_path(&self, flavor: OutputType) -> PathBuf { |
179 | let base = self.out_directory.join(&self.filestem()); | |
1a4d82fc JJ |
180 | match flavor { |
181 | OutputTypeBitcode => base.with_extension("bc"), | |
182 | OutputTypeAssembly => base.with_extension("s"), | |
183 | OutputTypeLlvmAssembly => base.with_extension("ll"), | |
184 | OutputTypeObject => base.with_extension("o"), | |
185 | OutputTypeDepInfo => base.with_extension("d"), | |
186 | OutputTypeExe => base, | |
187 | } | |
188 | } | |
189 | ||
c34b1796 AL |
190 | pub fn with_extension(&self, extension: &str) -> PathBuf { |
191 | self.out_directory.join(&self.filestem()).with_extension(extension) | |
1a4d82fc JJ |
192 | } |
193 | ||
194 | pub fn filestem(&self) -> String { | |
195 | format!("{}{}", self.out_filestem, self.extra) | |
196 | } | |
197 | } | |
198 | ||
199 | pub fn host_triple() -> &'static str { | |
200 | // Get the host triple out of the build environment. This ensures that our | |
201 | // idea of the host triple is the same as for the set of libraries we've | |
202 | // actually built. We can't just take LLVM's host triple because they | |
203 | // normalize all ix86 architectures to i386. | |
204 | // | |
205 | // Instead of grabbing the host triple (for the current host), we grab (at | |
206 | // compile time) the target triple that this rustc is built with and | |
207 | // calling that (at runtime) the host triple. | |
208 | (option_env!("CFG_COMPILER_HOST_TRIPLE")). | |
209 | expect("CFG_COMPILER_HOST_TRIPLE") | |
210 | } | |
211 | ||
212 | /// Some reasonable defaults | |
213 | pub fn basic_options() -> Options { | |
214 | Options { | |
215 | crate_types: Vec::new(), | |
216 | gc: false, | |
217 | optimize: No, | |
218 | debuginfo: NoDebugInfo, | |
219 | lint_opts: Vec::new(), | |
220 | describe_lints: false, | |
221 | output_types: Vec::new(), | |
222 | search_paths: SearchPaths::new(), | |
223 | maybe_sysroot: None, | |
224 | target_triple: host_triple().to_string(), | |
225 | cfg: Vec::new(), | |
226 | test: false, | |
227 | parse_only: false, | |
228 | no_trans: false, | |
c34b1796 | 229 | treat_err_as_bug: false, |
1a4d82fc JJ |
230 | no_analysis: false, |
231 | debugging_opts: basic_debugging_options(), | |
232 | write_dependency_info: (false, None), | |
233 | prints: Vec::new(), | |
234 | cg: basic_codegen_options(), | |
235 | color: Auto, | |
236 | show_span: None, | |
237 | externs: HashMap::new(), | |
238 | crate_name: None, | |
239 | alt_std_name: None, | |
240 | libs: Vec::new(), | |
c34b1796 AL |
241 | unstable_features: UnstableFeatures::Disallow, |
242 | debug_assertions: true, | |
1a4d82fc JJ |
243 | } |
244 | } | |
245 | ||
246 | // The type of entry function, so | |
247 | // users can have their own entry | |
248 | // functions that don't start a | |
249 | // scheduler | |
c34b1796 | 250 | #[derive(Copy, Clone, PartialEq)] |
1a4d82fc JJ |
251 | pub enum EntryFnType { |
252 | EntryMain, | |
253 | EntryStart, | |
254 | EntryNone, | |
255 | } | |
256 | ||
85aaf69f | 257 | #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)] |
1a4d82fc JJ |
258 | pub enum CrateType { |
259 | CrateTypeExecutable, | |
260 | CrateTypeDylib, | |
261 | CrateTypeRlib, | |
262 | CrateTypeStaticlib, | |
263 | } | |
264 | ||
1a4d82fc JJ |
265 | #[derive(Clone)] |
266 | pub enum Passes { | |
267 | SomePasses(Vec<String>), | |
268 | AllPasses, | |
269 | } | |
270 | ||
271 | impl Passes { | |
272 | pub fn is_empty(&self) -> bool { | |
273 | match *self { | |
274 | SomePasses(ref v) => v.is_empty(), | |
275 | AllPasses => false, | |
276 | } | |
277 | } | |
278 | } | |
279 | ||
280 | /// Declare a macro that will define all CodegenOptions/DebuggingOptions fields and parsers all | |
281 | /// at once. The goal of this macro is to define an interface that can be | |
282 | /// programmatically used by the option parser in order to initialize the struct | |
283 | /// without hardcoding field names all over the place. | |
284 | /// | |
285 | /// The goal is to invoke this macro once with the correct fields, and then this | |
286 | /// macro generates all necessary code. The main gotcha of this macro is the | |
287 | /// cgsetters module which is a bunch of generated code to parse an option into | |
288 | /// its respective field in the struct. There are a few hand-written parsers for | |
289 | /// parsing specific types of values in this module. | |
290 | macro_rules! options { | |
291 | ($struct_name:ident, $setter_name:ident, $defaultfn:ident, | |
292 | $buildfn:ident, $prefix:expr, $outputname:expr, | |
293 | $stat:ident, $mod_desc:ident, $mod_set:ident, | |
294 | $($opt:ident : $t:ty = ($init:expr, $parse:ident, $desc:expr)),* ,) => | |
295 | ( | |
296 | #[derive(Clone)] | |
1a4d82fc JJ |
297 | pub struct $struct_name { $(pub $opt: $t),* } |
298 | ||
299 | pub fn $defaultfn() -> $struct_name { | |
300 | $struct_name { $($opt: $init),* } | |
301 | } | |
302 | ||
303 | pub fn $buildfn(matches: &getopts::Matches) -> $struct_name | |
304 | { | |
305 | let mut op = $defaultfn(); | |
85aaf69f | 306 | for option in matches.opt_strs($prefix) { |
c34b1796 | 307 | let mut iter = option.splitn(2, '='); |
1a4d82fc JJ |
308 | let key = iter.next().unwrap(); |
309 | let value = iter.next(); | |
310 | let option_to_lookup = key.replace("-", "_"); | |
311 | let mut found = false; | |
85aaf69f | 312 | for &(candidate, setter, opt_type_desc, _) in $stat { |
1a4d82fc JJ |
313 | if option_to_lookup != candidate { continue } |
314 | if !setter(&mut op, value) { | |
315 | match (value, opt_type_desc) { | |
316 | (Some(..), None) => { | |
317 | early_error(&format!("{} option `{}` takes no \ | |
c34b1796 | 318 | value", $outputname, key)) |
1a4d82fc JJ |
319 | } |
320 | (None, Some(type_desc)) => { | |
321 | early_error(&format!("{0} option `{1}` requires \ | |
322 | {2} ({3} {1}=<value>)", | |
323 | $outputname, key, | |
c34b1796 | 324 | type_desc, $prefix)) |
1a4d82fc JJ |
325 | } |
326 | (Some(value), Some(type_desc)) => { | |
327 | early_error(&format!("incorrect value `{}` for {} \ | |
328 | option `{}` - {} was expected", | |
329 | value, $outputname, | |
c34b1796 | 330 | key, type_desc)) |
1a4d82fc JJ |
331 | } |
332 | (None, None) => unreachable!() | |
333 | } | |
334 | } | |
335 | found = true; | |
336 | break; | |
337 | } | |
338 | if !found { | |
85aaf69f | 339 | early_error(&format!("unknown {} option: `{}`", |
c34b1796 | 340 | $outputname, key)); |
1a4d82fc JJ |
341 | } |
342 | } | |
343 | return op; | |
344 | } | |
345 | ||
346 | pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool; | |
347 | pub const $stat: &'static [(&'static str, $setter_name, | |
348 | Option<&'static str>, &'static str)] = | |
349 | &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ]; | |
350 | ||
351 | #[allow(non_upper_case_globals, dead_code)] | |
352 | mod $mod_desc { | |
353 | pub const parse_bool: Option<&'static str> = None; | |
c34b1796 AL |
354 | pub const parse_opt_bool: Option<&'static str> = |
355 | Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`"); | |
1a4d82fc JJ |
356 | pub const parse_string: Option<&'static str> = Some("a string"); |
357 | pub const parse_opt_string: Option<&'static str> = Some("a string"); | |
358 | pub const parse_list: Option<&'static str> = Some("a space-separated list of strings"); | |
359 | pub const parse_opt_list: Option<&'static str> = Some("a space-separated list of strings"); | |
360 | pub const parse_uint: Option<&'static str> = Some("a number"); | |
361 | pub const parse_passes: Option<&'static str> = | |
362 | Some("a space-separated list of passes, or `all`"); | |
363 | pub const parse_opt_uint: Option<&'static str> = | |
364 | Some("a number"); | |
365 | } | |
366 | ||
367 | #[allow(dead_code)] | |
368 | mod $mod_set { | |
369 | use super::{$struct_name, Passes, SomePasses, AllPasses}; | |
370 | ||
371 | $( | |
372 | pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool { | |
373 | $parse(&mut cg.$opt, v) | |
374 | } | |
375 | )* | |
376 | ||
377 | fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool { | |
378 | match v { | |
379 | Some(..) => false, | |
380 | None => { *slot = true; true } | |
381 | } | |
382 | } | |
383 | ||
384 | fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool { | |
385 | match v { | |
c34b1796 AL |
386 | Some(s) => { |
387 | match s { | |
388 | "n" | "no" | "off" => { | |
389 | *slot = Some(false); | |
390 | } | |
391 | "y" | "yes" | "on" => { | |
392 | *slot = Some(true); | |
393 | } | |
394 | _ => { return false; } | |
395 | } | |
396 | ||
397 | true | |
398 | }, | |
1a4d82fc JJ |
399 | None => { *slot = Some(true); true } |
400 | } | |
401 | } | |
402 | ||
403 | fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool { | |
404 | match v { | |
405 | Some(s) => { *slot = Some(s.to_string()); true }, | |
406 | None => false, | |
407 | } | |
408 | } | |
409 | ||
410 | fn parse_string(slot: &mut String, v: Option<&str>) -> bool { | |
411 | match v { | |
412 | Some(s) => { *slot = s.to_string(); true }, | |
413 | None => false, | |
414 | } | |
415 | } | |
416 | ||
417 | fn parse_list(slot: &mut Vec<String>, v: Option<&str>) | |
418 | -> bool { | |
419 | match v { | |
420 | Some(s) => { | |
421 | for s in s.words() { | |
422 | slot.push(s.to_string()); | |
423 | } | |
424 | true | |
425 | }, | |
426 | None => false, | |
427 | } | |
428 | } | |
429 | ||
430 | fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>) | |
431 | -> bool { | |
432 | match v { | |
433 | Some(s) => { | |
434 | let v = s.words().map(|s| s.to_string()).collect(); | |
435 | *slot = Some(v); | |
436 | true | |
437 | }, | |
438 | None => false, | |
439 | } | |
440 | } | |
441 | ||
c34b1796 | 442 | fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool { |
85aaf69f | 443 | match v.and_then(|s| s.parse().ok()) { |
1a4d82fc JJ |
444 | Some(i) => { *slot = i; true }, |
445 | None => false | |
446 | } | |
447 | } | |
448 | ||
c34b1796 | 449 | fn parse_opt_uint(slot: &mut Option<usize>, v: Option<&str>) -> bool { |
1a4d82fc | 450 | match v { |
85aaf69f | 451 | Some(s) => { *slot = s.parse().ok(); slot.is_some() } |
1a4d82fc JJ |
452 | None => { *slot = None; true } |
453 | } | |
454 | } | |
455 | ||
456 | fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool { | |
457 | match v { | |
458 | Some("all") => { | |
459 | *slot = AllPasses; | |
460 | true | |
461 | } | |
462 | v => { | |
463 | let mut passes = vec!(); | |
464 | if parse_list(&mut passes, v) { | |
465 | *slot = SomePasses(passes); | |
466 | true | |
467 | } else { | |
468 | false | |
469 | } | |
470 | } | |
471 | } | |
472 | } | |
473 | } | |
474 | ) } | |
475 | ||
476 | options! {CodegenOptions, CodegenSetter, basic_codegen_options, | |
477 | build_codegen_options, "C", "codegen", | |
478 | CG_OPTIONS, cg_type_desc, cgsetters, | |
479 | ar: Option<String> = (None, parse_opt_string, | |
480 | "tool to assemble archives with"), | |
481 | linker: Option<String> = (None, parse_opt_string, | |
482 | "system linker to link outputs with"), | |
483 | link_args: Option<Vec<String>> = (None, parse_opt_list, | |
484 | "extra arguments to pass to the linker (space separated)"), | |
485 | lto: bool = (false, parse_bool, | |
486 | "perform LLVM link-time optimizations"), | |
487 | target_cpu: Option<String> = (None, parse_opt_string, | |
488 | "select target processor (llc -mcpu=help for details)"), | |
489 | target_feature: String = ("".to_string(), parse_string, | |
490 | "target specific attributes (llc -mattr=help for details)"), | |
491 | passes: Vec<String> = (Vec::new(), parse_list, | |
492 | "a list of extra LLVM passes to run (space separated)"), | |
493 | llvm_args: Vec<String> = (Vec::new(), parse_list, | |
494 | "a list of arguments to pass to llvm (space separated)"), | |
495 | save_temps: bool = (false, parse_bool, | |
496 | "save all temporary output files during compilation"), | |
497 | rpath: bool = (false, parse_bool, | |
498 | "set rpath values in libs/exes"), | |
499 | no_prepopulate_passes: bool = (false, parse_bool, | |
500 | "don't pre-populate the pass manager with a list of passes"), | |
501 | no_vectorize_loops: bool = (false, parse_bool, | |
502 | "don't run the loop vectorization optimization passes"), | |
503 | no_vectorize_slp: bool = (false, parse_bool, | |
504 | "don't run LLVM's SLP vectorization pass"), | |
505 | soft_float: bool = (false, parse_bool, | |
506 | "generate software floating point library calls"), | |
507 | prefer_dynamic: bool = (false, parse_bool, | |
508 | "prefer dynamic linking to static linking"), | |
509 | no_integrated_as: bool = (false, parse_bool, | |
510 | "use an external assembler rather than LLVM's integrated one"), | |
511 | no_redzone: Option<bool> = (None, parse_opt_bool, | |
512 | "disable the use of the redzone"), | |
513 | relocation_model: Option<String> = (None, parse_opt_string, | |
514 | "choose the relocation model to use (llc -relocation-model for details)"), | |
515 | code_model: Option<String> = (None, parse_opt_string, | |
516 | "choose the code model to use (llc -code-model for details)"), | |
517 | metadata: Vec<String> = (Vec::new(), parse_list, | |
518 | "metadata to mangle symbol names with"), | |
519 | extra_filename: String = ("".to_string(), parse_string, | |
520 | "extra data to put in each output filename"), | |
c34b1796 | 521 | codegen_units: usize = (1, parse_uint, |
1a4d82fc JJ |
522 | "divide crate into N units to optimize in parallel"), |
523 | remark: Passes = (SomePasses(Vec::new()), parse_passes, | |
524 | "print remarks for these optimization passes (space separated, or \"all\")"), | |
525 | no_stack_check: bool = (false, parse_bool, | |
526 | "disable checks for stack exhaustion (a memory-safety hazard!)"), | |
c34b1796 | 527 | debuginfo: Option<usize> = (None, parse_opt_uint, |
1a4d82fc JJ |
528 | "debug info emission level, 0 = no debug info, 1 = line tables only, \ |
529 | 2 = full debug info with variable and type information"), | |
c34b1796 | 530 | opt_level: Option<usize> = (None, parse_opt_uint, |
1a4d82fc | 531 | "Optimize with possible levels 0-3"), |
c34b1796 AL |
532 | debug_assertions: Option<bool> = (None, parse_opt_bool, |
533 | "explicitly enable the cfg(debug_assertions) directive"), | |
1a4d82fc JJ |
534 | } |
535 | ||
536 | ||
537 | options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, | |
538 | build_debugging_options, "Z", "debugging", | |
539 | DB_OPTIONS, db_type_desc, dbsetters, | |
540 | verbose: bool = (false, parse_bool, | |
541 | "in general, enable more debug printouts"), | |
542 | time_passes: bool = (false, parse_bool, | |
543 | "measure time of each rustc pass"), | |
544 | count_llvm_insns: bool = (false, parse_bool, | |
545 | "count where LLVM instrs originate"), | |
546 | time_llvm_passes: bool = (false, parse_bool, | |
547 | "measure time of each LLVM pass"), | |
548 | trans_stats: bool = (false, parse_bool, | |
549 | "gather trans statistics"), | |
550 | asm_comments: bool = (false, parse_bool, | |
551 | "generate comments into the assembly (may change behavior)"), | |
552 | no_verify: bool = (false, parse_bool, | |
553 | "skip LLVM verification"), | |
554 | borrowck_stats: bool = (false, parse_bool, | |
555 | "gather borrowck statistics"), | |
556 | no_landing_pads: bool = (false, parse_bool, | |
557 | "omit landing pads for unwinding"), | |
558 | debug_llvm: bool = (false, parse_bool, | |
559 | "enable debug output from LLVM"), | |
560 | count_type_sizes: bool = (false, parse_bool, | |
561 | "count the sizes of aggregate types"), | |
562 | meta_stats: bool = (false, parse_bool, | |
563 | "gather metadata statistics"), | |
564 | print_link_args: bool = (false, parse_bool, | |
565 | "Print the arguments passed to the linker"), | |
566 | gc: bool = (false, parse_bool, | |
567 | "Garbage collect shared data (experimental)"), | |
568 | print_llvm_passes: bool = (false, parse_bool, | |
569 | "Prints the llvm optimization passes being run"), | |
570 | ast_json: bool = (false, parse_bool, | |
571 | "Print the AST as JSON and halt"), | |
572 | ast_json_noexpand: bool = (false, parse_bool, | |
573 | "Print the pre-expansion AST as JSON and halt"), | |
574 | ls: bool = (false, parse_bool, | |
575 | "List the symbols defined by a library crate"), | |
576 | save_analysis: bool = (false, parse_bool, | |
577 | "Write syntax and type analysis information in addition to normal output"), | |
578 | print_move_fragments: bool = (false, parse_bool, | |
579 | "Print out move-fragment data for every fn"), | |
580 | flowgraph_print_loans: bool = (false, parse_bool, | |
581 | "Include loan analysis data in --pretty flowgraph output"), | |
582 | flowgraph_print_moves: bool = (false, parse_bool, | |
583 | "Include move analysis data in --pretty flowgraph output"), | |
584 | flowgraph_print_assigns: bool = (false, parse_bool, | |
585 | "Include assignment analysis data in --pretty flowgraph output"), | |
586 | flowgraph_print_all: bool = (false, parse_bool, | |
587 | "Include all dataflow analysis data in --pretty flowgraph output"), | |
588 | print_region_graph: bool = (false, parse_bool, | |
589 | "Prints region inference graph. \ | |
590 | Use with RUST_REGION_GRAPH=help for more info"), | |
591 | parse_only: bool = (false, parse_bool, | |
592 | "Parse only; do not compile, assemble, or link"), | |
593 | no_trans: bool = (false, parse_bool, | |
594 | "Run all passes except translation; no output"), | |
c34b1796 AL |
595 | treat_err_as_bug: bool = (false, parse_bool, |
596 | "Treat all errors that occur as bugs"), | |
1a4d82fc JJ |
597 | no_analysis: bool = (false, parse_bool, |
598 | "Parse and expand the source, but run no analysis"), | |
599 | extra_plugins: Vec<String> = (Vec::new(), parse_list, | |
600 | "load extra plugins"), | |
601 | unstable_options: bool = (false, parse_bool, | |
602 | "Adds unstable command line options to rustc interface"), | |
603 | print_enum_sizes: bool = (false, parse_bool, | |
604 | "Print the size of enums and their variants"), | |
c34b1796 AL |
605 | force_overflow_checks: Option<bool> = (None, parse_opt_bool, |
606 | "Force overflow checks on or off"), | |
607 | force_dropflag_checks: Option<bool> = (None, parse_opt_bool, | |
608 | "Force drop flag checks on or off"), | |
1a4d82fc JJ |
609 | } |
610 | ||
611 | pub fn default_lib_output() -> CrateType { | |
612 | CrateTypeRlib | |
613 | } | |
614 | ||
615 | pub fn default_configuration(sess: &Session) -> ast::CrateConfig { | |
616 | use syntax::parse::token::intern_and_get_ident as intern; | |
617 | ||
c34b1796 AL |
618 | let end = &sess.target.target.target_endian; |
619 | let arch = &sess.target.target.arch; | |
620 | let wordsz = &sess.target.target.target_pointer_width; | |
621 | let os = &sess.target.target.target_os; | |
1a4d82fc JJ |
622 | |
623 | let fam = match sess.target.target.options.is_like_windows { | |
624 | true => InternedString::new("windows"), | |
625 | false => InternedString::new("unix") | |
626 | }; | |
627 | ||
628 | let mk = attr::mk_name_value_item_str; | |
c34b1796 | 629 | let mut ret = vec![ // Target bindings. |
1a4d82fc JJ |
630 | attr::mk_word_item(fam.clone()), |
631 | mk(InternedString::new("target_os"), intern(os)), | |
632 | mk(InternedString::new("target_family"), fam), | |
633 | mk(InternedString::new("target_arch"), intern(arch)), | |
634 | mk(InternedString::new("target_endian"), intern(end)), | |
635 | mk(InternedString::new("target_pointer_width"), | |
636 | intern(wordsz)) | |
c34b1796 AL |
637 | ]; |
638 | if sess.opts.debug_assertions { | |
639 | ret.push(attr::mk_word_item(InternedString::new("debug_assertions"))); | |
640 | } | |
641 | return ret; | |
1a4d82fc JJ |
642 | } |
643 | ||
644 | pub fn append_configuration(cfg: &mut ast::CrateConfig, | |
645 | name: InternedString) { | |
646 | if !cfg.iter().any(|mi| mi.name() == name) { | |
647 | cfg.push(attr::mk_word_item(name)) | |
648 | } | |
649 | } | |
650 | ||
651 | pub fn build_configuration(sess: &Session) -> ast::CrateConfig { | |
652 | // Combine the configuration requested by the session (command line) with | |
653 | // some default and generated configuration items | |
654 | let default_cfg = default_configuration(sess); | |
655 | let mut user_cfg = sess.opts.cfg.clone(); | |
656 | // If the user wants a test runner, then add the test cfg | |
657 | if sess.opts.test { | |
658 | append_configuration(&mut user_cfg, InternedString::new("test")) | |
659 | } | |
660 | let mut v = user_cfg.into_iter().collect::<Vec<_>>(); | |
85aaf69f | 661 | v.push_all(&default_cfg[..]); |
1a4d82fc JJ |
662 | v |
663 | } | |
664 | ||
665 | pub fn build_target_config(opts: &Options, sp: &SpanHandler) -> Config { | |
c34b1796 | 666 | let target = match Target::search(&opts.target_triple) { |
1a4d82fc JJ |
667 | Ok(t) => t, |
668 | Err(e) => { | |
85aaf69f | 669 | sp.handler().fatal(&format!("Error loading target specification: {}", e)); |
1a4d82fc JJ |
670 | } |
671 | }; | |
672 | ||
c34b1796 | 673 | let (int_type, uint_type) = match &target.target_pointer_width[..] { |
1a4d82fc JJ |
674 | "32" => (ast::TyI32, ast::TyU32), |
675 | "64" => (ast::TyI64, ast::TyU64), | |
676 | w => sp.handler().fatal(&format!("target specification was invalid: unrecognized \ | |
c34b1796 | 677 | target-pointer-width {}", w)) |
1a4d82fc JJ |
678 | }; |
679 | ||
680 | Config { | |
681 | target: target, | |
682 | int_type: int_type, | |
683 | uint_type: uint_type, | |
684 | } | |
685 | } | |
686 | ||
687 | /// Returns the "short" subset of the stable rustc command line options. | |
688 | pub fn short_optgroups() -> Vec<getopts::OptGroup> { | |
689 | rustc_short_optgroups().into_iter() | |
690 | .filter(|g|g.is_stable()) | |
691 | .map(|g|g.opt_group) | |
692 | .collect() | |
693 | } | |
694 | ||
695 | /// Returns all of the stable rustc command line options. | |
696 | pub fn optgroups() -> Vec<getopts::OptGroup> { | |
697 | rustc_optgroups().into_iter() | |
698 | .filter(|g|g.is_stable()) | |
699 | .map(|g|g.opt_group) | |
700 | .collect() | |
701 | } | |
702 | ||
85aaf69f | 703 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] |
1a4d82fc JJ |
704 | pub enum OptionStability { Stable, Unstable } |
705 | ||
706 | #[derive(Clone, PartialEq, Eq)] | |
707 | pub struct RustcOptGroup { | |
708 | pub opt_group: getopts::OptGroup, | |
709 | pub stability: OptionStability, | |
710 | } | |
711 | ||
712 | impl RustcOptGroup { | |
713 | pub fn is_stable(&self) -> bool { | |
714 | self.stability == OptionStability::Stable | |
715 | } | |
716 | ||
717 | fn stable(g: getopts::OptGroup) -> RustcOptGroup { | |
718 | RustcOptGroup { opt_group: g, stability: OptionStability::Stable } | |
719 | } | |
720 | ||
721 | fn unstable(g: getopts::OptGroup) -> RustcOptGroup { | |
722 | RustcOptGroup { opt_group: g, stability: OptionStability::Unstable } | |
723 | } | |
724 | } | |
725 | ||
726 | // The `opt` local module holds wrappers around the `getopts` API that | |
727 | // adds extra rustc-specific metadata to each option; such metadata | |
728 | // is exposed by . The public | |
729 | // functions below ending with `_u` are the functions that return | |
730 | // *unstable* options, i.e. options that are only enabled when the | |
731 | // user also passes the `-Z unstable-options` debugging flag. | |
732 | mod opt { | |
733 | // The `fn opt_u` etc below are written so that we can use them | |
734 | // in the future; do not warn about them not being used right now. | |
735 | #![allow(dead_code)] | |
736 | ||
737 | use getopts; | |
738 | use super::RustcOptGroup; | |
739 | ||
c34b1796 AL |
740 | pub type R = RustcOptGroup; |
741 | pub type S<'a> = &'a str; | |
1a4d82fc JJ |
742 | |
743 | fn stable(g: getopts::OptGroup) -> R { RustcOptGroup::stable(g) } | |
744 | fn unstable(g: getopts::OptGroup) -> R { RustcOptGroup::unstable(g) } | |
745 | ||
746 | // FIXME (pnkfelix): We default to stable since the current set of | |
747 | // options is defacto stable. However, it would be good to revise the | |
748 | // code so that a stable option is the thing that takes extra effort | |
749 | // to encode. | |
750 | ||
751 | pub fn opt(a: S, b: S, c: S, d: S) -> R { stable(getopts::optopt(a, b, c, d)) } | |
752 | pub fn multi(a: S, b: S, c: S, d: S) -> R { stable(getopts::optmulti(a, b, c, d)) } | |
753 | pub fn flag(a: S, b: S, c: S) -> R { stable(getopts::optflag(a, b, c)) } | |
754 | pub fn flagopt(a: S, b: S, c: S, d: S) -> R { stable(getopts::optflagopt(a, b, c, d)) } | |
755 | ||
756 | pub fn opt_u(a: S, b: S, c: S, d: S) -> R { unstable(getopts::optopt(a, b, c, d)) } | |
757 | pub fn multi_u(a: S, b: S, c: S, d: S) -> R { unstable(getopts::optmulti(a, b, c, d)) } | |
758 | pub fn flag_u(a: S, b: S, c: S) -> R { unstable(getopts::optflag(a, b, c)) } | |
759 | pub fn flagopt_u(a: S, b: S, c: S, d: S) -> R { unstable(getopts::optflagopt(a, b, c, d)) } | |
760 | } | |
761 | ||
762 | /// Returns the "short" subset of the rustc command line options, | |
763 | /// including metadata for each option, such as whether the option is | |
764 | /// part of the stable long-term interface for rustc. | |
765 | pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> { | |
766 | vec![ | |
767 | opt::flag("h", "help", "Display this message"), | |
768 | opt::multi("", "cfg", "Configure the compilation environment", "SPEC"), | |
85aaf69f SL |
769 | opt::multi("L", "", "Add a directory to the library search path", |
770 | "[KIND=]PATH"), | |
1a4d82fc JJ |
771 | opt::multi("l", "", "Link the generated crate(s) to the specified native |
772 | library NAME. The optional KIND can be one of, | |
773 | static, dylib, or framework. If omitted, dylib is | |
774 | assumed.", "[KIND=]NAME"), | |
775 | opt::multi("", "crate-type", "Comma separated list of types of crates | |
776 | for the compiler to emit", | |
777 | "[bin|lib|rlib|dylib|staticlib]"), | |
778 | opt::opt("", "crate-name", "Specify the name of the crate being built", | |
779 | "NAME"), | |
780 | opt::multi("", "emit", "Comma separated list of types of output for \ | |
781 | the compiler to emit", | |
782 | "[asm|llvm-bc|llvm-ir|obj|link|dep-info]"), | |
783 | opt::multi("", "print", "Comma separated list of compiler information to \ | |
784 | print on stdout", | |
785 | "[crate-name|file-names|sysroot]"), | |
786 | opt::flag("g", "", "Equivalent to -C debuginfo=2"), | |
787 | opt::flag("O", "", "Equivalent to -C opt-level=2"), | |
788 | opt::opt("o", "", "Write output to <filename>", "FILENAME"), | |
789 | opt::opt("", "out-dir", "Write output to compiler-chosen filename \ | |
790 | in <dir>", "DIR"), | |
791 | opt::opt("", "explain", "Provide a detailed explanation of an error \ | |
792 | message", "OPT"), | |
793 | opt::flag("", "test", "Build a test harness"), | |
794 | opt::opt("", "target", "Target triple cpu-manufacturer-kernel[-os] \ | |
795 | to compile for (see chapter 3.4 of \ | |
796 | http://www.sourceware.org/autobook/ | |
797 | for details)", | |
798 | "TRIPLE"), | |
799 | opt::multi("W", "warn", "Set lint warnings", "OPT"), | |
800 | opt::multi("A", "allow", "Set lint allowed", "OPT"), | |
801 | opt::multi("D", "deny", "Set lint denied", "OPT"), | |
802 | opt::multi("F", "forbid", "Set lint forbidden", "OPT"), | |
803 | opt::multi("C", "codegen", "Set a codegen option", "OPT[=VALUE]"), | |
804 | opt::flag("V", "version", "Print version info and exit"), | |
805 | opt::flag("v", "verbose", "Use verbose output"), | |
806 | ] | |
807 | } | |
808 | ||
809 | /// Returns all rustc command line options, including metadata for | |
810 | /// each option, such as whether the option is part of the stable | |
811 | /// long-term interface for rustc. | |
812 | pub fn rustc_optgroups() -> Vec<RustcOptGroup> { | |
813 | let mut opts = rustc_short_optgroups(); | |
814 | opts.push_all(&[ | |
815 | opt::multi("", "extern", "Specify where an external rust library is \ | |
816 | located", | |
817 | "NAME=PATH"), | |
1a4d82fc JJ |
818 | opt::opt("", "sysroot", "Override the system root", "PATH"), |
819 | opt::multi("Z", "", "Set internal debugging options", "FLAG"), | |
820 | opt::opt("", "color", "Configure coloring of output: | |
821 | auto = colorize, if output goes to a tty (default); | |
822 | always = always colorize output; | |
823 | never = never colorize output", "auto|always|never"), | |
824 | ||
85aaf69f | 825 | opt::flagopt_u("", "pretty", |
1a4d82fc JJ |
826 | "Pretty-print the input instead of compiling; |
827 | valid types are: `normal` (un-annotated source), | |
828 | `expanded` (crates expanded), | |
829 | `typed` (crates expanded, with type annotations), or | |
830 | `expanded,identified` (fully parenthesized, AST nodes with IDs).", | |
831 | "TYPE"), | |
832 | opt::flagopt_u("", "xpretty", | |
833 | "Pretty-print the input instead of compiling, unstable variants; | |
834 | valid types are any of the types for `--pretty`, as well as: | |
835 | `flowgraph=<nodeid>` (graphviz formatted flowgraph for node), or | |
836 | `everybody_loops` (all function bodies replaced with `loop {}`).", | |
837 | "TYPE"), | |
838 | opt::opt_u("", "show-span", "Show spans for compiler debugging", "expr|pat|ty"), | |
1a4d82fc JJ |
839 | ]); |
840 | opts | |
841 | } | |
842 | ||
843 | // Convert strings provided as --cfg [cfgspec] into a crate_cfg | |
844 | pub fn parse_cfgspecs(cfgspecs: Vec<String> ) -> ast::CrateConfig { | |
845 | cfgspecs.into_iter().map(|s| { | |
846 | parse::parse_meta_from_source_str("cfgspec".to_string(), | |
847 | s.to_string(), | |
848 | Vec::new(), | |
849 | &parse::new_parse_sess()) | |
850 | }).collect::<ast::CrateConfig>() | |
851 | } | |
852 | ||
853 | pub fn build_session_options(matches: &getopts::Matches) -> Options { | |
1a4d82fc JJ |
854 | let unparsed_crate_types = matches.opt_strs("crate-type"); |
855 | let crate_types = parse_crate_types_from_list(unparsed_crate_types) | |
85aaf69f | 856 | .unwrap_or_else(|e| early_error(&e[..])); |
1a4d82fc JJ |
857 | |
858 | let mut lint_opts = vec!(); | |
859 | let mut describe_lints = false; | |
860 | ||
85aaf69f SL |
861 | for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] { |
862 | for lint_name in matches.opt_strs(level.as_str()) { | |
1a4d82fc JJ |
863 | if lint_name == "help" { |
864 | describe_lints = true; | |
865 | } else { | |
866 | lint_opts.push((lint_name.replace("-", "_"), level)); | |
867 | } | |
868 | } | |
869 | } | |
870 | ||
871 | let debugging_opts = build_debugging_options(matches); | |
872 | ||
85aaf69f SL |
873 | let parse_only = debugging_opts.parse_only; |
874 | let no_trans = debugging_opts.no_trans; | |
c34b1796 | 875 | let treat_err_as_bug = debugging_opts.treat_err_as_bug; |
85aaf69f | 876 | let no_analysis = debugging_opts.no_analysis; |
1a4d82fc JJ |
877 | |
878 | if debugging_opts.debug_llvm { | |
879 | unsafe { llvm::LLVMSetDebug(1); } | |
880 | } | |
881 | ||
882 | let mut output_types = Vec::new(); | |
883 | if !debugging_opts.parse_only && !no_trans { | |
884 | let unparsed_output_types = matches.opt_strs("emit"); | |
85aaf69f | 885 | for unparsed_output_type in &unparsed_output_types { |
1a4d82fc | 886 | for part in unparsed_output_type.split(',') { |
85aaf69f | 887 | let output_type = match part { |
1a4d82fc JJ |
888 | "asm" => OutputTypeAssembly, |
889 | "llvm-ir" => OutputTypeLlvmAssembly, | |
890 | "llvm-bc" => OutputTypeBitcode, | |
891 | "obj" => OutputTypeObject, | |
892 | "link" => OutputTypeExe, | |
893 | "dep-info" => OutputTypeDepInfo, | |
894 | _ => { | |
895 | early_error(&format!("unknown emission type: `{}`", | |
c34b1796 | 896 | part)) |
1a4d82fc JJ |
897 | } |
898 | }; | |
899 | output_types.push(output_type) | |
900 | } | |
901 | } | |
902 | }; | |
903 | output_types.sort(); | |
904 | output_types.dedup(); | |
9346a6ac | 905 | if output_types.is_empty() { |
1a4d82fc JJ |
906 | output_types.push(OutputTypeExe); |
907 | } | |
908 | ||
909 | let cg = build_codegen_options(matches); | |
910 | ||
c34b1796 | 911 | let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m)); |
1a4d82fc JJ |
912 | let target = matches.opt_str("target").unwrap_or( |
913 | host_triple().to_string()); | |
914 | let opt_level = { | |
915 | if matches.opt_present("O") { | |
1a4d82fc JJ |
916 | if cg.opt_level.is_some() { |
917 | early_error("-O and -C opt-level both provided"); | |
918 | } | |
919 | Default | |
1a4d82fc JJ |
920 | } else { |
921 | match cg.opt_level { | |
922 | None => No, | |
923 | Some(0) => No, | |
924 | Some(1) => Less, | |
925 | Some(2) => Default, | |
926 | Some(3) => Aggressive, | |
927 | Some(arg) => { | |
85aaf69f SL |
928 | early_error(&format!("optimization level needs to be \ |
929 | between 0-3 (instead was `{}`)", | |
930 | arg)); | |
1a4d82fc JJ |
931 | } |
932 | } | |
933 | } | |
934 | }; | |
c34b1796 | 935 | let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == No); |
1a4d82fc JJ |
936 | let gc = debugging_opts.gc; |
937 | let debuginfo = if matches.opt_present("g") { | |
1a4d82fc JJ |
938 | if cg.debuginfo.is_some() { |
939 | early_error("-g and -C debuginfo both provided"); | |
940 | } | |
941 | FullDebugInfo | |
1a4d82fc JJ |
942 | } else { |
943 | match cg.debuginfo { | |
944 | None | Some(0) => NoDebugInfo, | |
945 | Some(1) => LimitedDebugInfo, | |
946 | Some(2) => FullDebugInfo, | |
947 | Some(arg) => { | |
85aaf69f SL |
948 | early_error(&format!("debug info level needs to be between \ |
949 | 0-2 (instead was `{}`)", | |
950 | arg)); | |
1a4d82fc JJ |
951 | } |
952 | } | |
953 | }; | |
954 | ||
955 | let mut search_paths = SearchPaths::new(); | |
85aaf69f SL |
956 | for s in &matches.opt_strs("L") { |
957 | search_paths.add_path(&s[..]); | |
1a4d82fc JJ |
958 | } |
959 | ||
960 | let libs = matches.opt_strs("l").into_iter().map(|s| { | |
c34b1796 | 961 | let mut parts = s.splitn(2, '='); |
1a4d82fc JJ |
962 | let kind = parts.next().unwrap(); |
963 | let (name, kind) = match (parts.next(), kind) { | |
964 | (None, name) | | |
965 | (Some(name), "dylib") => (name, cstore::NativeUnknown), | |
966 | (Some(name), "framework") => (name, cstore::NativeFramework), | |
967 | (Some(name), "static") => (name, cstore::NativeStatic), | |
968 | (_, s) => { | |
969 | early_error(&format!("unknown library kind `{}`, expected \ | |
970 | one of dylib, framework, or static", | |
c34b1796 | 971 | s)); |
1a4d82fc JJ |
972 | } |
973 | }; | |
974 | (name.to_string(), kind) | |
975 | }).collect(); | |
976 | ||
977 | let cfg = parse_cfgspecs(matches.opt_strs("cfg")); | |
978 | let test = matches.opt_present("test"); | |
85aaf69f | 979 | let write_dependency_info = (output_types.contains(&OutputTypeDepInfo), None); |
1a4d82fc | 980 | |
85aaf69f SL |
981 | let prints = matches.opt_strs("print").into_iter().map(|s| { |
982 | match &*s { | |
1a4d82fc JJ |
983 | "crate-name" => PrintRequest::CrateName, |
984 | "file-names" => PrintRequest::FileNames, | |
985 | "sysroot" => PrintRequest::Sysroot, | |
986 | req => { | |
85aaf69f | 987 | early_error(&format!("unknown print request `{}`", req)) |
1a4d82fc JJ |
988 | } |
989 | } | |
990 | }).collect::<Vec<_>>(); | |
1a4d82fc JJ |
991 | |
992 | if !cg.remark.is_empty() && debuginfo == NoDebugInfo { | |
993 | early_warn("-C remark will not show source locations without \ | |
994 | --debuginfo"); | |
995 | } | |
996 | ||
85aaf69f | 997 | let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) { |
1a4d82fc JJ |
998 | Some("auto") => Auto, |
999 | Some("always") => Always, | |
1000 | Some("never") => Never, | |
1001 | ||
1002 | None => Auto, | |
1003 | ||
1004 | Some(arg) => { | |
1005 | early_error(&format!("argument for --color must be auto, always \ | |
1006 | or never (instead was `{}`)", | |
c34b1796 | 1007 | arg)) |
1a4d82fc JJ |
1008 | } |
1009 | }; | |
1010 | ||
1011 | let mut externs = HashMap::new(); | |
85aaf69f | 1012 | for arg in &matches.opt_strs("extern") { |
c34b1796 | 1013 | let mut parts = arg.splitn(2, '='); |
1a4d82fc JJ |
1014 | let name = match parts.next() { |
1015 | Some(s) => s, | |
1016 | None => early_error("--extern value must not be empty"), | |
1017 | }; | |
1018 | let location = match parts.next() { | |
1019 | Some(s) => s, | |
1020 | None => early_error("--extern value must be of the format `foo=bar`"), | |
1021 | }; | |
1022 | ||
c34b1796 | 1023 | externs.entry(name.to_string()).or_insert(vec![]).push(location.to_string()); |
1a4d82fc JJ |
1024 | } |
1025 | ||
1026 | let crate_name = matches.opt_str("crate-name"); | |
1027 | ||
1028 | Options { | |
1029 | crate_types: crate_types, | |
1030 | gc: gc, | |
1031 | optimize: opt_level, | |
1032 | debuginfo: debuginfo, | |
1033 | lint_opts: lint_opts, | |
1034 | describe_lints: describe_lints, | |
1035 | output_types: output_types, | |
1036 | search_paths: search_paths, | |
1037 | maybe_sysroot: sysroot_opt, | |
1038 | target_triple: target, | |
1039 | cfg: cfg, | |
1040 | test: test, | |
1041 | parse_only: parse_only, | |
1042 | no_trans: no_trans, | |
c34b1796 | 1043 | treat_err_as_bug: treat_err_as_bug, |
1a4d82fc JJ |
1044 | no_analysis: no_analysis, |
1045 | debugging_opts: debugging_opts, | |
1046 | write_dependency_info: write_dependency_info, | |
1047 | prints: prints, | |
1048 | cg: cg, | |
1049 | color: color, | |
1050 | show_span: None, | |
1051 | externs: externs, | |
1052 | crate_name: crate_name, | |
1053 | alt_std_name: None, | |
1054 | libs: libs, | |
85aaf69f | 1055 | unstable_features: get_unstable_features_setting(), |
c34b1796 | 1056 | debug_assertions: debug_assertions, |
85aaf69f SL |
1057 | } |
1058 | } | |
1059 | ||
1060 | pub fn get_unstable_features_setting() -> UnstableFeatures { | |
1061 | // Whether this is a feature-staged build, i.e. on the beta or stable channel | |
1062 | let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some(); | |
1063 | // The secret key needed to get through the rustc build itself by | |
1064 | // subverting the unstable features lints | |
1065 | let bootstrap_secret_key = option_env!("CFG_BOOTSTRAP_KEY"); | |
1066 | // The matching key to the above, only known by the build system | |
1067 | let bootstrap_provided_key = env::var("RUSTC_BOOTSTRAP_KEY").ok(); | |
1068 | match (disable_unstable_features, bootstrap_secret_key, bootstrap_provided_key) { | |
1069 | (_, Some(ref s), Some(ref p)) if s == p => UnstableFeatures::Cheat, | |
1070 | (true, _, _) => UnstableFeatures::Disallow, | |
1071 | (false, _, _) => UnstableFeatures::Default | |
1a4d82fc JJ |
1072 | } |
1073 | } | |
1074 | ||
1075 | pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> { | |
1076 | ||
1077 | let mut crate_types: Vec<CrateType> = Vec::new(); | |
85aaf69f | 1078 | for unparsed_crate_type in &list_list { |
1a4d82fc JJ |
1079 | for part in unparsed_crate_type.split(',') { |
1080 | let new_part = match part { | |
1081 | "lib" => default_lib_output(), | |
1082 | "rlib" => CrateTypeRlib, | |
1083 | "staticlib" => CrateTypeStaticlib, | |
1084 | "dylib" => CrateTypeDylib, | |
1085 | "bin" => CrateTypeExecutable, | |
1086 | _ => { | |
1087 | return Err(format!("unknown crate type: `{}`", | |
1088 | part)); | |
1089 | } | |
1090 | }; | |
85aaf69f SL |
1091 | if !crate_types.contains(&new_part) { |
1092 | crate_types.push(new_part) | |
1093 | } | |
1a4d82fc JJ |
1094 | } |
1095 | } | |
1096 | ||
1097 | return Ok(crate_types); | |
1098 | } | |
1099 | ||
85aaf69f | 1100 | impl fmt::Display for CrateType { |
1a4d82fc JJ |
1101 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
1102 | match *self { | |
1103 | CrateTypeExecutable => "bin".fmt(f), | |
1104 | CrateTypeDylib => "dylib".fmt(f), | |
1105 | CrateTypeRlib => "rlib".fmt(f), | |
1106 | CrateTypeStaticlib => "staticlib".fmt(f) | |
1107 | } | |
1108 | } | |
1109 | } | |
1110 | ||
1111 | #[cfg(test)] | |
1112 | mod test { | |
1113 | ||
1114 | use session::config::{build_configuration, optgroups, build_session_options}; | |
1115 | use session::build_session; | |
1116 | ||
1117 | use getopts::getopts; | |
1118 | use syntax::attr; | |
1119 | use syntax::attr::AttrMetaMethods; | |
1120 | use syntax::diagnostics; | |
1121 | ||
1122 | // When the user supplies --test we should implicitly supply --cfg test | |
1123 | #[test] | |
1124 | fn test_switch_implies_cfg_test() { | |
1125 | let matches = | |
c34b1796 | 1126 | &match getopts(&["--test".to_string()], &optgroups()) { |
1a4d82fc JJ |
1127 | Ok(m) => m, |
1128 | Err(f) => panic!("test_switch_implies_cfg_test: {}", f) | |
1129 | }; | |
1130 | let registry = diagnostics::registry::Registry::new(&[]); | |
1131 | let sessopts = build_session_options(matches); | |
1132 | let sess = build_session(sessopts, None, registry); | |
1133 | let cfg = build_configuration(&sess); | |
85aaf69f | 1134 | assert!((attr::contains_name(&cfg[..], "test"))); |
1a4d82fc JJ |
1135 | } |
1136 | ||
1137 | // When the user supplies --test and --cfg test, don't implicitly add | |
1138 | // another --cfg test | |
1139 | #[test] | |
1140 | fn test_switch_implies_cfg_test_unless_cfg_test() { | |
1141 | let matches = | |
1142 | &match getopts(&["--test".to_string(), "--cfg=test".to_string()], | |
c34b1796 | 1143 | &optgroups()) { |
1a4d82fc JJ |
1144 | Ok(m) => m, |
1145 | Err(f) => { | |
1146 | panic!("test_switch_implies_cfg_test_unless_cfg_test: {}", f) | |
1147 | } | |
1148 | }; | |
1149 | let registry = diagnostics::registry::Registry::new(&[]); | |
1150 | let sessopts = build_session_options(matches); | |
1151 | let sess = build_session(sessopts, None, registry); | |
1152 | let cfg = build_configuration(&sess); | |
1153 | let mut test_items = cfg.iter().filter(|m| m.name() == "test"); | |
1154 | assert!(test_items.next().is_some()); | |
1155 | assert!(test_items.next().is_none()); | |
1156 | } | |
1157 | ||
1158 | #[test] | |
1159 | fn test_can_print_warnings() { | |
1160 | { | |
1161 | let matches = getopts(&[ | |
1162 | "-Awarnings".to_string() | |
c34b1796 | 1163 | ], &optgroups()).unwrap(); |
1a4d82fc JJ |
1164 | let registry = diagnostics::registry::Registry::new(&[]); |
1165 | let sessopts = build_session_options(&matches); | |
1166 | let sess = build_session(sessopts, None, registry); | |
1167 | assert!(!sess.can_print_warnings); | |
1168 | } | |
1169 | ||
1170 | { | |
1171 | let matches = getopts(&[ | |
1172 | "-Awarnings".to_string(), | |
1173 | "-Dwarnings".to_string() | |
c34b1796 | 1174 | ], &optgroups()).unwrap(); |
1a4d82fc JJ |
1175 | let registry = diagnostics::registry::Registry::new(&[]); |
1176 | let sessopts = build_session_options(&matches); | |
1177 | let sess = build_session(sessopts, None, registry); | |
1178 | assert!(sess.can_print_warnings); | |
1179 | } | |
1180 | ||
1181 | { | |
1182 | let matches = getopts(&[ | |
1183 | "-Adead_code".to_string() | |
c34b1796 | 1184 | ], &optgroups()).unwrap(); |
1a4d82fc JJ |
1185 | let registry = diagnostics::registry::Registry::new(&[]); |
1186 | let sessopts = build_session_options(&matches); | |
1187 | let sess = build_session(sessopts, None, registry); | |
1188 | assert!(sess.can_print_warnings); | |
1189 | } | |
1190 | } | |
1191 | } |