config.rs 33.7 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::hashmap::{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 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
pub enum CrateType {
    CrateTypeExecutable,
    CrateTypeDylib,
    CrateTypeRlib,
    CrateTypeStaticlib,
}

macro_rules! debugging_opts(
    ([ $opt:ident ] $cnt:expr ) => (
        pub static $opt: u64 = 1 << $cnt;
    );
    ([ $opt:ident, $($rest:ident),* ] $cnt:expr ) => (
        pub static $opt: u64 = 1 << $cnt;
        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 271 272 273 274 275
/// 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;
    pub static CG_OPTIONS: &'static [(&'static str, CodegenSetter,
                                      &'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\")"),
N
Nick Cameron 已提交
393 394 395 396 397
)

pub fn build_codegen_options(matches: &getopts::Matches) -> CodegenOptions
{
    let mut cg = basic_codegen_options();
A
Aaron Turon 已提交
398
    for option in matches.opt_strs("C").into_iter() {
399
        let mut iter = option.as_slice().splitn(1, '=');
N
Nick Cameron 已提交
400 401 402 403 404 405 406 407
        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 {
408 409 410 411 412 413 414 415 416
                    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 已提交
417 418 419 420 421 422
                }
            }
            found = true;
            break;
        }
        if !found {
423 424
            early_error(format!("unknown codegen option: `{}`",
                                key).as_slice());
N
Nick Cameron 已提交
425 426 427 428 429 430 431 432 433 434 435
        }
    }
    return cg;
}

pub fn default_lib_output() -> CrateType {
    CrateTypeRlib
}

pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
    let tos = match sess.targ_cfg.os {
436
        abi::OsWindows =>   InternedString::new("windows"),
M
Michael Neumann 已提交
437 438 439 440 441 442
        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 已提交
443 444 445 446 447 448 449 450
    };

    // 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"),
451 452
        abi::Mips =>   ("big",    "mips",   "32"),
        abi::Mipsel => ("little", "mipsel", "32")
N
Nick Cameron 已提交
453 454 455
    };

    let fam = match sess.targ_cfg.os {
456
        abi::OsWindows => InternedString::new("windows"),
N
Nick Cameron 已提交
457 458 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
        _ => 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"))
    }
A
Aaron Turon 已提交
488
    user_cfg.into_iter().collect::<Vec<_>>().append(default_cfg.as_slice())
N
Nick Cameron 已提交
489 490 491 492 493 494 495 496
}

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

pub fn get_arch(triple: &str) -> Option<abi::Architecture> {
    for &(arch, abi) in architecture_abis.iter() {
        if triple.contains(arch) { return Some(abi) }
    }
    None
}
515
#[allow(non_uppercase_statics)]
516
static architecture_abis : &'static [(&'static str, abi::Architecture)] = &[
N
Nick Cameron 已提交
517 518 519 520 521 522 523 524 525 526 527 528
    ("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),

529
    ("mipsel", abi::Mipsel),
N
Nick Cameron 已提交
530 531 532
    ("mips",   abi::Mips)];

pub fn build_target_config(sopts: &Options) -> Config {
533
    let os = match get_os(sopts.target_triple.as_slice()) {
N
Nick Cameron 已提交
534 535 536
      Some(os) => os,
      None => early_error("unknown operating system")
    };
537
    let arch = match get_arch(sopts.target_triple.as_slice()) {
N
Nick Cameron 已提交
538
      Some(arch) => arch,
539
      None => {
540 541
          early_error(format!("unknown architecture: {}",
                              sopts.target_triple.as_slice()).as_slice())
542
      }
N
Nick Cameron 已提交
543 544 545 546 547
    };
    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),
548 549
      abi::Mips => (ast::TyI32, ast::TyU32),
      abi::Mipsel => (ast::TyI32, ast::TyU32)
N
Nick Cameron 已提交
550 551 552 553 554 555
    };
    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),
556 557
      abi::Mips => mips::get_target_strs(target_triple, os),
      abi::Mipsel => mipsel::get_target_strs(target_triple, os)
N
Nick Cameron 已提交
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
    };
    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]"),
579 580 581 582
        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 已提交
583
              continued and exit"),
584
        optflag("", "crate-file-name", "deprecated in favor of --print-file-name"),
N
Nick Cameron 已提交
585 586 587 588 589 590 591 592 593 594 595 596 597
        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"),
598
        optopt("", "explain", "Provide a detailed explanation of an error message", "OPT"),
N
Nick Cameron 已提交
599
        optflagopt("", "pretty",
600 601 602 603 604 605 606
                   "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 已提交
607 608 609 610 611 612 613 614 615 616 617 618 619 620
        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"),
621
        optflagopt("v", "version", "Print version info and exit", "verbose"),
622 623 624
        optopt("", "color", "Configure coloring of output:
            auto   = colorize, if output goes to a tty (default);
            always = always colorize output;
625 626
            never  = never colorize output", "auto|always|never"),
        optmulti("", "extern", "Specify where an external rust library is located",
627
                 "NAME=PATH"),
N
Nick Cameron 已提交
628 629 630 631 632
    )
}


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

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

N
Nick Cameron 已提交
644
    let unparsed_crate_types = matches.opt_strs("crate-type");
645 646
    let crate_types = parse_crate_types_from_list(unparsed_crate_types)
        .unwrap_or_else(|e| early_error(e.as_slice()));
N
Nick Cameron 已提交
647 648 649 650 651

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

652 653 654 655
    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 已提交
