config.rs 33.9 KB
Newer Older
N
Nick Cameron 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Contains infrastructure for configuring the compiler, including parsing
//! command line options.

14
use driver::{early_error, early_warn};
N
Nick Cameron 已提交
15 16 17 18
use driver::driver;
use driver::session::Session;

use back;
19
use back::write;
N
Nick Cameron 已提交
20
use back::target_strs;
21
use back::{arm, x86, x86_64, mips, mipsel};
K
Keegan McAllister 已提交
22
use lint;
N
Nick Cameron 已提交
23 24 25 26 27 28

use syntax::abi;
use syntax::ast;
use syntax::ast::{IntTy, UintTy};
use syntax::attr;
use syntax::attr::AttrMetaMethods;
29
use syntax::diagnostic::{ColorConfig, Auto, Always, Never};
N
Nick Cameron 已提交
30 31 32
use syntax::parse;
use syntax::parse::token::InternedString;

33
use std::collections::HashMap;
34
use std::collections::hash_map::{Occupied, Vacant};
N
Nick Cameron 已提交
35 36 37
use getopts::{optopt, optmulti, optflag, optflagopt};
use getopts;
use std::cell::{RefCell};
38
use std::fmt;
N
Nick Cameron 已提交
39

40
use llvm;
N
Nick Cameron 已提交
41 42 43 44 45 46 47 48 49

pub struct Config {
    pub os: abi::Os,
    pub arch: abi::Architecture,
    pub target_strs: target_strs::t,
    pub int_type: IntTy,
    pub uint_type: UintTy,
}

50
#[deriving(Clone, PartialEq)]
N
Nick Cameron 已提交
51 52 53 54 55 56 57
pub enum OptLevel {
    No, // -O0
    Less, // -O1
    Default, // -O2
    Aggressive // -O3
}

58
#[deriving(Clone, PartialEq)]
N
Nick Cameron 已提交
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
pub enum DebugInfoLevel {
    NoDebugInfo,
    LimitedDebugInfo,
    FullDebugInfo,
}

#[deriving(Clone)]
pub struct Options {
    // The crate config requested for the session, which may be combined
    // with additional crate configurations during the compile process
    pub crate_types: Vec<CrateType>,

    pub gc: bool,
    pub optimize: OptLevel,
    pub debuginfo: DebugInfoLevel,
74 75
    pub lint_opts: Vec<(String, lint::Level)>,
    pub describe_lints: bool,
76
    pub output_types: Vec<back::write::OutputType> ,
N
Nick Cameron 已提交
77 78 79
    // This was mutable for rustpkg, which updates search paths based on the
    // parsed code. It remains mutable in case its replacements wants to use
    // this.
80
    pub addl_lib_search_paths: RefCell<Vec<Path>>,
N
Nick Cameron 已提交
81
    pub maybe_sysroot: Option<Path>,
82
    pub target_triple: String,
N
Nick Cameron 已提交
83 84 85 86 87 88 89 90 91 92 93 94
    // User-specified cfg meta items. The compiler itself will add additional
    // items to the crate config, and during parsing the entire crate config
    // will be added to the crate AST node.  This should not be used for
    // anything except building the full crate config prior to parsing.
    pub cfg: ast::CrateConfig,
    pub test: bool,
    pub parse_only: bool,
    pub no_trans: bool,
    pub no_analysis: bool,
    pub debugging_opts: u64,
    /// Whether to write dependency files. It's (enabled, optional filename).
    pub write_dependency_info: (bool, Option<Path>),
95 96
    /// Crate id-related things to maybe print. It's (crate_name, crate_file_name).
    pub print_metas: (bool, bool),
N
Nick Cameron 已提交
97
    pub cg: CodegenOptions,
98
    pub color: ColorConfig,
99
    pub externs: HashMap<String, Vec<String>>,
100
    pub crate_name: Option<String>,
B
Brian Anderson 已提交
101 102 103
    /// An optional name to use as the crate for std during std injection,
    /// written `extern crate std = "name"`. Default to "std". Used by
    /// out-of-tree drivers.
104
    pub alt_std_name: Option<String>
N
Nick Cameron 已提交
105 106 107 108 109 110 111 112 113 114
}

/// Some reasonable defaults
pub fn basic_options() -> Options {
    Options {
        crate_types: Vec::new(),
        gc: false,
        optimize: No,
        debuginfo: NoDebugInfo,
        lint_opts: Vec::new(),
115
        describe_lints: false,
N
Nick Cameron 已提交
116
        output_types: Vec::new(),
117
        addl_lib_search_paths: RefCell::new(Vec::new()),
N
Nick Cameron 已提交
118
        maybe_sysroot: None,
119
        target_triple: driver::host_triple().to_string(),
N
Nick Cameron 已提交
120 121 122 123 124 125 126
        cfg: Vec::new(),
        test: false,
        parse_only: false,
        no_trans: false,
        no_analysis: false,
        debugging_opts: 0,
        write_dependency_info: (false, None),
127
        print_metas: (false, false),
N
Nick Cameron 已提交
128
        cg: basic_codegen_options(),
129
        color: Auto,
130
        externs: HashMap::new(),
131
        crate_name: None,
132
        alt_std_name: None,
N
Nick Cameron 已提交
133 134 135 136 137 138 139
    }
}

