]> git.proxmox.com Git - rustc.git/blame - src/librustc/session/config.rs
Imported Upstream version 1.0.0~beta.3
[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::*;
17pub use self::OptLevel::*;
18pub use self::OutputType::*;
19pub use self::DebugInfoLevel::*;
20
21use session::{early_error, early_warn, Session};
22use session::search_paths::SearchPaths;
23
24use rustc_back::target::Target;
25use lint;
26use metadata::cstore;
27
28use syntax::ast;
29use syntax::ast::{IntTy, UintTy};
30use syntax::attr;
31use syntax::attr::AttrMetaMethods;
32use syntax::diagnostic::{ColorConfig, Auto, Always, Never, SpanHandler};
33use syntax::parse;
34use syntax::parse::token::InternedString;
35
85aaf69f 36use getopts;
1a4d82fc 37use std::collections::HashMap;
85aaf69f 38use std::env;
1a4d82fc 39use std::fmt;
c34b1796 40use std::path::PathBuf;
1a4d82fc
JJ
41
42use llvm;
43
44pub struct Config {
45 pub target: Target,
46 pub int_type: IntTy,
47 pub uint_type: UintTy,
48}
49
50#[derive(Clone, Copy, PartialEq)]
51pub enum OptLevel {
52 No, // -O0
53 Less, // -O1
54 Default, // -O2
55 Aggressive // -O3
56}
57
58#[derive(Clone, Copy, PartialEq)]
59pub enum DebugInfoLevel {
60 NoDebugInfo,
61 LimitedDebugInfo,
62 FullDebugInfo,
63}
64
65#[derive(Clone, Copy, PartialEq, PartialOrd, Ord, Eq)]
66pub enum OutputType {
67 OutputTypeBitcode,
68 OutputTypeAssembly,
69 OutputTypeLlvmAssembly,
70 OutputTypeObject,
71 OutputTypeExe,
72 OutputTypeDepInfo,
73}
74
75#[derive(Clone)]
76pub 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)]
123pub 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
138pub enum PrintRequest {
139 FileNames,
140 Sysroot,
141 CrateName,
142}
143
144pub enum Input {
145 /// Load source from file
c34b1796 146 File(PathBuf),
1a4d82fc
JJ
147 /// The string is the source
148 Str(String)
149}
150
151impl 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)]
162pub 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
169impl 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
199pub 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
213pub 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
251pub enum EntryFnType {
252 EntryMain,
253 EntryStart,
254 EntryNone,
255}
256
85aaf69f 257#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)]
1a4d82fc
JJ
258pub enum CrateType {
259 CrateTypeExecutable,
260 CrateTypeDylib,
261 CrateTypeRlib,
262 CrateTypeStaticlib,
263}
264
1a4d82fc
JJ
265#[derive(Clone)]
266pub enum Passes {
267 SomePasses(Vec<String>),
268 AllPasses,
269}
270
271impl 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.
290macro_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
476options! {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
537options! {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
611pub fn default_lib_output() -> CrateType {
612 CrateTypeRlib
613}
614
615pub 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
644pub 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
651pub 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
665pub 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.
688pub 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.
696pub 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
704pub enum OptionStability { Stable, Unstable }
705
706#[derive(Clone, PartialEq, Eq)]
707pub struct RustcOptGroup {
708 pub opt_group: getopts::OptGroup,
709 pub stability: OptionStability,
710}
711
712impl 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.
732mod 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.
765pub 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.
812pub 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
844pub 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
853pub 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
1060pub 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
1075pub 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 1100impl 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)]
1112mod 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}