656
        for lint_name in matches.opt_strs(level.as_str()).into_iter() {
657 658 659 660
            if lint_name.as_slice() == "help" {
                describe_lints = true;
            } else {
                lint_opts.push((lint_name.replace("-", "_").into_string(), level));
N
Nick Cameron 已提交
661 662 663 664 665 666 667 668 669 670 671
            }
        }
    }

    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) };
672 673 674 675
            if *name == debug_flag.as_slice() {
                this_bit = bit;
                break;
            }
N
Nick Cameron 已提交
676 677
        }
        if this_bit == 0 {
678 679
            early_error(format!("unknown debug flag: {}",
                                *debug_flag).as_slice())
N
Nick Cameron 已提交
680 681 682 683 684 685 686 687 688 689 690 691
        }
        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() {
692
            for part in unparsed_output_type.as_slice().split(',') {
N
Nick Cameron 已提交
693
                let output_type = match part.as_slice() {
694 695 696 697 698
                    "asm"  => write::OutputTypeAssembly,
                    "ir"   => write::OutputTypeLlvmAssembly,
                    "bc"   => write::OutputTypeBitcode,
                    "obj"  => write::OutputTypeObject,
                    "link" => write::OutputTypeExe,
699 700 701 702
                    _ => {
                        early_error(format!("unknown emission type: `{}`",
                                            part).as_slice())
                    }
N
Nick Cameron 已提交
703 704 705 706 707 708 709 710
                };
                output_types.push(output_type)
            }
        }
    };
    output_types.as_mut_slice().sort();
    output_types.dedup();
    if output_types.len() == 0 {
711
        output_types.push(write::OutputTypeExe);
N
Nick Cameron 已提交
712 713 714
    }

    let sysroot_opt = matches.opt_str("sysroot").map(|m| Path::new(m));
715 716
    let target = matches.opt_str("target").unwrap_or(
        driver::host_triple().to_string());
N
Nick Cameron 已提交
717
    let opt_level = {
C
Colin Davidson 已提交
718
        if matches.opt_present("O") {
N
Nick Cameron 已提交
719 720 721 722 723 724 725 726 727 728 729 730
            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) => {
731 732 733
                    early_error(format!("optimization level needs to be \
                                         between 0-3 (instead was `{}`)",
                                        arg).as_slice());
N
Nick Cameron 已提交
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
                }
            }
        } 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) => {
753 754
                early_error(format!("debug info level needs to be between \
                                     0-2 (instead was `{}`)",
755
                                    arg).as_slice());
N
Nick Cameron 已提交
756 757 758 759 760 761 762 763 764 765
            }
        }
    } else {
        NoDebugInfo
    };

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

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

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

781 782 783 784
    if !cg.remark.is_empty() && debuginfo == NoDebugInfo {
        early_warn("-C remark will not show source locations without --debuginfo");
    }

785 786 787 788 789 790 791
    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,

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

799 800
    let mut externs = HashMap::new();
    for arg in matches.opt_strs("extern").iter() {
801
        let mut parts = arg.as_slice().splitn(1, '=');
802 803 804 805 806 807 808 809
        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`"),
        };
810 811 812 813 814

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

817 818
    let crate_name = matches.opt_str("crate-name");

N
Nick Cameron 已提交
819 820 821 822 823 824
    Options {
        crate_types: crate_types,
        gc: gc,
        optimize: opt_level,
        debuginfo: debuginfo,
        lint_opts: lint_opts,
825
        describe_lints: describe_lints,
N
Nick Cameron 已提交
826 827 828 829 830 831 832 833 834 835 836 837 838
        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,
839 840
        color: color,
        externs: externs,
841
        crate_name: crate_name,
842
        alt_std_name: None
N
Nick Cameron 已提交
843 844 845
    }
}

B
Brian Anderson 已提交
846
pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
847 848

    let mut crate_types: Vec<CrateType> = Vec::new();
B
Brian Anderson 已提交
849
    for unparsed_crate_type in list_list.iter() {
850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868
        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);
}

869 870 871 872 873 874 875 876 877 878
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 已提交
879 880 881 882 883 884 885 886 887 888

#[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;
889
    use syntax::diagnostics;
N
Nick Cameron 已提交
890 891 892 893 894

    // When the user supplies --test we should implicitly supply --cfg test
    #[test]
    fn test_switch_implies_cfg_test() {
        let matches =
895
            &match getopts(["--test".to_string()], optgroups().as_slice()) {
N
Nick Cameron 已提交
896
              Ok(m) => m,
897
              Err(f) => fail!("test_switch_implies_cfg_test: {}", f)
N
Nick Cameron 已提交
898
            };
899
        let registry = diagnostics::registry::Registry::new([]);
N
Nick Cameron 已提交
900
        let sessopts = build_session_options(matches);
901
        let sess = build_session(sessopts, None, registry);
N
Nick Cameron 已提交
902 903 904 905 906 907 908 909 910
        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 =
911
            &match getopts(["--test".to_string(), "--cfg=test".to_string()],
N
Nick Cameron 已提交
912 913 914
                           optgroups().as_slice()) {
              Ok(m) => m,
              Err(f) => {
915
                fail!("test_switch_implies_cfg_test_unless_cfg_test: {}", f)
N
Nick Cameron 已提交
916 917
              }
            };
918
        let registry = diagnostics::registry::Registry::new([]);
N
Nick Cameron 已提交
919
        let sessopts = build_session_options(matches);
920
        let sess = build_session(sessopts, None, registry);
N
Nick Cameron 已提交
921 922 923 924 925 926
        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());
    }
}