// The type of entry function, so
// users can have their own entry
// functions that don't start a
// scheduler
140
#[deriving(PartialEq)]
N
Nick Cameron 已提交
141 142 143 144 145 146
pub enum EntryFnType {
    EntryMain,
    EntryStart,
    EntryNone,
}

147
#[deriving(PartialEq, PartialOrd, Clone, Ord, Eq, Hash)]
N
Nick Cameron 已提交
148 149 150 151 152 153 154 155 156
pub enum CrateType {
    CrateTypeExecutable,
    CrateTypeDylib,
    CrateTypeRlib,
    CrateTypeStaticlib,
}

macro_rules! debugging_opts(
    ([ $opt:ident ] $cnt:expr ) => (
157
        pub const $opt: u64 = 1 << $cnt;
N
Nick Cameron 已提交
158 159
    );
    ([ $opt:ident, $($rest:ident),* ] $cnt:expr ) => (
160
        pub const $opt: u64 = 1 << $cnt;
N
Nick Cameron 已提交
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
        debugging_opts!([ $($rest),* ] $cnt + 1)
    )
)

debugging_opts!(
    [
        VERBOSE,
        TIME_PASSES,
        COUNT_LLVM_INSNS,
        TIME_LLVM_PASSES,
        TRANS_STATS,
        ASM_COMMENTS,
        NO_VERIFY,
        BORROWCK_STATS,
        NO_LANDING_PADS,
        DEBUG_LLVM,
        SHOW_SPAN,
        COUNT_TYPE_SIZES,
        META_STATS,
        GC,
        PRINT_LINK_ARGS,
        PRINT_LLVM_PASSES,
        AST_JSON,
        AST_JSON_NOEXPAND,
185
        LS,
186 187 188 189 190
        SAVE_ANALYSIS,
        FLOWGRAPH_PRINT_LOANS,
        FLOWGRAPH_PRINT_MOVES,
        FLOWGRAPH_PRINT_ASSIGNS,
        FLOWGRAPH_PRINT_ALL
N
Nick Cameron 已提交
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
    ]
    0
)

