]> git.proxmox.com Git - rustc.git/blame - src/librustc/session/config.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / librustc / session / config.rs
CommitLineData
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
14pub use self::EntryFnType::*;
15pub use self::CrateType::*;
16pub use self::Passes::*;
1a4d82fc
JJ
17pub use self::DebugInfoLevel::*;
18
19use session::{early_error, early_warn, Session};
20use session::search_paths::SearchPaths;
21
22use rustc_back::target::Target;
23use lint;
92a42be0 24use middle::cstore;
1a4d82fc 25
b039eaaf 26use syntax::ast::{self, IntTy, UintTy};
1a4d82fc
JJ
27use syntax::attr;
28use syntax::attr::AttrMetaMethods;
9cc50fc6 29use syntax::errors::{ColorConfig, Handler};
1a4d82fc 30use syntax::parse;
7453a54e 31use syntax::parse::lexer::Reader;
1a4d82fc 32use syntax::parse::token::InternedString;
62682a34 33use syntax::feature_gate::UnstableFeatures;
1a4d82fc 34
85aaf69f 35use getopts;
1a4d82fc 36use std::collections::HashMap;
85aaf69f 37use std::env;
1a4d82fc 38use std::fmt;
c34b1796 39use std::path::PathBuf;
1a4d82fc 40
1a4d82fc
JJ
41pub struct Config {
42 pub target: Target,
43 pub int_type: IntTy,
44 pub uint_type: UintTy,
45}
46
47#[derive(Clone, Copy, PartialEq)]
48pub enum OptLevel {
49 No, // -O0
50 Less, // -O1
51 Default, // -O2
52 Aggressive // -O3
53}
54
55#[derive(Clone, Copy, PartialEq)]
56pub enum DebugInfoLevel {
57 NoDebugInfo,
58 LimitedDebugInfo,
59 FullDebugInfo,
60}
61
b039eaaf 62#[derive(Clone, Copy, PartialEq, Eq, Hash)]
1a4d82fc 63pub enum OutputType {
b039eaaf
SL
64 Bitcode,
65 Assembly,
66 LlvmAssembly,
67 Object,
68 Exe,
69 DepInfo,
1a4d82fc
JJ
70}
71
9cc50fc6
SL
72#[derive(Clone, Copy, Debug, PartialEq, Eq)]
73pub enum ErrorOutputType {
74 HumanReadable(ColorConfig),
75 Json,
76}
77
78impl Default for ErrorOutputType {
79 fn default() -> ErrorOutputType {
80 ErrorOutputType::HumanReadable(ColorConfig::Auto)
81 }
82}
83
92a42be0
SL
84impl OutputType {
85 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
86 match *self {
87 OutputType::Exe |
88 OutputType::DepInfo => true,
89 OutputType::Bitcode |
90 OutputType::Assembly |
91 OutputType::LlvmAssembly |
92 OutputType::Object => false,
93 }
94 }
95
96 fn shorthand(&self) -> &'static str {
97 match *self {
98 OutputType::Bitcode => "llvm-bc",
99 OutputType::Assembly => "asm",
100 OutputType::LlvmAssembly => "llvm-ir",
101 OutputType::Object => "obj",
102 OutputType::Exe => "link",
103 OutputType::DepInfo => "dep-info",
104 }
105 }
106}
107
1a4d82fc
JJ
108#[derive(Clone)]
109pub struct Options {
110 // The crate config requested for the session, which may be combined
111 // with additional crate configurations during the compile process
112 pub crate_types: Vec<CrateType>,
113
114 pub gc: bool,
115 pub optimize: OptLevel,
c34b1796 116 pub debug_assertions: bool,
1a4d82fc
JJ
117 pub debuginfo: DebugInfoLevel,
118 pub lint_opts: Vec<(String, lint::Level)>,
c1a9b12d 119 pub lint_cap: Option<lint::Level>,
1a4d82fc 120 pub describe_lints: bool,
b039eaaf 121 pub output_types: HashMap<OutputType, Option<PathBuf>>,
1a4d82fc
JJ
122 // This was mutable for rustpkg, which updates search paths based on the
123 // parsed code. It remains mutable in case its replacements wants to use
124 // this.
125 pub search_paths: SearchPaths,
126 pub libs: Vec<(String, cstore::NativeLibraryKind)>,
c34b1796 127 pub maybe_sysroot: Option<PathBuf>,
1a4d82fc
JJ
128 pub target_triple: String,
129 // User-specified cfg meta items. The compiler itself will add additional
130 // items to the crate config, and during parsing the entire crate config
131 // will be added to the crate AST node. This should not be used for
132 // anything except building the full crate config prior to parsing.
133 pub cfg: ast::CrateConfig,
134 pub test: bool,
135 pub parse_only: bool,
136 pub no_trans: bool,
9cc50fc6 137 pub error_format: ErrorOutputType,
c34b1796 138 pub treat_err_as_bug: bool,
7453a54e
SL
139 pub continue_parse_after_error: bool,
140 pub mir_opt_level: usize,
141
54a0048b
SL
142 /// if Some, enable incremental compilation, using the given
143 /// directory to store intermediate results
144 pub incremental: Option<PathBuf>,
7453a54e 145
1a4d82fc
JJ
146 pub no_analysis: bool,
147 pub debugging_opts: DebuggingOptions,
1a4d82fc
JJ
148 pub prints: Vec<PrintRequest>,
149 pub cg: CodegenOptions,
1a4d82fc
JJ
150 pub externs: HashMap<String, Vec<String>>,
151 pub crate_name: Option<String>,
152 /// An optional name to use as the crate for std during std injection,
153 /// written `extern crate std = "name"`. Default to "std". Used by
154 /// out-of-tree drivers.
155 pub alt_std_name: Option<String>,
156 /// Indicates how the compiler should treat unstable features
157 pub unstable_features: UnstableFeatures
158}
159
1a4d82fc 160#[derive(Clone, PartialEq, Eq)]
1a4d82fc
JJ
161pub enum PrintRequest {
162 FileNames,
163 Sysroot,
164 CrateName,
7453a54e
SL
165 Cfg,
166 TargetList,
1a4d82fc
JJ
167}
168
169pub enum Input {
170 /// Load source from file
c34b1796 171 File(PathBuf),
54a0048b
SL
172 Str {
173 /// String that is shown in place of a filename
174 name: String,
175 /// Anonymous source string
176 input: String,
177 },
1a4d82fc
JJ
178}
179
180impl Input {
181 pub fn filestem(&self) -> String {
182 match *self {
c34b1796
AL
183 Input::File(ref ifile) => ifile.file_stem().unwrap()
184 .to_str().unwrap().to_string(),
54a0048b 185 Input::Str { .. } => "rust_out".to_string(),
1a4d82fc
JJ
186 }
187 }
188}
189
190#[derive(Clone)]
191pub struct OutputFilenames {
c34b1796 192 pub out_directory: PathBuf,
1a4d82fc 193 pub out_filestem: String,
c34b1796 194 pub single_output_file: Option<PathBuf>,
1a4d82fc 195 pub extra: String,
b039eaaf 196 pub outputs: HashMap<OutputType, Option<PathBuf>>,
1a4d82fc
JJ
197}
198
199impl OutputFilenames {
c34b1796 200 pub fn path(&self, flavor: OutputType) -> PathBuf {
b039eaaf
SL
201 self.outputs.get(&flavor).and_then(|p| p.to_owned())
202 .or_else(|| self.single_output_file.clone())
203 .unwrap_or_else(|| self.temp_path(flavor))
1a4d82fc
JJ
204 }
205
c34b1796
AL
206 pub fn temp_path(&self, flavor: OutputType) -> PathBuf {
207 let base = self.out_directory.join(&self.filestem());
1a4d82fc 208 match flavor {
b039eaaf
SL
209 OutputType::Bitcode => base.with_extension("bc"),
210 OutputType::Assembly => base.with_extension("s"),
211 OutputType::LlvmAssembly => base.with_extension("ll"),
212 OutputType::Object => base.with_extension("o"),
213 OutputType::DepInfo => base.with_extension("d"),
214 OutputType::Exe => base,
1a4d82fc
JJ
215 }
216 }
217
c34b1796
AL
218 pub fn with_extension(&self, extension: &str) -> PathBuf {
219 self.out_directory.join(&self.filestem()).with_extension(extension)
1a4d82fc
JJ
220 }
221
222 pub fn filestem(&self) -> String {
223 format!("{}{}", self.out_filestem, self.extra)
224 }
225}
226
227pub fn host_triple() -> &'static str {
228 // Get the host triple out of the build environment. This ensures that our
229 // idea of the host triple is the same as for the set of libraries we've
230 // actually built. We can't just take LLVM's host triple because they
231 // normalize all ix86 architectures to i386.
232 //
233 // Instead of grabbing the host triple (for the current host), we grab (at
234 // compile time) the target triple that this rustc is built with and
235 // calling that (at runtime) the host triple.
236 (option_env!("CFG_COMPILER_HOST_TRIPLE")).
237 expect("CFG_COMPILER_HOST_TRIPLE")
238}
239
240/// Some reasonable defaults
241pub fn basic_options() -> Options {
242 Options {
243 crate_types: Vec::new(),
244 gc: false,
9cc50fc6 245 optimize: OptLevel::No,
1a4d82fc
JJ
246 debuginfo: NoDebugInfo,
247 lint_opts: Vec::new(),
c1a9b12d 248 lint_cap: None,
1a4d82fc 249 describe_lints: false,
b039eaaf 250 output_types: HashMap::new(),
1a4d82fc
JJ
251 search_paths: SearchPaths::new(),
252 maybe_sysroot: None,
253 target_triple: host_triple().to_string(),
254 cfg: Vec::new(),
255 test: false,
256 parse_only: false,
257 no_trans: false,
c34b1796 258 treat_err_as_bug: false,
7453a54e
SL
259 continue_parse_after_error: false,
260 mir_opt_level: 1,
54a0048b 261 incremental: None,
1a4d82fc
JJ
262 no_analysis: false,
263 debugging_opts: basic_debugging_options(),
1a4d82fc
JJ
264 prints: Vec::new(),
265 cg: basic_codegen_options(),
9cc50fc6 266 error_format: ErrorOutputType::default(),
1a4d82fc
JJ
267 externs: HashMap::new(),
268 crate_name: None,
269 alt_std_name: None,
270 libs: Vec::new(),
c34b1796
AL
271 unstable_features: UnstableFeatures::Disallow,
272 debug_assertions: true,
1a4d82fc
JJ
273 }
274}
275
54a0048b
SL
276impl Options {
277 /// True if there is a reason to build the dep graph.
278 pub fn build_dep_graph(&self) -> bool {
279 self.incremental.is_some() ||
280 self.debugging_opts.dump_dep_graph ||
281 self.debugging_opts.query_dep_graph
282 }
283}
284
1a4d82fc
JJ
285// The type of entry function, so
286// users can have their own entry
287// functions that don't start a
288// scheduler
c34b1796 289#[derive(Copy, Clone, PartialEq)]
1a4d82fc
JJ
290pub enum EntryFnType {
291 EntryMain,
292 EntryStart,
293 EntryNone,
294}
295
85aaf69f 296#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)]
1a4d82fc
JJ
297pub enum CrateType {
298 CrateTypeExecutable,
299 CrateTypeDylib,
300 CrateTypeRlib,
301 CrateTypeStaticlib,
302}
303
1a4d82fc
JJ
304#[derive(Clone)]
305pub enum Passes {
306 SomePasses(Vec<String>),
307 AllPasses,
308}
309
310impl Passes {
311 pub fn is_empty(&self) -> bool {
312 match *self {
313 SomePasses(ref v) => v.is_empty(),
314 AllPasses => false,
315 }
316 }
317}
318
319/// Declare a macro that will define all CodegenOptions/DebuggingOptions fields and parsers all
320/// at once. The goal of this macro is to define an interface that can be
321/// programmatically used by the option parser in order to initialize the struct
322/// without hardcoding field names all over the place.
323///
324/// The goal is to invoke this macro once with the correct fields, and then this
325/// macro generates all necessary code. The main gotcha of this macro is the
326/// cgsetters module which is a bunch of generated code to parse an option into
327/// its respective field in the struct. There are a few hand-written parsers for
328/// parsing specific types of values in this module.
329macro_rules! options {
330 ($struct_name:ident, $setter_name:ident, $defaultfn:ident,
331 $buildfn:ident, $prefix:expr, $outputname:expr,
332 $stat:ident, $mod_desc:ident, $mod_set:ident,
333 $($opt:ident : $t:ty = ($init:expr, $parse:ident, $desc:expr)),* ,) =>
334(
335 #[derive(Clone)]
1a4d82fc
JJ
336 pub struct $struct_name { $(pub $opt: $t),* }
337
338 pub fn $defaultfn() -> $struct_name {
339 $struct_name { $($opt: $init),* }
340 }
341
9cc50fc6 342 pub fn $buildfn(matches: &getopts::Matches, error_format: ErrorOutputType) -> $struct_name
1a4d82fc
JJ
343 {
344 let mut op = $defaultfn();
85aaf69f 345 for option in matches.opt_strs($prefix) {
c34b1796 346 let mut iter = option.splitn(2, '=');
1a4d82fc
JJ
347 let key = iter.next().unwrap();
348 let value = iter.next();
349 let option_to_lookup = key.replace("-", "_");
350 let mut found = false;
85aaf69f 351 for &(candidate, setter, opt_type_desc, _) in $stat {
1a4d82fc
JJ
352 if option_to_lookup != candidate { continue }
353 if !setter(&mut op, value) {
354 match (value, opt_type_desc) {
355 (Some(..), None) => {
9cc50fc6
SL
356 early_error(error_format, &format!("{} option `{}` takes no \
357 value", $outputname, key))
1a4d82fc
JJ
358 }
359 (None, Some(type_desc)) => {
9cc50fc6
SL
360 early_error(error_format, &format!("{0} option `{1}` requires \
361 {2} ({3} {1}=<value>)",
362 $outputname, key,
363 type_desc, $prefix))
1a4d82fc
JJ
364 }
365 (Some(value), Some(type_desc)) => {
9cc50fc6
SL
366 early_error(error_format, &format!("incorrect value `{}` for {} \
367 option `{}` - {} was expected",
368 value, $outputname,
369 key, type_desc))
1a4d82fc 370 }
54a0048b 371 (None, None) => bug!()
1a4d82fc
JJ
372 }
373 }
374 found = true;
375 break;
376 }
377 if !found {
9cc50fc6
SL
378 early_error(error_format, &format!("unknown {} option: `{}`",
379 $outputname, key));
1a4d82fc
JJ
380 }
381 }
382 return op;
383 }
384
385 pub type $setter_name = fn(&mut $struct_name, v: Option<&str>) -> bool;
386 pub const $stat: &'static [(&'static str, $setter_name,
387 Option<&'static str>, &'static str)] =
388 &[ $( (stringify!($opt), $mod_set::$opt, $mod_desc::$parse, $desc) ),* ];
389
390 #[allow(non_upper_case_globals, dead_code)]
391 mod $mod_desc {
392 pub const parse_bool: Option<&'static str> = None;
c34b1796
AL
393 pub const parse_opt_bool: Option<&'static str> =
394 Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
1a4d82fc
JJ
395 pub const parse_string: Option<&'static str> = Some("a string");
396 pub const parse_opt_string: Option<&'static str> = Some("a string");
397 pub const parse_list: Option<&'static str> = Some("a space-separated list of strings");
398 pub const parse_opt_list: Option<&'static str> = Some("a space-separated list of strings");
399 pub const parse_uint: Option<&'static str> = Some("a number");
400 pub const parse_passes: Option<&'static str> =
401 Some("a space-separated list of passes, or `all`");
402 pub const parse_opt_uint: Option<&'static str> =
403 Some("a number");
404 }
405
406 #[allow(dead_code)]
407 mod $mod_set {
408 use super::{$struct_name, Passes, SomePasses, AllPasses};
409
410 $(
411 pub fn $opt(cg: &mut $struct_name, v: Option<&str>) -> bool {
412 $parse(&mut cg.$opt, v)
413 }
414 )*
415
416 fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
417 match v {
418 Some(..) => false,
419 None => { *slot = true; true }
420 }
421 }
422
423 fn parse_opt_bool(slot: &mut Option<bool>, v: Option<&str>) -> bool {
424 match v {
c34b1796
AL
425 Some(s) => {
426 match s {
427 "n" | "no" | "off" => {
428 *slot = Some(false);
429 }
430 "y" | "yes" | "on" => {
431 *slot = Some(true);
432 }
433 _ => { return false; }
434 }
435
436 true
437 },
1a4d82fc
JJ
438 None => { *slot = Some(true); true }
439 }
440 }
441
442 fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
443 match v {
444 Some(s) => { *slot = Some(s.to_string()); true },
445 None => false,
446 }
447 }
448
449 fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
450 match v {
451 Some(s) => { *slot = s.to_string(); true },
452 None => false,
453 }
454 }
455
456 fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
457 -> bool {
458 match v {
459 Some(s) => {
d9579d0f 460 for s in s.split_whitespace() {
1a4d82fc
JJ
461 slot.push(s.to_string());
462 }
463 true
464 },
465 None => false,
466 }
467 }
468
469 fn parse_opt_list(slot: &mut Option<Vec<String>>, v: Option<&str>)
470 -> bool {
471 match v {
472 Some(s) => {
d9579d0f 473 let v = s.split_whitespace().map(|s| s.to_string()).collect();
1a4d82fc
JJ
474 *slot = Some(v);
475 true
476 },
477 None => false,
478 }
479 }
480
c34b1796 481 fn parse_uint(slot: &mut usize, v: Option<&str>) -> bool {
85aaf69f 482 match v.and_then(|s| s.parse().ok()) {
1a4d82fc
JJ
483 Some(i) => { *slot = i; true },
484 None => false
485 }
486 }
487
c34b1796 488 fn parse_opt_uint(slot: &mut Option<usize>, v: Option<&str>) -> bool {
1a4d82fc 489 match v {
85aaf69f 490 Some(s) => { *slot = s.parse().ok(); slot.is_some() }
1a4d82fc
JJ
491 None => { *slot = None; true }
492 }
493 }
494
495 fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
496 match v {
497 Some("all") => {
498 *slot = AllPasses;
499 true
500 }
501 v => {
502 let mut passes = vec!();
503 if parse_list(&mut passes, v) {
504 *slot = SomePasses(passes);
505 true
506 } else {
507 false
508 }
509 }
510 }
511 }
512 }
513) }
514
515options! {CodegenOptions, CodegenSetter, basic_codegen_options,
516 build_codegen_options, "C", "codegen",
517 CG_OPTIONS, cg_type_desc, cgsetters,
518 ar: Option<String> = (None, parse_opt_string,
519 "tool to assemble archives with"),
520 linker: Option<String> = (None, parse_opt_string,
521 "system linker to link outputs with"),
522 link_args: Option<Vec<String>> = (None, parse_opt_list,
523 "extra arguments to pass to the linker (space separated)"),
7453a54e
SL
524 link_dead_code: bool = (false, parse_bool,
525 "don't let linker strip dead code (turning it on can be used for code coverage)"),
1a4d82fc
JJ
526 lto: bool = (false, parse_bool,
527 "perform LLVM link-time optimizations"),
528 target_cpu: Option<String> = (None, parse_opt_string,
529 "select target processor (llc -mcpu=help for details)"),
530 target_feature: String = ("".to_string(), parse_string,
531 "target specific attributes (llc -mattr=help for details)"),
532 passes: Vec<String> = (Vec::new(), parse_list,
533 "a list of extra LLVM passes to run (space separated)"),
534 llvm_args: Vec<String> = (Vec::new(), parse_list,
535 "a list of arguments to pass to llvm (space separated)"),
536 save_temps: bool = (false, parse_bool,
537 "save all temporary output files during compilation"),
538 rpath: bool = (false, parse_bool,
539 "set rpath values in libs/exes"),
540 no_prepopulate_passes: bool = (false, parse_bool,
541 "don't pre-populate the pass manager with a list of passes"),
542 no_vectorize_loops: bool = (false, parse_bool,
543 "don't run the loop vectorization optimization passes"),
544 no_vectorize_slp: bool = (false, parse_bool,
545 "don't run LLVM's SLP vectorization pass"),
546 soft_float: bool = (false, parse_bool,
547 "generate software floating point library calls"),
548 prefer_dynamic: bool = (false, parse_bool,
549 "prefer dynamic linking to static linking"),
550 no_integrated_as: bool = (false, parse_bool,
551 "use an external assembler rather than LLVM's integrated one"),
552 no_redzone: Option<bool> = (None, parse_opt_bool,
553 "disable the use of the redzone"),
554 relocation_model: Option<String> = (None, parse_opt_string,
555 "choose the relocation model to use (llc -relocation-model for details)"),
556 code_model: Option<String> = (None, parse_opt_string,
557 "choose the code model to use (llc -code-model for details)"),
558 metadata: Vec<String> = (Vec::new(), parse_list,
559 "metadata to mangle symbol names with"),
560 extra_filename: String = ("".to_string(), parse_string,
561 "extra data to put in each output filename"),
c34b1796 562 codegen_units: usize = (1, parse_uint,
1a4d82fc
JJ
563 "divide crate into N units to optimize in parallel"),
564 remark: Passes = (SomePasses(Vec::new()), parse_passes,
565 "print remarks for these optimization passes (space separated, or \"all\")"),
566 no_stack_check: bool = (false, parse_bool,
567 "disable checks for stack exhaustion (a memory-safety hazard!)"),
c34b1796 568 debuginfo: Option<usize> = (None, parse_opt_uint,
1a4d82fc
JJ
569 "debug info emission level, 0 = no debug info, 1 = line tables only, \
570 2 = full debug info with variable and type information"),
c34b1796 571 opt_level: Option<usize> = (None, parse_opt_uint,
92a42be0 572 "optimize with possible levels 0-3"),
c34b1796
AL
573 debug_assertions: Option<bool> = (None, parse_opt_bool,
574 "explicitly enable the cfg(debug_assertions) directive"),
92a42be0
SL
575 inline_threshold: Option<usize> = (None, parse_opt_uint,
576 "set the inlining threshold for"),
1a4d82fc
JJ
577}
578
579
580options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
581 build_debugging_options, "Z", "debugging",
582 DB_OPTIONS, db_type_desc, dbsetters,
583 verbose: bool = (false, parse_bool,
584 "in general, enable more debug printouts"),
585 time_passes: bool = (false, parse_bool,
586 "measure time of each rustc pass"),
587 count_llvm_insns: bool = (false, parse_bool,
588 "count where LLVM instrs originate"),
589 time_llvm_passes: bool = (false, parse_bool,
590 "measure time of each LLVM pass"),
92a42be0
SL
591 input_stats: bool = (false, parse_bool,
592 "gather statistics about the input"),
1a4d82fc
JJ
593 trans_stats: bool = (false, parse_bool,
594 "gather trans statistics"),
595 asm_comments: bool = (false, parse_bool,
596 "generate comments into the assembly (may change behavior)"),
597 no_verify: bool = (false, parse_bool,
598 "skip LLVM verification"),
599 borrowck_stats: bool = (false, parse_bool,
600 "gather borrowck statistics"),
601 no_landing_pads: bool = (false, parse_bool,
602 "omit landing pads for unwinding"),
603 debug_llvm: bool = (false, parse_bool,
604 "enable debug output from LLVM"),
605 count_type_sizes: bool = (false, parse_bool,
606 "count the sizes of aggregate types"),
607 meta_stats: bool = (false, parse_bool,
608 "gather metadata statistics"),
609 print_link_args: bool = (false, parse_bool,
92a42be0 610 "print the arguments passed to the linker"),
1a4d82fc 611 gc: bool = (false, parse_bool,
92a42be0 612 "garbage collect shared data (experimental)"),
1a4d82fc 613 print_llvm_passes: bool = (false, parse_bool,
92a42be0 614 "prints the llvm optimization passes being run"),
1a4d82fc 615 ast_json: bool = (false, parse_bool,
92a42be0 616 "print the AST as JSON and halt"),
1a4d82fc 617 ast_json_noexpand: bool = (false, parse_bool,
92a42be0 618 "print the pre-expansion AST as JSON and halt"),
1a4d82fc 619 ls: bool = (false, parse_bool,
92a42be0 620 "list the symbols defined by a library crate"),
1a4d82fc 621 save_analysis: bool = (false, parse_bool,
92a42be0 622 "write syntax and type analysis information in addition to normal output"),
1a4d82fc 623 print_move_fragments: bool = (false, parse_bool,
92a42be0 624 "print out move-fragment data for every fn"),
1a4d82fc 625 flowgraph_print_loans: bool = (false, parse_bool,
92a42be0 626 "include loan analysis data in --unpretty flowgraph output"),
1a4d82fc 627 flowgraph_print_moves: bool = (false, parse_bool,
92a42be0 628 "include move analysis data in --unpretty flowgraph output"),
1a4d82fc 629 flowgraph_print_assigns: bool = (false, parse_bool,
92a42be0 630 "include assignment analysis data in --unpretty flowgraph output"),
1a4d82fc 631 flowgraph_print_all: bool = (false, parse_bool,
92a42be0 632 "include all dataflow analysis data in --unpretty flowgraph output"),
1a4d82fc 633 print_region_graph: bool = (false, parse_bool,
92a42be0 634 "prints region inference graph. \
1a4d82fc
JJ
635 Use with RUST_REGION_GRAPH=help for more info"),
636 parse_only: bool = (false, parse_bool,
92a42be0 637 "parse only; do not compile, assemble, or link"),
1a4d82fc 638 no_trans: bool = (false, parse_bool,
92a42be0 639 "run all passes except translation; no output"),
c34b1796 640 treat_err_as_bug: bool = (false, parse_bool,
92a42be0 641 "treat all errors that occur as bugs"),
7453a54e
SL
642 continue_parse_after_error: bool = (false, parse_bool,
643 "attempt to recover from parse errors (experimental)"),
54a0048b 644 incremental: Option<String> = (None, parse_opt_string,
9cc50fc6
SL
645 "enable incremental compilation (experimental)"),
646 dump_dep_graph: bool = (false, parse_bool,
647 "dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv)"),
54a0048b
SL
648 query_dep_graph: bool = (false, parse_bool,
649 "enable queries of the dependency graph for regression testing"),
1a4d82fc 650 no_analysis: bool = (false, parse_bool,
92a42be0 651 "parse and expand the source, but run no analysis"),
1a4d82fc
JJ
652 extra_plugins: Vec<String> = (Vec::new(), parse_list,
653 "load extra plugins"),
654 unstable_options: bool = (false, parse_bool,
92a42be0 655 "adds unstable command line options to rustc interface"),
1a4d82fc 656 print_enum_sizes: bool = (false, parse_bool,
92a42be0 657 "print the size of enums and their variants"),
c34b1796 658 force_overflow_checks: Option<bool> = (None, parse_opt_bool,
92a42be0 659 "force overflow checks on or off"),
c34b1796 660 force_dropflag_checks: Option<bool> = (None, parse_opt_bool,
92a42be0 661 "force drop flag checks on or off"),
d9579d0f 662 trace_macros: bool = (false, parse_bool,
92a42be0 663 "for every macro invocation, print its name and arguments"),
c1a9b12d 664 enable_nonzeroing_move_hints: bool = (false, parse_bool,
92a42be0 665 "force nonzeroing move optimization on"),
b039eaaf 666 keep_mtwt_tables: bool = (false, parse_bool,
92a42be0 667 "don't clear the resolution tables after analysis"),
9cc50fc6
SL
668 keep_ast: bool = (false, parse_bool,
669 "keep the AST after lowering it to HIR"),
670 show_span: Option<String> = (None, parse_opt_string,
671 "show spans for compiler debugging (expr|pat|ty)"),
7453a54e
SL
672 print_trans_items: Option<String> = (None, parse_opt_string,
673 "print the result of the translation item collection pass"),
674 mir_opt_level: Option<usize> = (None, parse_opt_uint,
675 "set the MIR optimization level (0-3)"),
54a0048b
SL
676 dump_mir: Option<String> = (None, parse_opt_string,
677 "dump MIR state at various points in translation"),
678 orbit: bool = (false, parse_bool,
679 "get MIR where it belongs - everywhere; most importantly, in orbit"),
1a4d82fc
JJ
680}
681
682pub fn default_lib_output() -> CrateType {
683 CrateTypeRlib
684}
685
686pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
687 use syntax::parse::token::intern_and_get_ident as intern;
688
c34b1796
AL
689 let end = &sess.target.target.target_endian;
690 let arch = &sess.target.target.arch;
691 let wordsz = &sess.target.target.target_pointer_width;
692 let os = &sess.target.target.target_os;
d9579d0f 693 let env = &sess.target.target.target_env;
b039eaaf 694 let vendor = &sess.target.target.target_vendor;
1a4d82fc 695
92a42be0
SL
696 let fam = if let Some(ref fam) = sess.target.target.options.target_family {
697 intern(fam)
698 } else if sess.target.target.options.is_like_windows {
699 InternedString::new("windows")
700 } else {
701 InternedString::new("unix")
1a4d82fc
JJ
702 };
703
704 let mk = attr::mk_name_value_item_str;
c34b1796 705 let mut ret = vec![ // Target bindings.
92a42be0
SL
706 mk(InternedString::new("target_os"), intern(os)),
707 mk(InternedString::new("target_family"), fam.clone()),
708 mk(InternedString::new("target_arch"), intern(arch)),
709 mk(InternedString::new("target_endian"), intern(end)),
710 mk(InternedString::new("target_pointer_width"), intern(wordsz)),
711 mk(InternedString::new("target_env"), intern(env)),
712 mk(InternedString::new("target_vendor"), intern(vendor)),
c34b1796 713 ];
92a42be0
SL
714 match &fam[..] {
715 "windows" | "unix" => ret.push(attr::mk_word_item(fam)),
716 _ => (),
717 }
9cc50fc6
SL
718 if sess.target.target.options.has_elf_tls {
719 ret.push(attr::mk_word_item(InternedString::new("target_thread_local")));
720 }
c34b1796
AL
721 if sess.opts.debug_assertions {
722 ret.push(attr::mk_word_item(InternedString::new("debug_assertions")));
723 }
724 return ret;
1a4d82fc
JJ
725}
726
727pub fn append_configuration(cfg: &mut ast::CrateConfig,
728 name: InternedString) {
729 if !cfg.iter().any(|mi| mi.name() == name) {
730 cfg.push(attr::mk_word_item(name))
731 }
732}
733
734pub fn build_configuration(sess: &Session) -> ast::CrateConfig {
735 // Combine the configuration requested by the session (command line) with
736 // some default and generated configuration items
737 let default_cfg = default_configuration(sess);
738 let mut user_cfg = sess.opts.cfg.clone();
739 // If the user wants a test runner, then add the test cfg
740 if sess.opts.test {
741 append_configuration(&mut user_cfg, InternedString::new("test"))
742 }
743 let mut v = user_cfg.into_iter().collect::<Vec<_>>();
92a42be0 744 v.extend_from_slice(&default_cfg[..]);
1a4d82fc
JJ
745 v
746}
747
9cc50fc6 748pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
c34b1796 749 let target = match Target::search(&opts.target_triple) {
1a4d82fc
JJ
750 Ok(t) => t,
751 Err(e) => {
9cc50fc6 752 panic!(sp.fatal(&format!("Error loading target specification: {}", e)));
d9579d0f 753 }
1a4d82fc
JJ
754 };
755
c34b1796 756 let (int_type, uint_type) = match &target.target_pointer_width[..] {
7453a54e
SL
757 "32" => (ast::IntTy::I32, ast::UintTy::U32),
758 "64" => (ast::IntTy::I64, ast::UintTy::U64),
9cc50fc6
SL
759 w => panic!(sp.fatal(&format!("target specification was invalid: \
760 unrecognized target-pointer-width {}", w))),
1a4d82fc
JJ
761 };
762
763 Config {
764 target: target,
765 int_type: int_type,
766 uint_type: uint_type,
767 }
768}
769
85aaf69f 770#[derive(Copy, Clone, PartialEq, Eq, Debug)]
7453a54e
SL
771pub enum OptionStability {
772 Stable,
773
774 // FIXME: historically there were some options which were either `-Z` or
775 // required the `-Z unstable-options` flag, which were all intended
776 // to be unstable. Unfortunately we didn't actually gate usage of
777 // these options on the stable compiler, so we still allow them there
778 // today. There are some warnings printed out about this in the
779 // driver.
780 UnstableButNotReally,
781
782 Unstable,
783}
1a4d82fc
JJ
784
785#[derive(Clone, PartialEq, Eq)]
786pub struct RustcOptGroup {
787 pub opt_group: getopts::OptGroup,
788 pub stability: OptionStability,
789}
790
791impl RustcOptGroup {
792 pub fn is_stable(&self) -> bool {
793 self.stability == OptionStability::Stable
794 }
795
54a0048b 796 pub fn stable(g: getopts::OptGroup) -> RustcOptGroup {
1a4d82fc
JJ
797 RustcOptGroup { opt_group: g, stability: OptionStability::Stable }
798 }
799
7453a54e 800 #[allow(dead_code)] // currently we have no "truly unstable" options
54a0048b 801 pub fn unstable(g: getopts::OptGroup) -> RustcOptGroup {
1a4d82fc
JJ
802 RustcOptGroup { opt_group: g, stability: OptionStability::Unstable }
803 }
7453a54e
SL
804
805 fn unstable_bnr(g: getopts::OptGroup) -> RustcOptGroup {
806 RustcOptGroup {
807 opt_group: g,
808 stability: OptionStability::UnstableButNotReally,
809 }
810 }
1a4d82fc
JJ
811}
812
813// The `opt` local module holds wrappers around the `getopts` API that
814// adds extra rustc-specific metadata to each option; such metadata
815// is exposed by . The public
816// functions below ending with `_u` are the functions that return
817// *unstable* options, i.e. options that are only enabled when the
818// user also passes the `-Z unstable-options` debugging flag.
819mod opt {
820 // The `fn opt_u` etc below are written so that we can use them
821 // in the future; do not warn about them not being used right now.
822 #![allow(dead_code)]
823
824 use getopts;
825 use super::RustcOptGroup;
826
c34b1796
AL
827 pub type R = RustcOptGroup;
828 pub type S<'a> = &'a str;
1a4d82fc
JJ
829
830 fn stable(g: getopts::OptGroup) -> R { RustcOptGroup::stable(g) }
831 fn unstable(g: getopts::OptGroup) -> R { RustcOptGroup::unstable(g) }
7453a54e 832 fn unstable_bnr(g: getopts::OptGroup) -> R { RustcOptGroup::unstable_bnr(g) }
1a4d82fc 833
7453a54e
SL
834 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
835 stable(getopts::optopt(a, b, c, d))
836 }
837 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
838 stable(getopts::optmulti(a, b, c, d))
839 }
840 pub fn flag_s(a: S, b: S, c: S) -> R {
841 stable(getopts::optflag(a, b, c))
842 }
843 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
844 stable(getopts::optflagopt(a, b, c, d))
845 }
846 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
847 stable(getopts::optflagmulti(a, b, c))
848 }
d9579d0f 849
7453a54e
SL
850 pub fn opt(a: S, b: S, c: S, d: S) -> R {
851 unstable(getopts::optopt(a, b, c, d))
852 }
853 pub fn multi(a: S, b: S, c: S, d: S) -> R {
854 unstable(getopts::optmulti(a, b, c, d))
855 }
856 pub fn flag(a: S, b: S, c: S) -> R {
857 unstable(getopts::optflag(a, b, c))
858 }
859 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
860 unstable(getopts::optflagopt(a, b, c, d))
861 }
862 pub fn flagmulti(a: S, b: S, c: S) -> R {
863 unstable(getopts::optflagmulti(a, b, c))
864 }
1a4d82fc 865
7453a54e
SL
866 // Do not use these functions for any new options added to the compiler, all
867 // new options should use the `*_u` variants above to be truly unstable.
868 pub fn opt_ubnr(a: S, b: S, c: S, d: S) -> R {
869 unstable_bnr(getopts::optopt(a, b, c, d))
870 }
871 pub fn multi_ubnr(a: S, b: S, c: S, d: S) -> R {
872 unstable_bnr(getopts::optmulti(a, b, c, d))
873 }
874 pub fn flag_ubnr(a: S, b: S, c: S) -> R {
875 unstable_bnr(getopts::optflag(a, b, c))
876 }
877 pub fn flagopt_ubnr(a: S, b: S, c: S, d: S) -> R {
878 unstable_bnr(getopts::optflagopt(a, b, c, d))
879 }
880 pub fn flagmulti_ubnr(a: S, b: S, c: S) -> R {
881 unstable_bnr(getopts::optflagmulti(a, b, c))
882 }
1a4d82fc
JJ
883}
884
885/// Returns the "short" subset of the rustc command line options,
886/// including metadata for each option, such as whether the option is
887/// part of the stable long-term interface for rustc.
888pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
889 vec![
7453a54e
SL
890 opt::flag_s("h", "help", "Display this message"),
891 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
892 opt::multi_s("L", "", "Add a directory to the library search path",
85aaf69f 893 "[KIND=]PATH"),
7453a54e 894 opt::multi_s("l", "", "Link the generated crate(s) to the specified native
1a4d82fc
JJ
895 library NAME. The optional KIND can be one of,
896 static, dylib, or framework. If omitted, dylib is
897 assumed.", "[KIND=]NAME"),
7453a54e 898 opt::multi_s("", "crate-type", "Comma separated list of types of crates
1a4d82fc
JJ
899 for the compiler to emit",
900 "[bin|lib|rlib|dylib|staticlib]"),
7453a54e 901 opt::opt_s("", "crate-name", "Specify the name of the crate being built",
1a4d82fc 902 "NAME"),
7453a54e 903 opt::multi_s("", "emit", "Comma separated list of types of output for \
1a4d82fc
JJ
904 the compiler to emit",
905 "[asm|llvm-bc|llvm-ir|obj|link|dep-info]"),
7453a54e 906 opt::multi_s("", "print", "Comma separated list of compiler information to \
1a4d82fc 907 print on stdout",
54a0048b 908 "[crate-name|file-names|sysroot|cfg|target-list]"),
7453a54e
SL
909 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
910 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
911 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
912 opt::opt_s("", "out-dir", "Write output to compiler-chosen filename \
1a4d82fc 913 in <dir>", "DIR"),
7453a54e 914 opt::opt_s("", "explain", "Provide a detailed explanation of an error \
1a4d82fc 915 message", "OPT"),
7453a54e
SL
916 opt::flag_s("", "test", "Build a test harness"),
917 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
918 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
919 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
920 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
921 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
922 opt::multi_s("", "cap-lints", "Set the most restrictive lint level. \
c1a9b12d
SL
923 More restrictive lints are capped at this \
924 level", "LEVEL"),
7453a54e
SL
925 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
926 opt::flag_s("V", "version", "Print version info and exit"),
927 opt::flag_s("v", "verbose", "Use verbose output"),
1a4d82fc
JJ
928 ]
929}
930
931/// Returns all rustc command line options, including metadata for
932/// each option, such as whether the option is part of the stable
933/// long-term interface for rustc.
934pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
935 let mut opts = rustc_short_optgroups();
92a42be0 936 opts.extend_from_slice(&[
54a0048b
SL
937 opt::multi_s("", "extern", "Specify where an external rust library is located",
938 "NAME=PATH"),
7453a54e
SL
939 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
940 opt::multi_ubnr("Z", "", "Set internal debugging options", "FLAG"),
941 opt::opt_ubnr("", "error-format",
942 "How errors and other messages are produced",
943 "human|json"),
944 opt::opt_s("", "color", "Configure coloring of output:
54a0048b
SL
945 auto = colorize, if output goes to a tty (default);
946 always = always colorize output;
947 never = never colorize output", "auto|always|never"),
1a4d82fc 948
7453a54e 949 opt::flagopt_ubnr("", "pretty",
54a0048b
SL
950 "Pretty-print the input instead of compiling;
951 valid types are: `normal` (un-annotated source),
952 `expanded` (crates expanded), or
953 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
954 "TYPE"),
7453a54e 955 opt::flagopt_ubnr("", "unpretty",
54a0048b
SL
956 "Present the input source, unstable (and less-pretty) variants;
957 valid types are any of the types for `--pretty`, as well as:
958 `flowgraph=<nodeid>` (graphviz formatted flowgraph for node),
959 `everybody_loops` (all function bodies replaced with `loop {}`),
960 `hir` (the HIR), `hir,identified`, or
961 `hir,typed` (HIR with types for each node).",
962 "TYPE"),
7453a54e
SL
963
964 // new options here should **not** use the `_ubnr` functions, all new
965 // unstable options should use the short variants to indicate that they
966 // are truly unstable. All `_ubnr` flags are just that way because they
967 // were so historically.
968 //
969 // You may also wish to keep this comment at the bottom of this list to
970 // ensure that others see it.
1a4d82fc
JJ
971 ]);
972 opts
973}
974
975// Convert strings provided as --cfg [cfgspec] into a crate_cfg
976pub fn parse_cfgspecs(cfgspecs: Vec<String> ) -> ast::CrateConfig {
977 cfgspecs.into_iter().map(|s| {
7453a54e
SL
978 let sess = parse::ParseSess::new();
979 let mut parser = parse::new_parser_from_source_str(&sess,
980 Vec::new(),
981 "cfgspec".to_string(),
982 s.to_string());
983 let meta_item = panictry!(parser.parse_meta_item());
984
985 if !parser.reader.is_eof() {
986 early_error(ErrorOutputType::default(), &format!("invalid --cfg argument: {}",
987 s))
988 }
989
990 meta_item
1a4d82fc
JJ
991 }).collect::<ast::CrateConfig>()
992}
993
994pub fn build_session_options(matches: &getopts::Matches) -> Options {
e9174d1e 995 let color = match matches.opt_str("color").as_ref().map(|s| &s[..]) {
9cc50fc6
SL
996 Some("auto") => ColorConfig::Auto,
997 Some("always") => ColorConfig::Always,
998 Some("never") => ColorConfig::Never,
e9174d1e 999
9cc50fc6 1000 None => ColorConfig::Auto,
e9174d1e
SL
1001
1002 Some(arg) => {
9cc50fc6
SL
1003 early_error(ErrorOutputType::default(), &format!("argument for --color must be auto, \
1004 always or never (instead was `{}`)",
1005 arg))
1006 }
1007 };
1008
1009 // We need the opts_present check because the driver will send us Matches
1010 // with only stable options if no unstable options are used. Since error-format
1011 // is unstable, it will not be present. We have to use opts_present not
1012 // opt_present because the latter will panic.
1013 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1014 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1015 Some("human") => ErrorOutputType::HumanReadable(color),
1016 Some("json") => ErrorOutputType::Json,
1017
1018 None => ErrorOutputType::HumanReadable(color),
1019
1020 Some(arg) => {
1021 early_error(ErrorOutputType::HumanReadable(color),
1022 &format!("argument for --error-format must be human or json (instead \
1023 was `{}`)",
1024 arg))
1025 }
e9174d1e 1026 }
9cc50fc6
SL
1027 } else {
1028 ErrorOutputType::HumanReadable(color)
e9174d1e
SL
1029 };
1030
1a4d82fc
JJ
1031 let unparsed_crate_types = matches.opt_strs("crate-type");
1032 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
9cc50fc6 1033 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1a4d82fc
JJ
1034
1035 let mut lint_opts = vec!();
1036 let mut describe_lints = false;
1037
85aaf69f
SL
1038 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1039 for lint_name in matches.opt_strs(level.as_str()) {
1a4d82fc
JJ
1040 if lint_name == "help" {
1041 describe_lints = true;
1042 } else {
1043 lint_opts.push((lint_name.replace("-", "_"), level));
1044 }
1045 }
1046 }
1047
c1a9b12d
SL
1048 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1049 lint::Level::from_str(&cap).unwrap_or_else(|| {
9cc50fc6 1050 early_error(error_format, &format!("unknown lint level: `{}`", cap))
c1a9b12d
SL
1051 })
1052 });
1053
9cc50fc6 1054 let debugging_opts = build_debugging_options(matches, error_format);
1a4d82fc 1055
85aaf69f
SL
1056 let parse_only = debugging_opts.parse_only;
1057 let no_trans = debugging_opts.no_trans;
c34b1796 1058 let treat_err_as_bug = debugging_opts.treat_err_as_bug;
7453a54e
SL
1059 let continue_parse_after_error = debugging_opts.continue_parse_after_error;
1060 let mir_opt_level = debugging_opts.mir_opt_level.unwrap_or(1);
85aaf69f 1061 let no_analysis = debugging_opts.no_analysis;
1a4d82fc 1062
b039eaaf 1063 let mut output_types = HashMap::new();
1a4d82fc 1064 if !debugging_opts.parse_only && !no_trans {
b039eaaf
SL
1065 for list in matches.opt_strs("emit") {
1066 for output_type in list.split(',') {
1067 let mut parts = output_type.splitn(2, '=');
1068 let output_type = match parts.next().unwrap() {
1069 "asm" => OutputType::Assembly,
1070 "llvm-ir" => OutputType::LlvmAssembly,
1071 "llvm-bc" => OutputType::Bitcode,
1072 "obj" => OutputType::Object,
1073 "link" => OutputType::Exe,
1074 "dep-info" => OutputType::DepInfo,
1075 part => {
9cc50fc6 1076 early_error(error_format, &format!("unknown emission type: `{}`",
e9174d1e 1077 part))
1a4d82fc
JJ
1078 }
1079 };
b039eaaf
SL
1080 let path = parts.next().map(PathBuf::from);
1081 output_types.insert(output_type, path);
1a4d82fc
JJ
1082 }
1083 }
1084 };
9346a6ac 1085 if output_types.is_empty() {
b039eaaf 1086 output_types.insert(OutputType::Exe, None);
1a4d82fc
JJ
1087 }
1088
9cc50fc6 1089 let mut cg = build_codegen_options(matches, error_format);
92a42be0
SL
1090
1091 // Issue #30063: if user requests llvm-related output to one
1092 // particular path, disable codegen-units.
1093 if matches.opt_present("o") && cg.codegen_units != 1 {
1094 let incompatible: Vec<_> = output_types.iter()
1095 .map(|ot_path| ot_path.0)
1096 .filter(|ot| {
1097 !ot.is_compatible_with_codegen_units_and_single_output_file()
1098 }).collect();
1099 if !incompatible.is_empty() {
1100 for ot in &incompatible {
9cc50fc6
SL
1101 early_warn(error_format, &format!("--emit={} with -o incompatible with \
1102 -C codegen-units=N for N > 1",
1103 ot.shorthand()));
92a42be0 1104 }
9cc50fc6 1105 early_warn(error_format, "resetting to default -C codegen-units=1");
92a42be0
SL
1106 cg.codegen_units = 1;
1107 }
1108 }
1109
54a0048b
SL
1110 if cg.codegen_units < 1 {
1111 early_error(error_format, "Value for codegen units must be a positive nonzero integer");
1112 }
1113
92a42be0 1114 let cg = cg;
1a4d82fc 1115
c34b1796 1116 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1a4d82fc
JJ
1117 let target = matches.opt_str("target").unwrap_or(
1118 host_triple().to_string());
1119 let opt_level = {
1120 if matches.opt_present("O") {
1a4d82fc 1121 if cg.opt_level.is_some() {
9cc50fc6 1122 early_error(error_format, "-O and -C opt-level both provided");
1a4d82fc 1123 }
9cc50fc6 1124 OptLevel::Default
1a4d82fc
JJ
1125 } else {
1126 match cg.opt_level {
9cc50fc6
SL
1127 None => OptLevel::No,
1128 Some(0) => OptLevel::No,
1129 Some(1) => OptLevel::Less,
1130 Some(2) => OptLevel::Default,
1131 Some(3) => OptLevel::Aggressive,
1a4d82fc 1132 Some(arg) => {
9cc50fc6
SL
1133 early_error(error_format, &format!("optimization level needs to be \
1134 between 0-3 (instead was `{}`)",
1135 arg));
1a4d82fc
JJ
1136 }
1137 }
1138 }
1139 };
9cc50fc6 1140 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1a4d82fc
JJ
1141 let gc = debugging_opts.gc;
1142 let debuginfo = if matches.opt_present("g") {
1a4d82fc 1143 if cg.debuginfo.is_some() {
9cc50fc6 1144 early_error(error_format, "-g and -C debuginfo both provided");
1a4d82fc
JJ
1145 }
1146 FullDebugInfo
1a4d82fc
JJ
1147 } else {
1148 match cg.debuginfo {
1149 None | Some(0) => NoDebugInfo,
1150 Some(1) => LimitedDebugInfo,
1151 Some(2) => FullDebugInfo,
1152 Some(arg) => {
9cc50fc6
SL
1153 early_error(error_format, &format!("debug info level needs to be between \
1154 0-2 (instead was `{}`)",
1155 arg));
1a4d82fc
JJ
1156 }
1157 }
1158 };
1159
1160 let mut search_paths = SearchPaths::new();
85aaf69f 1161 for s in &matches.opt_strs("L") {
9cc50fc6 1162 search_paths.add_path(&s[..], error_format);
1a4d82fc
JJ
1163 }
1164
1165 let libs = matches.opt_strs("l").into_iter().map(|s| {
c34b1796 1166 let mut parts = s.splitn(2, '=');
1a4d82fc
JJ
1167 let kind = parts.next().unwrap();
1168 let (name, kind) = match (parts.next(), kind) {
1169 (None, name) |
1170 (Some(name), "dylib") => (name, cstore::NativeUnknown),
1171 (Some(name), "framework") => (name, cstore::NativeFramework),
1172 (Some(name), "static") => (name, cstore::NativeStatic),
1173 (_, s) => {
9cc50fc6
SL
1174 early_error(error_format, &format!("unknown library kind `{}`, expected \
1175 one of dylib, framework, or static",
1176 s));
1a4d82fc
JJ
1177 }
1178 };
1179 (name.to_string(), kind)
1180 }).collect();
1181
1182 let cfg = parse_cfgspecs(matches.opt_strs("cfg"));
1183 let test = matches.opt_present("test");
1a4d82fc 1184
85aaf69f
SL
1185 let prints = matches.opt_strs("print").into_iter().map(|s| {
1186 match &*s {
1a4d82fc
JJ
1187 "crate-name" => PrintRequest::CrateName,
1188 "file-names" => PrintRequest::FileNames,
1189 "sysroot" => PrintRequest::Sysroot,
7453a54e
SL
1190 "cfg" => PrintRequest::Cfg,
1191 "target-list" => PrintRequest::TargetList,
1a4d82fc 1192 req => {
9cc50fc6 1193 early_error(error_format, &format!("unknown print request `{}`", req))
1a4d82fc
JJ
1194 }
1195 }
1196 }).collect::<Vec<_>>();
1a4d82fc
JJ
1197
1198 if !cg.remark.is_empty() && debuginfo == NoDebugInfo {
9cc50fc6
SL
1199 early_warn(error_format, "-C remark will not show source locations without \
1200 --debuginfo");
1a4d82fc
JJ
1201 }
1202
1a4d82fc 1203 let mut externs = HashMap::new();
85aaf69f 1204 for arg in &matches.opt_strs("extern") {
c34b1796 1205 let mut parts = arg.splitn(2, '=');
1a4d82fc
JJ
1206 let name = match parts.next() {
1207 Some(s) => s,
9cc50fc6 1208 None => early_error(error_format, "--extern value must not be empty"),
1a4d82fc
JJ
1209 };
1210 let location = match parts.next() {
1211 Some(s) => s,
9cc50fc6 1212 None => early_error(error_format, "--extern value must be of the format `foo=bar`"),
1a4d82fc
JJ
1213 };
1214
c34b1796 1215 externs.entry(name.to_string()).or_insert(vec![]).push(location.to_string());
1a4d82fc
JJ
1216 }
1217
1218 let crate_name = matches.opt_str("crate-name");
1219
54a0048b
SL
1220 let incremental = debugging_opts.incremental.as_ref().map(|m| PathBuf::from(m));
1221
1a4d82fc
JJ
1222 Options {
1223 crate_types: crate_types,
1224 gc: gc,
1225 optimize: opt_level,
1226 debuginfo: debuginfo,
1227 lint_opts: lint_opts,
c1a9b12d 1228 lint_cap: lint_cap,
1a4d82fc
JJ
1229 describe_lints: describe_lints,
1230 output_types: output_types,
1231 search_paths: search_paths,
1232 maybe_sysroot: sysroot_opt,
1233 target_triple: target,
1234 cfg: cfg,
1235 test: test,
1236 parse_only: parse_only,
1237 no_trans: no_trans,
c34b1796 1238 treat_err_as_bug: treat_err_as_bug,
7453a54e
SL
1239 continue_parse_after_error: continue_parse_after_error,
1240 mir_opt_level: mir_opt_level,
54a0048b 1241 incremental: incremental,
1a4d82fc
JJ
1242 no_analysis: no_analysis,
1243 debugging_opts: debugging_opts,
1a4d82fc
JJ
1244 prints: prints,
1245 cg: cg,
9cc50fc6 1246 error_format: error_format,
1a4d82fc
JJ
1247 externs: externs,
1248 crate_name: crate_name,
1249 alt_std_name: None,
1250 libs: libs,
85aaf69f 1251 unstable_features: get_unstable_features_setting(),
c34b1796 1252 debug_assertions: debug_assertions,
85aaf69f
SL
1253 }
1254}
1255
1256pub fn get_unstable_features_setting() -> UnstableFeatures {
1257 // Whether this is a feature-staged build, i.e. on the beta or stable channel
1258 let disable_unstable_features = option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
1259 // The secret key needed to get through the rustc build itself by
1260 // subverting the unstable features lints
1261 let bootstrap_secret_key = option_env!("CFG_BOOTSTRAP_KEY");
1262 // The matching key to the above, only known by the build system
1263 let bootstrap_provided_key = env::var("RUSTC_BOOTSTRAP_KEY").ok();
1264 match (disable_unstable_features, bootstrap_secret_key, bootstrap_provided_key) {
1265 (_, Some(ref s), Some(ref p)) if s == p => UnstableFeatures::Cheat,
1266 (true, _, _) => UnstableFeatures::Disallow,
62682a34 1267 (false, _, _) => UnstableFeatures::Allow
1a4d82fc
JJ
1268 }
1269}
1270
1271pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
1a4d82fc 1272 let mut crate_types: Vec<CrateType> = Vec::new();
85aaf69f 1273 for unparsed_crate_type in &list_list {
1a4d82fc
JJ
1274 for part in unparsed_crate_type.split(',') {
1275 let new_part = match part {
1276 "lib" => default_lib_output(),
1277 "rlib" => CrateTypeRlib,
1278 "staticlib" => CrateTypeStaticlib,
1279 "dylib" => CrateTypeDylib,
1280 "bin" => CrateTypeExecutable,
1281 _ => {
1282 return Err(format!("unknown crate type: `{}`",
1283 part));
1284 }
1285 };
85aaf69f
SL
1286 if !crate_types.contains(&new_part) {
1287 crate_types.push(new_part)
1288 }
1a4d82fc
JJ
1289 }
1290 }
1291
1292 return Ok(crate_types);
1293}
1294
54a0048b
SL
1295pub mod nightly_options {
1296 use getopts;
1297 use syntax::feature_gate::UnstableFeatures;
1298 use super::{ErrorOutputType, OptionStability, RustcOptGroup, get_unstable_features_setting};
1299 use session::{early_error, early_warn};
1300
1301 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
1302 is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
1303 }
1304
1305 fn is_nightly_build() -> bool {
1306 match get_unstable_features_setting() {
1307 UnstableFeatures::Allow | UnstableFeatures::Cheat => true,
1308 _ => false,
1309 }
1310 }
1311
1312 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
1313 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
1314 let really_allows_unstable_options = match get_unstable_features_setting() {
1315 UnstableFeatures::Disallow => false,
1316 _ => true,
1317 };
1318
1319 for opt in flags.iter() {
1320 if opt.stability == OptionStability::Stable {
1321 continue
1322 }
1323 let opt_name = if opt.opt_group.long_name.is_empty() {
1324 &opt.opt_group.short_name
1325 } else {
1326 &opt.opt_group.long_name
1327 };
1328 if !matches.opt_present(opt_name) {
1329 continue
1330 }
1331 if opt_name != "Z" && !has_z_unstable_option {
1332 early_error(ErrorOutputType::default(),
1333 &format!("the `-Z unstable-options` flag must also be passed to enable \
1334 the flag `{}`",
1335 opt_name));
1336 }
1337 if really_allows_unstable_options {
1338 continue
1339 }
1340 match opt.stability {
1341 OptionStability::Unstable => {
1342 let msg = format!("the option `{}` is only accepted on the \
1343 nightly compiler", opt_name);
1344 early_error(ErrorOutputType::default(), &msg);
1345 }
1346 OptionStability::UnstableButNotReally => {
1347 let msg = format!("the option `{}` is is unstable and should \
1348 only be used on the nightly compiler, but \
1349 it is currently accepted for backwards \
1350 compatibility; this will soon change, \
1351 see issue #31847 for more details",
1352 opt_name);
1353 early_warn(ErrorOutputType::default(), &msg);
1354 }
1355 OptionStability::Stable => {}
1356 }
1357 }
1358 }
1359}
1360
85aaf69f 1361impl fmt::Display for CrateType {
1a4d82fc
JJ
1362 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1363 match *self {
1364 CrateTypeExecutable => "bin".fmt(f),
1365 CrateTypeDylib => "dylib".fmt(f),
1366 CrateTypeRlib => "rlib".fmt(f),
1367 CrateTypeStaticlib => "staticlib".fmt(f)
1368 }
1369 }
1370}
1371
1372#[cfg(test)]
d9579d0f 1373mod tests {
92a42be0 1374 use middle::cstore::DummyCrateStore;
7453a54e 1375 use session::config::{build_configuration, build_session_options};
1a4d82fc
JJ
1376 use session::build_session;
1377
92a42be0 1378 use std::rc::Rc;
7453a54e 1379 use getopts::{getopts, OptGroup};
1a4d82fc
JJ
1380 use syntax::attr;
1381 use syntax::attr::AttrMetaMethods;
1382 use syntax::diagnostics;
1383
7453a54e
SL
1384 fn optgroups() -> Vec<OptGroup> {
1385 super::rustc_optgroups().into_iter()
1386 .map(|a| a.opt_group)
1387 .collect()
1388 }
1389
1a4d82fc
JJ
1390 // When the user supplies --test we should implicitly supply --cfg test
1391 #[test]
1392 fn test_switch_implies_cfg_test() {
1393 let matches =
c34b1796 1394 &match getopts(&["--test".to_string()], &optgroups()) {
1a4d82fc
JJ
1395 Ok(m) => m,
1396 Err(f) => panic!("test_switch_implies_cfg_test: {}", f)
1397 };
1398 let registry = diagnostics::registry::Registry::new(&[]);
1399 let sessopts = build_session_options(matches);
92a42be0 1400 let sess = build_session(sessopts, None, registry, Rc::new(DummyCrateStore));
1a4d82fc 1401 let cfg = build_configuration(&sess);
85aaf69f 1402 assert!((attr::contains_name(&cfg[..], "test")));
1a4d82fc
JJ
1403 }
1404
1405 // When the user supplies --test and --cfg test, don't implicitly add
1406 // another --cfg test
1407 #[test]
1408 fn test_switch_implies_cfg_test_unless_cfg_test() {
1409 let matches =
1410 &match getopts(&["--test".to_string(), "--cfg=test".to_string()],
c34b1796 1411 &optgroups()) {
1a4d82fc
JJ
1412 Ok(m) => m,
1413 Err(f) => {
1414 panic!("test_switch_implies_cfg_test_unless_cfg_test: {}", f)
1415 }
1416 };
1417 let registry = diagnostics::registry::Registry::new(&[]);
1418 let sessopts = build_session_options(matches);
92a42be0
SL
1419 let sess = build_session(sessopts, None, registry,
1420 Rc::new(DummyCrateStore));
1a4d82fc
JJ
1421 let cfg = build_configuration(&sess);
1422 let mut test_items = cfg.iter().filter(|m| m.name() == "test");
1423 assert!(test_items.next().is_some());
1424 assert!(test_items.next().is_none());
1425 }
1426
1427 #[test]
1428 fn test_can_print_warnings() {
1429 {
1430 let matches = getopts(&[
1431 "-Awarnings".to_string()
c34b1796 1432 ], &optgroups()).unwrap();
1a4d82fc
JJ
1433 let registry = diagnostics::registry::Registry::new(&[]);
1434 let sessopts = build_session_options(&matches);
92a42be0
SL
1435 let sess = build_session(sessopts, None, registry,
1436 Rc::new(DummyCrateStore));
9cc50fc6 1437 assert!(!sess.diagnostic().can_emit_warnings);
1a4d82fc
JJ
1438 }
1439
1440 {
1441 let matches = getopts(&[
1442 "-Awarnings".to_string(),
1443 "-Dwarnings".to_string()
c34b1796 1444 ], &optgroups()).unwrap();
1a4d82fc
JJ
1445 let registry = diagnostics::registry::Registry::new(&[]);
1446 let sessopts = build_session_options(&matches);
92a42be0
SL
1447 let sess = build_session(sessopts, None, registry,
1448 Rc::new(DummyCrateStore));
9cc50fc6 1449 assert!(sess.diagnostic().can_emit_warnings);
1a4d82fc
JJ
1450 }
1451
1452 {
1453 let matches = getopts(&[
1454 "-Adead_code".to_string()
c34b1796 1455 ], &optgroups()).unwrap();
1a4d82fc
JJ
1456 let registry = diagnostics::registry::Registry::new(&[]);
1457 let sessopts = build_session_options(&matches);
92a42be0
SL
1458 let sess = build_session(sessopts, None, registry,
1459 Rc::new(DummyCrateStore));
9cc50fc6 1460 assert!(sess.diagnostic().can_emit_warnings);
1a4d82fc
JJ
1461 }
1462 }
1463}