pub fn debugging_opts_map() -> Vec<(&'static str, &'static str, u64)> {
    vec!(("verbose", "in general, enable more debug printouts", VERBOSE),
     ("time-passes", "measure time of each rustc pass", TIME_PASSES),
     ("count-llvm-insns", "count where LLVM \
                           instrs originate", COUNT_LLVM_INSNS),
     ("time-llvm-passes", "measure time of each LLVM pass",
      TIME_LLVM_PASSES),
     ("trans-stats", "gather trans statistics", TRANS_STATS),
     ("asm-comments", "generate comments into the assembly (may change behavior)",
      ASM_COMMENTS),
     ("no-verify", "skip LLVM verification", NO_VERIFY),
     ("borrowck-stats", "gather borrowck statistics",  BORROWCK_STATS),
     ("no-landing-pads", "omit landing pads for unwinding",
      NO_LANDING_PADS),
     ("debug-llvm", "enable debug output from LLVM", DEBUG_LLVM),
     ("show-span", "show spans for compiler debugging", SHOW_SPAN),
     ("count-type-sizes", "count the sizes of aggregate types",
      COUNT_TYPE_SIZES),
     ("meta-stats", "gather metadata statistics", META_STATS),
     ("print-link-args", "Print the arguments passed to the linker",
      PRINT_LINK_ARGS),
     ("gc", "Garbage collect shared data (experimental)", GC),
     ("print-llvm-passes",
      "Prints the llvm optimization passes being run",
      PRINT_LLVM_PASSES),
     ("ast-json", "Print the AST as JSON and halt", AST_JSON),
     ("ast-json-noexpand", "Print the pre-expansion AST as JSON and halt", AST_JSON_NOEXPAND),
222 223
     ("ls", "List the symbols defined by a library crate", LS),
     ("save-analysis", "Write syntax and type analysis information \
224 225 226 227 228 229 230 231 232
                        in addition to normal output", SAVE_ANALYSIS),
     ("flowgraph-print-loans", "Include loan analysis data in \
                       --pretty flowgraph output", FLOWGRAPH_PRINT_LOANS),
     ("flowgraph-print-moves", "Include move analysis data in \
                       --pretty flowgraph output", FLOWGRAPH_PRINT_MOVES),
     ("flowgraph-print-assigns", "Include assignment analysis data in \
                       --pretty flowgraph output", FLOWGRAPH_PRINT_ASSIGNS),
     ("flowgraph-print-all", "Include all dataflow analysis data in \
                       --pretty flowgraph output", FLOWGRAPH_PRINT_ALL))
N
Nick Cameron 已提交
233 234
}

235 236
#[deriving(Clone)]
pub enum Passes {
237
    SomePasses(Vec<String>),
238 239 240 241 242 243
    AllPasses,
}

impl Passes {
    pub fn is_empty(&self) -> bool {
        match *self {
244
            SomePasses(ref v) => v.is_empty(),
245 246 247 248 249
            AllPasses => false,
        }
    }
}

N
Nick Cameron 已提交
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
/// Declare a macro that will define all CodegenOptions fields and parsers all
/// at once. The goal of this macro is to define an interface that can be
/// programmatically used by the option parser in order to initialize the struct
/// without hardcoding field names all over the place.
///
/// The goal is to invoke this macro once with the correct fields, and then this
/// macro generates all necessary code. The main gotcha of this macro is the
/// cgsetters module which is a bunch of generated code to parse an option into
/// its respective field in the struct. There are a few hand-written parsers for
/// parsing specific types of values in this module.
macro_rules! cgoptions(
    ($($opt:ident : $t:ty = ($init:expr, $parse:ident, $desc:expr)),* ,) =>
(
    #[deriving(Clone)]
    pub struct CodegenOptions { $(pub $opt: $t),* }

    pub fn basic_codegen_options() -> CodegenOptions {
        CodegenOptions { $($opt: $init),* }
    }

    pub type CodegenSetter = fn(&mut CodegenOptions, v: Option<&str>) -> bool;
271
    pub const CG_OPTIONS: &'static [(&'static str, CodegenSetter,
N
Nick Cameron 已提交
272 273 274 275
                                      &'static str)] =
        &[ $( (stringify!($opt), cgsetters::$opt, $desc) ),* ];

    mod cgsetters {
276
        use super::{CodegenOptions, Passes, SomePasses, AllPasses};
N
Nick Cameron 已提交
277 278 279 280 281 282 283 284 285 286 287 288 289 290

        $(
            pub fn $opt(cg: &mut CodegenOptions, v: Option<&str>) -> bool {
                $parse(&mut cg.$opt, v)
            }
        )*

        fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
            match v {
                Some(..) => false,
                None => { *slot = true; true }
            }
        }

291
        fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
N
Nick Cameron 已提交
292
            match v {
293
                Some(s) => { *slot = Some(s.to_string()); true },
N
Nick Cameron 已提交
294 295 296 297
                None => false,
            }
        }

298
        fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
N
Nick Cameron 已提交
299
            match v {
300
                Some(s) => { *slot = s.to_string(); true },
N
Nick Cameron 已提交
301 302 303 304
                None => false,
            }
        }

305
        fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
N
Nick Cameron 已提交
306 307 308 309
                      -> bool {
            match v {
                Some(s) => {
                    for s in s.words() {
310
                        slot.push(s.to_string());
N
Nick Cameron 已提交
311 312 313 314 315 316 317
                    }
                    true
                },
                None => false,
            }
        }

318 319 320 321 322 323 324
        fn parse_uint(slot: &mut uint, v: Option<&str>) -> bool {
            use std::from_str::FromStr;
            match v.and_then(FromStr::from_str) {
                Some(i) => { *slot = i; true },
                None => false
            }
        }
325 326 327 328 329 330 331 332 333 334

        fn parse_passes(slot: &mut Passes, v: Option<&str>) -> bool {
            match v {
                Some("all") => {
                    *slot = AllPasses;
                    true
                }
                v => {
                    let mut passes = vec!();
                    if parse_list(&mut passes, v) {
335
                        *slot = SomePasses(passes);
336 337 338 339 340 341 342
                        true
                    } else {
                        false
                    }
                }
            }
        }
N
Nick Cameron 已提交
343 344 345 346
    }
) )

cgoptions!(
347
    ar: Option<String> = (None, parse_opt_string,
N
Nick Cameron 已提交
348
        "tool to assemble archives with"),
349
    linker: Option<String> = (None, parse_opt_string,
N
Nick Cameron 已提交
350
        "system linker to link outputs with"),
351
    link_args: Vec<String> = (Vec::new(), parse_list,
N
Nick Cameron 已提交
352
        "extra arguments to pass to the linker (space separated)"),
C
Colin Davidson 已提交
353 354
    lto: bool = (false, parse_bool,
        "perform LLVM link-time optimizations"),
355
    target_cpu: String = ("generic".to_string(), parse_string,
N
Nick Cameron 已提交
356
        "select target processor (llc -mcpu=help for details)"),
357
    target_feature: String = ("".to_string(), parse_string,
N
Nick Cameron 已提交
358
        "target specific attributes (llc -mattr=help for details)"),
359
    passes: Vec<String> = (Vec::new(), parse_list,
N
Nick Cameron 已提交
360
        "a list of extra LLVM passes to run (space separated)"),
361
    llvm_args: Vec<String> = (Vec::new(), parse_list,
N
Nick Cameron 已提交
362 363 364
        "a list of arguments to pass to llvm (space separated)"),
    save_temps: bool = (false, parse_bool,
        "save all temporary output files during compilation"),
365 366
    rpath: bool = (false, parse_bool,
        "set rpath values in libs/exes"),
N
Nick Cameron 已提交
367 368 369 370 371 372 373 374 375 376 377 378
    no_prepopulate_passes: bool = (false, parse_bool,
        "don't pre-populate the pass manager with a list of passes"),
    no_vectorize_loops: bool = (false, parse_bool,
        "don't run the loop vectorization optimization passes"),
    no_vectorize_slp: bool = (false, parse_bool,
        "don't run LLVM's SLP vectorization pass"),
    soft_float: bool = (false, parse_bool,
        "generate software floating point library calls"),
    prefer_dynamic: bool = (false, parse_bool,
        "prefer dynamic linking to static linking"),
    no_integrated_as: bool = (false, parse_bool,
        "use an external assembler rather than LLVM's integrated one"),
379 380
    no_redzone: bool = (false, parse_bool,
        "disable the use of the redzone"),
381
    relocation_model: String = ("pic".to_string(), parse_string,
N
Nick Cameron 已提交
382
         "choose the relocation model to use (llc -relocation-model for details)"),
383 384
    code_model: String = ("default".to_string(), parse_string,
         "choose the code model to use (llc -code-model for details)"),
385 386
    metadata: Vec<String> = (Vec::new(), parse_list,
         "metadata to mangle symbol names with"),
387 388
    extra_filename: String = ("".to_string(), parse_string,
         "extra data to put in each output filename"),
389 390
    codegen_units: uint = (1, parse_uint,
        "divide crate into N units to optimize in parallel"),
391
    remark: Passes = (SomePasses(Vec::new()), parse_passes,
392
        "print remarks for these optimization passes (space separated, or \"all\")"),
K
Keegan McAllister 已提交
393 394
    no_stack_check: bool = (false, parse_bool,
        "disable checks for stack exhaustion (a memory-safety hazard!)"),
N
Nick Cameron 已提交
395 396 397 398 399
)

pub fn build_codegen_options(matches: &getopts::Matches) -> CodegenOptions
{
    let mut cg = basic_codegen_options();
A
Aaron Turon 已提交
400
    for option in matches.opt_strs("C").into_iter() {
401
        let mut iter = option.as_slice().splitn(1, '=');
N
Nick Cameron 已提交
402 403 404 405 406 407 408 409
        let key = iter.next().unwrap();
        let value = iter.next();
        let option_to_lookup = key.replace("-", "_");
        let mut found = false;
        for &(candidate, setter, _) in CG_OPTIONS.iter() {
            if option_to_lookup.as_slice() != candidate { continue }
            if !setter(&mut cg, value) {
                match value {
410 411 412 413 414 415 416 417 418
                    Some(..) => {
                        early_error(format!("codegen option `{}` takes no \
                                             value", key).as_slice())
                    }
                    None => {
                        early_error(format!("codegen option `{0}` requires \
                                             a value (-C {0}=<value>)",
                                            key).as_slice())
                    }
N
Nick Cameron 已提交
419 420 421 422 423 424
                }
            }
            found = true;
            break;
        }
        if !found {
425 426
            early_error(format!("unknown codegen option: `{}`",
                                key).as_slice());
N
Nick Cameron 已提交
427 428 429 430 431 432 433 434 435 436 437
        }
    }
    return cg;
}

pub fn default_lib_output() -> CrateType {
    CrateTypeRlib
}

pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
    let tos = match sess.targ_cfg.os {
438
        abi::OsWindows =>   InternedString::new("windows"),
M
Michael Neumann 已提交
439 440 441 442 443 444
        abi::OsMacos =>     InternedString::new("macos"),
        abi::OsLinux =>     InternedString::new("linux"),
        abi::OsAndroid =>   InternedString::new("android"),
        abi::OsFreebsd =>   InternedString::new("freebsd"),
        abi::OsDragonfly => InternedString::new("dragonfly"),
        abi::OsiOS =>       InternedString::new("ios"),
N
Nick Cameron 已提交
445 446 447 448 449 450 451 452
    };

    // ARM is bi-endian, however using NDK seems to default
    // to little-endian unless a flag is provided.
    let (end,arch,wordsz) = match sess.targ_cfg.arch {
        abi::X86 =>    ("little", "x86",    "32"),
        abi::X86_64 => ("little", "x86_64", "64"),
        abi::Arm =>    ("little", "arm",    "32"),
453 454
        abi::Mips =>   ("big",    "mips",   "32"),
        abi::Mipsel => ("little", "mipsel", "32")
N
Nick Cameron 已提交
455 456 457
    };

    let fam = match sess.targ_cfg.os {
458
        abi::OsWindows => InternedString::new("windows"),
N
Nick Cameron 已提交
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
        _ => InternedString::new("unix")
    };

    let mk = attr::mk_name_value_item_str;
    return vec!(// Target bindings.
         attr::mk_word_item(fam.clone()),
         mk(InternedString::new("target_os"), tos),
         mk(InternedString::new("target_family"), fam),
         mk(InternedString::new("target_arch"), InternedString::new(arch)),
         mk(InternedString::new("target_endian"), InternedString::new(end)),
         mk(InternedString::new("target_word_size"),
            InternedString::new(wordsz))
    );
}

pub fn append_configuration(cfg: &mut ast::CrateConfig,
                            name: InternedString) {
    if !cfg.iter().any(|mi| mi.name() == name) {
        cfg.push(attr::mk_word_item(name))
    }
}

pub fn build_configuration(sess: &Session) -> ast::CrateConfig {
    // Combine the configuration requested by the session (command line) with
    // some default and generated configuration items
    let default_cfg = default_configuration(sess);
    let mut user_cfg = sess.opts.cfg.clone();
    // If the user wants a test runner, then add the test cfg
    if sess.opts.test {
        append_configuration(&mut user_cfg, InternedString::new("test"))
    }
490 491 492
    let mut v = user_cfg.into_iter().collect::<Vec<_>>();
    v.push_all(default_cfg.as_slice());
    v
N
Nick Cameron 已提交
493 494 495 496 497 498 499 500
}

pub fn get_os(triple: &str) -> Option<abi::Os> {
    for &(name, os) in os_names.iter() {
        if triple.contains(name) { return Some(os) }
    }
    None
}
A
Aaron Turon 已提交
501
#[allow(non_upper_case_globals)]
502
static os_names : &'static [(&'static str, abi::Os)] = &[
503 504
    ("mingw32",   abi::OsWindows),
    ("win32",     abi::OsWindows),
505
    ("windows",   abi::OsWindows),
M
Michael Neumann 已提交
506 507 508 509 510 511
    ("darwin",    abi::OsMacos),
    ("android",   abi::OsAndroid),
    ("linux",     abi::OsLinux),
    ("freebsd",   abi::OsFreebsd),
    ("dragonfly", abi::OsDragonfly),
    ("ios",       abi::OsiOS)];
N
Nick Cameron 已提交
512 513 514 515 516 517 518

pub fn get_arch(triple: &str) -> Option<abi::Architecture> {
    for &(arch, abi) in architecture_abis.iter() {
        if triple.contains(arch) { return Some(abi) }
    }
    None
}
A
Aaron Turon 已提交
519
#[allow(non_upper_case_globals)]
520
static architecture_abis : &'static [(&'static str, abi::Architecture)] = &[
N
Nick Cameron 已提交
521 522 523 524 525 526 527 528 529 530 531 532
    ("i386",   abi::X86),
    ("i486",   abi::X86),
    ("i586",   abi::X86),
    ("i686",   abi::X86),
    ("i786",   abi::X86),

    ("x86_64", abi::X86_64),

    ("arm",    abi::Arm),
    ("xscale", abi::Arm),
    ("thumb",  abi::Arm),

533
    ("mipsel", abi::Mipsel),
N
Nick Cameron 已提交
534 535 536
    ("mips",   abi::Mips)];

pub fn build_target_config(sopts: &Options) -> Config {
537
    let os = match get_os(sopts.target_triple.as_slice()) {
N
Nick Cameron 已提交
538 539 540
      Some(os) => os,
      None => early_error("unknown operating system")
    };
541
    let arch = match get_arch(sopts.target_triple.as_slice()) {
N
Nick Cameron 已提交
542
      Some(arch) => arch,
543
      None => {
544 545
          early_error(format!("unknown architecture: {}",
                              sopts.target_triple.as_slice()).as_slice())
546
      }
N
Nick Cameron 已提交
547 548 549 550 551
    };
    let (int_type, uint_type) = match arch {
      abi::X86 => (ast::TyI32, ast::TyU32),
      abi::X86_64 => (ast::TyI64, ast::TyU64),
      abi::Arm => (ast::TyI32, ast::TyU32),
552 553
      abi::Mips => (ast::TyI32, ast::TyU32),
      abi::Mipsel => (ast::TyI32, ast::TyU32)
N
Nick Cameron 已提交
554 555 556 557 558 559
    };
    let target_triple = sopts.target_triple.clone();
    let target_strs = match arch {
      abi::X86 => x86::get_target_strs(target_triple, os),
      abi::X86_64 => x86_64::get_target_strs(target_triple, os),
      abi::Arm => arm::get_target_strs(target_triple, os),
560 561
      abi::Mips => mips::get_target_strs(target_triple, os),
      abi::Mipsel => mipsel::get_target_strs(target_triple, os)
N
Nick Cameron 已提交
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582
    };
    Config {
        os: os,
        arch: arch,
        target_strs: target_strs,
        int_type: int_type,
        uint_type: uint_type,
    }
}

// rustc command line options
pub fn optgroups() -> Vec<getopts::OptGroup> {
    vec!(
        optflag("h", "help", "Display this message"),
        optmulti("", "cfg", "Configure the compilation environment", "SPEC"),
        optmulti("L", "",   "Add a directory to the library search path", "PATH"),
        optmulti("", "crate-type", "Comma separated list of types of crates
                                    for the compiler to emit",
                 "[bin|lib|rlib|dylib|staticlib]"),
        optmulti("", "emit", "Comma separated list of types of output for the compiler to emit",
                 "[asm|bc|ir|obj|link]"),
583 584 585 586
        optopt("", "crate-name", "Specify the name of the crate being built",
               "NAME"),
        optflag("", "print-crate-name", "Output the crate name and exit"),
        optflag("", "print-file-name", "Output the file(s) that would be written if compilation \
N
Nick Cameron 已提交
587
              continued and exit"),
588
        optflag("", "crate-file-name", "deprecated in favor of --print-file-name"),
N
Nick Cameron 已提交
589 590 591 592 593 594 595 596 597 598 599 600 601
        optflag("g",  "",  "Equivalent to --debuginfo=2"),
        optopt("",  "debuginfo",  "Emit DWARF debug info to the objects created:
             0 = no debug info,
             1 = line-tables only (for stacktraces and breakpoints),
             2 = full debug info with variable and type information (same as -g)", "LEVEL"),
        optflag("", "no-trans", "Run all passes except translation; no output"),
        optflag("", "no-analysis",
              "Parse and expand the source, but run no analysis and produce no output"),
        optflag("O", "", "Equivalent to --opt-level=2"),
        optopt("o", "", "Write output to <filename>", "FILENAME"),
        optopt("", "opt-level", "Optimize with possible levels 0-3", "LEVEL"),
        optopt( "",  "out-dir", "Write output to compiler-chosen filename in <dir>", "DIR"),
        optflag("", "parse-only", "Parse only; do not compile, assemble, or link"),
602
        optopt("", "explain", "Provide a detailed explanation of an error message", "OPT"),
N
Nick Cameron 已提交
603
        optflagopt("", "pretty",
604 605 606 607 608 609 610
                   "Pretty-print the input instead of compiling;
                   valid types are: `normal` (un-annotated source),
                   `expanded` (crates expanded),
                   `typed` (crates expanded, with type annotations),
                   `expanded,identified` (fully parenthesized, AST nodes with IDs), or
                   `flowgraph=<nodeid>` (graphviz formatted flowgraph for node)",
                 "TYPE"),
N
Nick Cameron 已提交
611 612 613 614 615 616 617 618 619 620 621 622 623 624
        optflagopt("", "dep-info",
                 "Output dependency info to <filename> after compiling, \
                  in a format suitable for use by Makefiles", "FILENAME"),
        optopt("", "sysroot", "Override the system root", "PATH"),
        optflag("", "test", "Build a test harness"),
        optopt("", "target", "Target triple cpu-manufacturer-kernel[-os]
                            to compile for (see chapter 3.4 of http://www.sourceware.org/autobook/
                            for details)", "TRIPLE"),
        optmulti("W", "warn", "Set lint warnings", "OPT"),
        optmulti("A", "allow", "Set lint allowed", "OPT"),
        optmulti("D", "deny", "Set lint denied", "OPT"),
        optmulti("F", "forbid", "Set lint forbidden", "OPT"),
        optmulti("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
        optmulti("Z", "", "Set internal debugging options", "FLAG"),
625
        optflagopt("v", "version", "Print version info and exit", "verbose"),
626 627 628
        optopt("", "color", "Configure coloring of output:
            auto   = colorize, if output goes to a tty (default);
            always = always colorize output;
629 630
            never  = never colorize output", "auto|always|never"),
        optmulti("", "extern", "Specify where an external rust library is located",
631
                 "NAME=PATH"),
N
Nick Cameron 已提交
632 633 634 635 636
    )
}


// Convert strings provided as --cfg [cfgspec] into a crate_cfg
S
Steven Fackler 已提交
637
pub fn parse_cfgspecs(cfgspecs: Vec<String> ) -> ast::CrateConfig {
A
Aaron Turon 已提交
638
    cfgspecs.into_iter().map(|s| {
639 640
        parse::parse_meta_from_source_str("cfgspec".to_string(),
                                          s.to_string(),
N
Nick Cameron 已提交
641 642 643 644 645 646
                                          Vec::new(),
                                          &parse::new_parse_sess())
    }).collect::<ast::CrateConfig>()
}

pub fn build_session_options(matches: &getopts::Matches) -> Options {
647

N
Nick Cameron 已提交
648
    let unparsed_crate_types = matches.opt_strs("crate-type");
649 650
    let crate_types = parse_crate_types_from_list(unparsed_crate_types)
        .unwrap_or_else(|e| early_error(e.as_slice()));
N
Nick Cameron 已提交
651 652 653 654 655

    let parse_only = matches.opt_present("parse-only");
    let no_trans = matches.opt_present("no-trans");
    let no_analysis = matches.opt_present("no-analysis");

656 657 658 659
    let mut lint_opts = vec!();
    let mut describe_lints = false;

    for &level in [lint::Allow, lint::Warn, lint::Deny, lint::Forbid].iter() {
A
Aaron Turon 已提交
660
        for lint_name in matches.opt_strs(level.as_str()).into_iter() {
661 662 663 664
            if lint_name.as_slice() == "help" {
                describe_lints = true;
            } else {
                lint_opts.push((lint_name.replace("-", "_").into_string(), level));
N
Nick Cameron 已提交
665 666 667 668 669 670 671 672 673 674 675
            }
        }
    }

    let mut debugging_opts = 0;
    let debug_flags = matches.opt_strs("Z");
    let debug_map = debugging_opts_map();
    for debug_flag in debug_flags.iter() {
        let mut this_bit = 0;
        for tuple in debug_map.iter() {
            let (name, bit) = match *tuple { (ref a, _, b) => (a, b) };
676 677 678 679
            if *name == debug_flag.as_slice() {
                this_bit = bit;
                break;
            }
N
Nick Cameron 已提交
680 681
        }
        if this_bit == 0 {
682 683
            early_error(format!("unknown debug flag: {}",
                                *debug_flag).as_slice())
N
Nick Cameron 已提交
684 685 686 687 688 689 690 691 692 693 694 695
        }
        debugging_opts |= this_bit;
    }

    if debugging_opts & DEBUG_LLVM != 0 {
        unsafe { llvm::LLVMSetDebug(1); }
    }

    let mut output_types = Vec::new();
    if !parse_only && !no_trans {
        let unparsed_output_types = matches.opt_strs("emit");
        for unparsed_output_type in unparsed_output_types.iter() {
696
            for part in unparsed_output_type.as_slice().split(',') {
N
Nick Cameron 已提交
697
                let output_type = match part.as_slice() {
698 699 700 701 702
                    "asm"  => write::OutputTypeAssembly,
                    "ir"   => write::OutputTypeLlvmAssembly,
                    "bc"   => write::OutputTypeBitcode,
                    "obj"  => write::OutputTypeObject,
                    "link" => write::OutputTypeExe,
703 704 705 706
                    _ => {
                        early_error(format!("unknown emission type: `{}`",
                                            part).as_slice())
                    }
N
Nick Cameron 已提交
707 708 709 710 711 712 713 714
                };
                output_types.push(output_type)
            }
        }
    };
    output_types.as_mut_slice().sort();
    output_types.dedup();
    if output_types.len() == 0 {
715
        output_types.push(write::OutputTypeExe);
N
Nick Cameron 已提交
716 717 718
    }

    let sysroot_opt = matches.opt_str("sysroot").map(|m| Path::new(m));
719 720
    let target = matches.opt_str("target").unwrap_or(
        driver::host_triple().to_string());
N
Nick Cameron 已提交
721
    let opt_level = {
C
Colin Davidson 已提交
722
        if matches.opt_present("O") {
N
Nick Cameron 已提交
723 724 725 726 727 728 729 730 731 732 733 734
            if matches.opt_present("opt-level") {
                early_error("-O and --opt-level both provided");
            }
            Default
        } else if matches.opt_present("opt-level") {
            match matches.opt_str("opt-level").as_ref().map(|s| s.as_slice()) {
                None      |
                Some("0") => No,
                Some("1") => Less,
                Some("2") => Default,
                Some("3") => Aggressive,
                Some(arg) => {
735 736 737
                    early_error(format!("optimization level needs to be \
                                         between 0-3 (instead was `{}`)",
                                        arg).as_slice());
N
Nick Cameron 已提交
738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756
                }
            }
        } else {
            No
        }
    };
    let gc = debugging_opts & GC != 0;
    let debuginfo = if matches.opt_present("g") {
        if matches.opt_present("debuginfo") {
            early_error("-g and --debuginfo both provided");
        }
        FullDebugInfo
    } else if matches.opt_present("debuginfo") {
        match matches.opt_str("debuginfo").as_ref().map(|s| s.as_slice()) {
            Some("0") => NoDebugInfo,
            Some("1") => LimitedDebugInfo,
            None      |
            Some("2") => FullDebugInfo,
            Some(arg) => {
757 758
                early_error(format!("debug info level needs to be between \
                                     0-2 (instead was `{}`)",
759
                                    arg).as_slice());
N
Nick Cameron 已提交
760 761 762 763 764 765 766 767 768 769
            }
        }
    } else {
        NoDebugInfo
    };

    let addl_lib_search_paths = matches.opt_strs("L").iter().map(|s| {
        Path::new(s.as_slice())
    }).collect();

770
    let cfg = parse_cfgspecs(matches.opt_strs("cfg"));
N
Nick Cameron 已提交
771 772
    let test = matches.opt_present("test");
    let write_dependency_info = (matches.opt_present("dep-info"),
773 774
                                 matches.opt_str("dep-info")
                                        .map(|p| Path::new(p)));
N
Nick Cameron 已提交
775

776 777
    let print_metas = (matches.opt_present("print-crate-name"),
                       matches.opt_present("print-file-name") ||
N
Nick Cameron 已提交
778
                       matches.opt_present("crate-file-name"));
779 780 781 782
    if matches.opt_present("crate-file-name") {
        early_warn("the --crate-file-name argument has been renamed to \
                    --print-file-name");
    }
783
    let cg = build_codegen_options(matches);
N
Nick Cameron 已提交
784

785 786 787 788
    if !cg.remark.is_empty() && debuginfo == NoDebugInfo {
        early_warn("-C remark will not show source locations without --debuginfo");
    }

789 790 791 792 793 794 795
    let color = match matches.opt_str("color").as_ref().map(|s| s.as_slice()) {
        Some("auto")   => Auto,
        Some("always") => Always,
        Some("never")  => Never,

        None => Auto,

796 797 798 799 800
        Some(arg) => {
            early_error(format!("argument for --color must be auto, always \
                                 or never (instead was `{}`)",
                                arg).as_slice())
        }
801 802
    };

803 804
    let mut externs = HashMap::new();
    for arg in matches.opt_strs("extern").iter() {
805
        let mut parts = arg.as_slice().splitn(1, '=');
806 807 808 809 810 811 812 813
        let name = match parts.next() {
            Some(s) => s,
            None => early_error("--extern value must not be empty"),
        };
        let location = match parts.next() {
            Some(s) => s,
            None => early_error("--extern value must be of the format `foo=bar`"),
        };
814 815 816 817 818

        match externs.entry(name.to_string()) {
            Vacant(entry) => { entry.set(vec![location.to_string()]); },
            Occupied(mut entry) => { entry.get_mut().push(location.to_string()); },
        }
819 820
    }

821 822
    let crate_name = matches.opt_str("crate-name");

N
Nick Cameron 已提交
823 824 825 826 827 828
    Options {
        crate_types: crate_types,
        gc: gc,
        optimize: opt_level,
        debuginfo: debuginfo,
        lint_opts: lint_opts,
829
        describe_lints: describe_lints,
N
Nick Cameron 已提交
830 831 832 833 834 835 836 837 838 839 840 841 842
        output_types: output_types,
        addl_lib_search_paths: RefCell::new(addl_lib_search_paths),
        maybe_sysroot: sysroot_opt,
        target_triple: target,
        cfg: cfg,
        test: test,
        parse_only: parse_only,
        no_trans: no_trans,
        no_analysis: no_analysis,
        debugging_opts: debugging_opts,
        write_dependency_info: write_dependency_info,
        print_metas: print_metas,
        cg: cg,
843 844
        color: color,
        externs: externs,
845
        crate_name: crate_name,
846
        alt_std_name: None
N
Nick Cameron 已提交
847 848 849
    }
}

B
Brian Anderson 已提交
850
pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
851 852

    let mut crate_types: Vec<CrateType> = Vec::new();
B
Brian Anderson 已提交
853
    for unparsed_crate_type in list_list.iter() {
854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872
        for part in unparsed_crate_type.as_slice().split(',') {
            let new_part = match part {
                "lib"       => default_lib_output(),
                "rlib"      => CrateTypeRlib,
                "staticlib" => CrateTypeStaticlib,
                "dylib"     => CrateTypeDylib,
                "bin"       => CrateTypeExecutable,
                _ => {
                    return Err(format!("unknown crate type: `{}`",
                                       part));
                }
            };
            crate_types.push(new_part)
        }
    }

    return Ok(crate_types);
}

873 874 875 876 877 878 879 880 881 882
impl fmt::Show for CrateType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CrateTypeExecutable => "bin".fmt(f),
            CrateTypeDylib => "dylib".fmt(f),
            CrateTypeRlib => "rlib".fmt(f),
            CrateTypeStaticlib => "staticlib".fmt(f)
        }
    }
}
N
Nick Cameron 已提交
883 884 885 886 887 888 889 890 891 892

#[cfg(test)]
mod test {

    use driver::config::{build_configuration, optgroups, build_session_options};
    use driver::session::build_session;

    use getopts::getopts;
    use syntax::attr;
    use syntax::attr::AttrMetaMethods;
893
    use syntax::diagnostics;
N
Nick Cameron 已提交
894 895 896 897 898

    // When the user supplies --test we should implicitly supply --cfg test
    #[test]
    fn test_switch_implies_cfg_test() {
        let matches =
899
            &match getopts(["--test".to_string()], optgroups().as_slice()) {
N
Nick Cameron 已提交
900
              Ok(m) => m,
S
Steve Klabnik 已提交
901
              Err(f) => panic!("test_switch_implies_cfg_test: {}", f)
N
Nick Cameron 已提交
902
            };
903
        let registry = diagnostics::registry::Registry::new([]);
N
Nick Cameron 已提交
904
        let sessopts = build_session_options(matches);
905
        let sess = build_session(sessopts, None, registry);
N
Nick Cameron 已提交
906 907 908 909 910 911 912 913 914
        let cfg = build_configuration(&sess);
        assert!((attr::contains_name(cfg.as_slice(), "test")));
    }

    // When the user supplies --test and --cfg test, don't implicitly add
    // another --cfg test
    #[test]
    fn test_switch_implies_cfg_test_unless_cfg_test() {
        let matches =
915
            &match getopts(["--test".to_string(), "--cfg=test".to_string()],
N
Nick Cameron 已提交
916 917 918
                           optgroups().as_slice()) {
              Ok(m) => m,
              Err(f) => {
S
Steve Klabnik 已提交
919
                panic!("test_switch_implies_cfg_test_unless_cfg_test: {}", f)
N
Nick Cameron 已提交
920 921
              }
            };
922
        let registry = diagnostics::registry::Registry::new([]);
N
Nick Cameron 已提交
923
        let sessopts = build_session_options(matches);
924
        let sess = build_session(sessopts, None, registry);
N
Nick Cameron 已提交
925 926 927 928 929 930
        let cfg = build_configuration(&sess);
        let mut test_items = cfg.iter().filter(|m| m.name().equiv(&("test")));
        assert!(test_items.next().is_some());
        assert!(test_items.next().is_none());
    }
}