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.
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.
11 //! Contains infrastructure for configuring the compiler, including parsing
12 //! command line options.
14 pub use self::EntryFnType
::*;
15 pub use self::CrateType
::*;
16 pub use self::Passes
::*;
17 pub use self::OptLevel
::*;
18 pub use self::OutputType
::*;
19 pub use self::DebugInfoLevel
::*;
21 use session
::{early_error, early_warn, Session}
;
22 use session
::search_paths
::SearchPaths
;
24 use rustc_back
::target
::Target
;
29 use syntax
::ast
::{IntTy, UintTy}
;
31 use syntax
::attr
::AttrMetaMethods
;
32 use syntax
::diagnostic
::{ColorConfig, Auto, Always, Never, SpanHandler}
;
34 use syntax
::parse
::token
::InternedString
;
35 use syntax
::feature_gate
::UnstableFeatures
;
38 use std
::collections
::HashMap
;
41 use std
::path
::PathBuf
;
48 pub uint_type
: UintTy
,
51 #[derive(Clone, Copy, PartialEq)]
59 #[derive(Clone, Copy, PartialEq)]
60 pub enum DebugInfoLevel
{
66 #[derive(Clone, Copy, PartialEq, PartialOrd, Ord, Eq)]
70 OutputTypeLlvmAssembly
,
78 // The crate config requested for the session, which may be combined
79 // with additional crate configurations during the compile process
80 pub crate_types
: Vec
<CrateType
>,
83 pub optimize
: OptLevel
,
84 pub debug_assertions
: bool
,
85 pub debuginfo
: DebugInfoLevel
,
86 pub lint_opts
: Vec
<(String
, lint
::Level
)>,
87 pub describe_lints
: bool
,
88 pub output_types
: Vec
<OutputType
>,
89 // This was mutable for rustpkg, which updates search paths based on the
90 // parsed code. It remains mutable in case its replacements wants to use
92 pub search_paths
: SearchPaths
,
93 pub libs
: Vec
<(String
, cstore
::NativeLibraryKind
)>,
94 pub maybe_sysroot
: Option
<PathBuf
>,
95 pub target_triple
: String
,
96 // User-specified cfg meta items. The compiler itself will add additional
97 // items to the crate config, and during parsing the entire crate config
98 // will be added to the crate AST node. This should not be used for
99 // anything except building the full crate config prior to parsing.
100 pub cfg
: ast
::CrateConfig
,
102 pub parse_only
: bool
,
104 pub treat_err_as_bug
: bool
,
105 pub no_analysis
: bool
,
106 pub debugging_opts
: DebuggingOptions
,
107 /// Whether to write dependency files. It's (enabled, optional filename).
108 pub write_dependency_info
: (bool
, Option
<PathBuf
>),
109 pub prints
: Vec
<PrintRequest
>,
110 pub cg
: CodegenOptions
,
111 pub color
: ColorConfig
,
112 pub show_span
: Option
<String
>,
113 pub externs
: HashMap
<String
, Vec
<String
>>,
114 pub crate_name
: Option
<String
>,
115 /// An optional name to use as the crate for std during std injection,
116 /// written `extern crate std = "name"`. Default to "std". Used by
117 /// out-of-tree drivers.
118 pub alt_std_name
: Option
<String
>,
119 /// Indicates how the compiler should treat unstable features
120 pub unstable_features
: UnstableFeatures
123 #[derive(Clone, PartialEq, Eq)]
124 pub enum PrintRequest
{
131 /// Load source from file
133 /// The string is the source
138 pub fn filestem(&self) -> String
{
140 Input
::File(ref ifile
) => ifile
.file_stem().unwrap()
141 .to_str().unwrap().to_string(),
142 Input
::Str(_
) => "rust_out".to_string(),
148 pub struct OutputFilenames
{
149 pub out_directory
: PathBuf
,
150 pub out_filestem
: String
,
151 pub single_output_file
: Option
<PathBuf
>,
155 impl OutputFilenames
{
156 pub fn path(&self, flavor
: OutputType
) -> PathBuf
{
157 match self.single_output_file
{
158 Some(ref path
) => return path
.clone(),
161 self.temp_path(flavor
)
164 pub fn temp_path(&self, flavor
: OutputType
) -> PathBuf
{
165 let base
= self.out_directory
.join(&self.filestem());
167 OutputTypeBitcode
=> base
.with_extension("bc"),
168 OutputTypeAssembly
=> base
.with_extension("s"),
169 OutputTypeLlvmAssembly
=> base
.with_extension("ll"),
170 OutputTypeObject
=> base
.with_extension("o"),
171 OutputTypeDepInfo
=> base
.with_extension("d"),
172 OutputTypeExe
=> base
,
176 pub fn with_extension(&self, extension
: &str) -> PathBuf
{
177 self.out_directory
.join(&self.filestem()).with_extension(extension
)
180 pub fn filestem(&self) -> String
{
181 format
!("{}{}", self.out_filestem
, self.extra
)
185 pub fn host_triple() -> &'
static str {
186 // Get the host triple out of the build environment. This ensures that our
187 // idea of the host triple is the same as for the set of libraries we've
188 // actually built. We can't just take LLVM's host triple because they
189 // normalize all ix86 architectures to i386.
191 // Instead of grabbing the host triple (for the current host), we grab (at
192 // compile time) the target triple that this rustc is built with and
193 // calling that (at runtime) the host triple.
194 (option_env
!("CFG_COMPILER_HOST_TRIPLE")).
195 expect("CFG_COMPILER_HOST_TRIPLE")
198 /// Some reasonable defaults
199 pub fn basic_options() -> Options
{
201 crate_types
: Vec
::new(),
204 debuginfo
: NoDebugInfo
,
205 lint_opts
: Vec
::new(),
206 describe_lints
: false,
207 output_types
: Vec
::new(),
208 search_paths
: SearchPaths
::new(),
210 target_triple
: host_triple().to_string(),
215 treat_err_as_bug
: false,
217 debugging_opts
: basic_debugging_options(),
218 write_dependency_info
: (false, None
),
220 cg
: basic_codegen_options(),
223 externs
: HashMap
::new(),
227 unstable_features
: UnstableFeatures
::Disallow
,
228 debug_assertions
: true,
232 // The type of entry function, so
233 // users can have their own entry
234 // functions that don't start a
236 #[derive(Copy, Clone, PartialEq)]
237 pub enum EntryFnType
{
243 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug)]
253 SomePasses(Vec
<String
>),
258 pub fn is_empty(&self) -> bool
{
260 SomePasses(ref v
) => v
.is_empty(),
266 /// Declare a macro that will define all CodegenOptions/DebuggingOptions fields and parsers all
267 /// at once. The goal of this macro is to define an interface that can be
268 /// programmatically used by the option parser in order to initialize the struct
269 /// without hardcoding field names all over the place.
271 /// The goal is to invoke this macro once with the correct fields, and then this
272 /// macro generates all necessary code. The main gotcha of this macro is the
273 /// cgsetters module which is a bunch of generated code to parse an option into
274 /// its respective field in the struct. There are a few hand-written parsers for
275 /// parsing specific types of values in this module.
276 macro_rules
! options
{
277 ($struct_name
:ident
, $setter_name
:ident
, $defaultfn
:ident
,
278 $buildfn
:ident
, $prefix
:expr
, $outputname
:expr
,
279 $stat
:ident
, $mod_desc
:ident
, $mod_set
:ident
,
280 $
($opt
:ident
: $t
:ty
= ($init
:expr
, $parse
:ident
, $desc
:expr
)),* ,) =>
283 pub struct $struct_name { $(pub $opt: $t),* }
285 pub fn $
defaultfn() -> $struct_name
{
286 $struct_name { $($opt: $init),* }
289 pub fn $
buildfn(matches
: &getopts
::Matches
) -> $struct_name
291 let mut op
= $
defaultfn();
292 for option
in matches
.opt_strs($prefix
) {
293 let mut iter
= option
.splitn(2, '
='
);
294 let key
= iter
.next().unwrap();
295 let value
= iter
.next();
296 let option_to_lookup
= key
.replace("-", "_");
297 let mut found
= false;
298 for &(candidate
, setter
, opt_type_desc
, _
) in $stat
{
299 if option_to_lookup
!= candidate { continue }
300 if !setter(&mut op
, value
) {
301 match (value
, opt_type_desc
) {
302 (Some(..), None
) => {
303 early_error(&format
!("{} option `{}` takes no \
304 value", $outputname
, key
))
306 (None
, Some(type_desc
)) => {
307 early_error(&format
!("{0} option `{1}` requires \
308 {2} ({3} {1}=<value>)",
312 (Some(value
), Some(type_desc
)) => {
313 early_error(&format
!("incorrect value `{}` for {} \
314 option `{}` - {} was expected",
318 (None
, None
) => unreachable
!()
325 early_error(&format
!("unknown {} option: `{}`",
332 pub type $setter_name
= fn(&mut $struct_name
, v
: Option
<&str>) -> bool
;
333 pub const $stat
: &'
static [(&'
static str, $setter_name
,
334 Option
<&'
static str>, &'
static str)] =
335 &[ $
( (stringify
!($opt
), $mod_set
::$opt
, $mod_desc
::$parse
, $desc
) ),* ];
337 #[allow(non_upper_case_globals, dead_code)]
339 pub const parse_bool
: Option
<&'
static str> = None
;
340 pub const parse_opt_bool
: Option
<&'
static str> =
341 Some("one of: `y`, `yes`, `on`, `n`, `no`, or `off`");
342 pub const parse_string
: Option
<&'
static str> = Some("a string");
343 pub const parse_opt_string
: Option
<&'
static str> = Some("a string");
344 pub const parse_list
: Option
<&'
static str> = Some("a space-separated list of strings");
345 pub const parse_opt_list
: Option
<&'
static str> = Some("a space-separated list of strings");
346 pub const parse_uint
: Option
<&'
static str> = Some("a number");
347 pub const parse_passes
: Option
<&'
static str> =
348 Some("a space-separated list of passes, or `all`");
349 pub const parse_opt_uint
: Option
<&'
static str> =
355 use super::{$struct_name, Passes, SomePasses, AllPasses}
;
358 pub fn $
opt(cg
: &mut $struct_name
, v
: Option
<&str>) -> bool
{
359 $
parse(&mut cg
.$opt
, v
)
363 fn parse_bool(slot
: &mut bool
, v
: Option
<&str>) -> bool
{
366 None
=> { *slot = true; true }
370 fn parse_opt_bool(slot
: &mut Option
<bool
>, v
: Option
<&str>) -> bool
{
374 "n" | "no" | "off" => {
377 "y" | "yes" | "on" => {
380 _
=> { return false; }
385 None
=> { *slot = Some(true); true }
389 fn parse_opt_string(slot
: &mut Option
<String
>, v
: Option
<&str>) -> bool
{
391 Some(s
) => { *slot = Some(s.to_string()); true }
,
396 fn parse_string(slot
: &mut String
, v
: Option
<&str>) -> bool
{
398 Some(s
) => { *slot = s.to_string(); true }
,
403 fn parse_list(slot
: &mut Vec
<String
>, v
: Option
<&str>)
407 for s
in s
.split_whitespace() {
408 slot
.push(s
.to_string());
416 fn parse_opt_list(slot
: &mut Option
<Vec
<String
>>, v
: Option
<&str>)
420 let v
= s
.split_whitespace().map(|s
| s
.to_string()).collect();
428 fn parse_uint(slot
: &mut usize, v
: Option
<&str>) -> bool
{
429 match v
.and_then(|s
| s
.parse().ok()) {
430 Some(i
) => { *slot = i; true }
,
435 fn parse_opt_uint(slot
: &mut Option
<usize>, v
: Option
<&str>) -> bool
{
437 Some(s
) => { *slot = s.parse().ok(); slot.is_some() }
438 None
=> { *slot = None; true }
442 fn parse_passes(slot
: &mut Passes
, v
: Option
<&str>) -> bool
{
449 let mut passes
= vec
!();
450 if parse_list(&mut passes
, v
) {
451 *slot
= SomePasses(passes
);
462 options
! {CodegenOptions
, CodegenSetter
, basic_codegen_options
,
463 build_codegen_options
, "C", "codegen",
464 CG_OPTIONS
, cg_type_desc
, cgsetters
,
465 ar
: Option
<String
> = (None
, parse_opt_string
,
466 "tool to assemble archives with"),
467 linker
: Option
<String
> = (None
, parse_opt_string
,
468 "system linker to link outputs with"),
469 link_args
: Option
<Vec
<String
>> = (None
, parse_opt_list
,
470 "extra arguments to pass to the linker (space separated)"),
471 lto
: bool
= (false, parse_bool
,
472 "perform LLVM link-time optimizations"),
473 target_cpu
: Option
<String
> = (None
, parse_opt_string
,
474 "select target processor (llc -mcpu=help for details)"),
475 target_feature
: String
= ("".to_string(), parse_string
,
476 "target specific attributes (llc -mattr=help for details)"),
477 passes
: Vec
<String
> = (Vec
::new(), parse_list
,
478 "a list of extra LLVM passes to run (space separated)"),
479 llvm_args
: Vec
<String
> = (Vec
::new(), parse_list
,
480 "a list of arguments to pass to llvm (space separated)"),
481 save_temps
: bool
= (false, parse_bool
,
482 "save all temporary output files during compilation"),
483 rpath
: bool
= (false, parse_bool
,
484 "set rpath values in libs/exes"),
485 no_prepopulate_passes
: bool
= (false, parse_bool
,
486 "don't pre-populate the pass manager with a list of passes"),
487 no_vectorize_loops
: bool
= (false, parse_bool
,
488 "don't run the loop vectorization optimization passes"),
489 no_vectorize_slp
: bool
= (false, parse_bool
,
490 "don't run LLVM's SLP vectorization pass"),
491 soft_float
: bool
= (false, parse_bool
,
492 "generate software floating point library calls"),
493 prefer_dynamic
: bool
= (false, parse_bool
,
494 "prefer dynamic linking to static linking"),
495 no_integrated_as
: bool
= (false, parse_bool
,
496 "use an external assembler rather than LLVM's integrated one"),
497 no_redzone
: Option
<bool
> = (None
, parse_opt_bool
,
498 "disable the use of the redzone"),
499 relocation_model
: Option
<String
> = (None
, parse_opt_string
,
500 "choose the relocation model to use (llc -relocation-model for details)"),
501 code_model
: Option
<String
> = (None
, parse_opt_string
,
502 "choose the code model to use (llc -code-model for details)"),
503 metadata
: Vec
<String
> = (Vec
::new(), parse_list
,
504 "metadata to mangle symbol names with"),
505 extra_filename
: String
= ("".to_string(), parse_string
,
506 "extra data to put in each output filename"),
507 codegen_units
: usize = (1, parse_uint
,
508 "divide crate into N units to optimize in parallel"),
509 remark
: Passes
= (SomePasses(Vec
::new()), parse_passes
,
510 "print remarks for these optimization passes (space separated, or \"all\")"),
511 no_stack_check
: bool
= (false, parse_bool
,
512 "disable checks for stack exhaustion (a memory-safety hazard!)"),
513 debuginfo
: Option
<usize> = (None
, parse_opt_uint
,
514 "debug info emission level, 0 = no debug info, 1 = line tables only, \
515 2 = full debug info with variable and type information"),
516 opt_level
: Option
<usize> = (None
, parse_opt_uint
,
517 "Optimize with possible levels 0-3"),
518 debug_assertions
: Option
<bool
> = (None
, parse_opt_bool
,
519 "explicitly enable the cfg(debug_assertions) directive"),
523 options
! {DebuggingOptions
, DebuggingSetter
, basic_debugging_options
,
524 build_debugging_options
, "Z", "debugging",
525 DB_OPTIONS
, db_type_desc
, dbsetters
,
526 verbose
: bool
= (false, parse_bool
,
527 "in general, enable more debug printouts"),
528 time_passes
: bool
= (false, parse_bool
,
529 "measure time of each rustc pass"),
530 count_llvm_insns
: bool
= (false, parse_bool
,
531 "count where LLVM instrs originate"),
532 time_llvm_passes
: bool
= (false, parse_bool
,
533 "measure time of each LLVM pass"),
534 trans_stats
: bool
= (false, parse_bool
,
535 "gather trans statistics"),
536 asm_comments
: bool
= (false, parse_bool
,
537 "generate comments into the assembly (may change behavior)"),
538 no_verify
: bool
= (false, parse_bool
,
539 "skip LLVM verification"),
540 borrowck_stats
: bool
= (false, parse_bool
,
541 "gather borrowck statistics"),
542 no_landing_pads
: bool
= (false, parse_bool
,
543 "omit landing pads for unwinding"),
544 debug_llvm
: bool
= (false, parse_bool
,
545 "enable debug output from LLVM"),
546 count_type_sizes
: bool
= (false, parse_bool
,
547 "count the sizes of aggregate types"),
548 meta_stats
: bool
= (false, parse_bool
,
549 "gather metadata statistics"),
550 print_link_args
: bool
= (false, parse_bool
,
551 "Print the arguments passed to the linker"),
552 gc
: bool
= (false, parse_bool
,
553 "Garbage collect shared data (experimental)"),
554 print_llvm_passes
: bool
= (false, parse_bool
,
555 "Prints the llvm optimization passes being run"),
556 ast_json
: bool
= (false, parse_bool
,
557 "Print the AST as JSON and halt"),
558 ast_json_noexpand
: bool
= (false, parse_bool
,
559 "Print the pre-expansion AST as JSON and halt"),
560 ls
: bool
= (false, parse_bool
,
561 "List the symbols defined by a library crate"),
562 save_analysis
: bool
= (false, parse_bool
,
563 "Write syntax and type analysis information in addition to normal output"),
564 print_move_fragments
: bool
= (false, parse_bool
,
565 "Print out move-fragment data for every fn"),
566 flowgraph_print_loans
: bool
= (false, parse_bool
,
567 "Include loan analysis data in --pretty flowgraph output"),
568 flowgraph_print_moves
: bool
= (false, parse_bool
,
569 "Include move analysis data in --pretty flowgraph output"),
570 flowgraph_print_assigns
: bool
= (false, parse_bool
,
571 "Include assignment analysis data in --pretty flowgraph output"),
572 flowgraph_print_all
: bool
= (false, parse_bool
,
573 "Include all dataflow analysis data in --pretty flowgraph output"),
574 print_region_graph
: bool
= (false, parse_bool
,
575 "Prints region inference graph. \
576 Use with RUST_REGION_GRAPH=help for more info"),
577 parse_only
: bool
= (false, parse_bool
,
578 "Parse only; do not compile, assemble, or link"),
579 no_trans
: bool
= (false, parse_bool
,
580 "Run all passes except translation; no output"),
581 treat_err_as_bug
: bool
= (false, parse_bool
,
582 "Treat all errors that occur as bugs"),
583 no_analysis
: bool
= (false, parse_bool
,
584 "Parse and expand the source, but run no analysis"),
585 extra_plugins
: Vec
<String
> = (Vec
::new(), parse_list
,
586 "load extra plugins"),
587 unstable_options
: bool
= (false, parse_bool
,
588 "Adds unstable command line options to rustc interface"),
589 print_enum_sizes
: bool
= (false, parse_bool
,
590 "Print the size of enums and their variants"),
591 force_overflow_checks
: Option
<bool
> = (None
, parse_opt_bool
,
592 "Force overflow checks on or off"),
593 force_dropflag_checks
: Option
<bool
> = (None
, parse_opt_bool
,
594 "Force drop flag checks on or off"),
595 trace_macros
: bool
= (false, parse_bool
,
596 "For every macro invocation, print its name and arguments"),
599 pub fn default_lib_output() -> CrateType
{
603 pub fn default_configuration(sess
: &Session
) -> ast
::CrateConfig
{
604 use syntax
::parse
::token
::intern_and_get_ident
as intern
;
606 let end
= &sess
.target
.target
.target_endian
;
607 let arch
= &sess
.target
.target
.arch
;
608 let wordsz
= &sess
.target
.target
.target_pointer_width
;
609 let os
= &sess
.target
.target
.target_os
;
610 let env
= &sess
.target
.target
.target_env
;
612 let fam
= match sess
.target
.target
.options
.is_like_windows
{
613 true => InternedString
::new("windows"),
614 false => InternedString
::new("unix")
617 let mk
= attr
::mk_name_value_item_str
;
618 let mut ret
= vec
![ // Target bindings.
619 attr
::mk_word_item(fam
.clone()),
620 mk(InternedString
::new("target_os"), intern(os
)),
621 mk(InternedString
::new("target_family"), fam
),
622 mk(InternedString
::new("target_arch"), intern(arch
)),
623 mk(InternedString
::new("target_endian"), intern(end
)),
624 mk(InternedString
::new("target_pointer_width"), intern(wordsz
)),
625 mk(InternedString
::new("target_env"), intern(env
)),
627 if sess
.opts
.debug_assertions
{
628 ret
.push(attr
::mk_word_item(InternedString
::new("debug_assertions")));
633 pub fn append_configuration(cfg
: &mut ast
::CrateConfig
,
634 name
: InternedString
) {
635 if !cfg
.iter().any(|mi
| mi
.name() == name
) {
636 cfg
.push(attr
::mk_word_item(name
))
640 pub fn build_configuration(sess
: &Session
) -> ast
::CrateConfig
{
641 // Combine the configuration requested by the session (command line) with
642 // some default and generated configuration items
643 let default_cfg
= default_configuration(sess
);
644 let mut user_cfg
= sess
.opts
.cfg
.clone();
645 // If the user wants a test runner, then add the test cfg
647 append_configuration(&mut user_cfg
, InternedString
::new("test"))
649 let mut v
= user_cfg
.into_iter().collect
::<Vec
<_
>>();
650 v
.push_all(&default_cfg
[..]);
654 pub fn build_target_config(opts
: &Options
, sp
: &SpanHandler
) -> Config
{
655 let target
= match Target
::search(&opts
.target_triple
) {
658 sp
.handler().fatal(&format
!("Error loading target specification: {}", e
));
662 let (int_type
, uint_type
) = match &target
.target_pointer_width
[..] {
663 "32" => (ast
::TyI32
, ast
::TyU32
),
664 "64" => (ast
::TyI64
, ast
::TyU64
),
665 w
=> sp
.handler().fatal(&format
!("target specification was invalid: unrecognized \
666 target-pointer-width {}", w
))
672 uint_type
: uint_type
,
676 /// Returns the "short" subset of the stable rustc command line options.
677 pub fn short_optgroups() -> Vec
<getopts
::OptGroup
> {
678 rustc_short_optgroups().into_iter()
679 .filter(|g
|g
.is_stable())
684 /// Returns all of the stable rustc command line options.
685 pub fn optgroups() -> Vec
<getopts
::OptGroup
> {
686 rustc_optgroups().into_iter()
687 .filter(|g
|g
.is_stable())
692 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
693 pub enum OptionStability { Stable, Unstable }
695 #[derive(Clone, PartialEq, Eq)]
696 pub struct RustcOptGroup
{
697 pub opt_group
: getopts
::OptGroup
,
698 pub stability
: OptionStability
,
702 pub fn is_stable(&self) -> bool
{
703 self.stability
== OptionStability
::Stable
706 fn stable(g
: getopts
::OptGroup
) -> RustcOptGroup
{
707 RustcOptGroup { opt_group: g, stability: OptionStability::Stable }
710 fn unstable(g
: getopts
::OptGroup
) -> RustcOptGroup
{
711 RustcOptGroup { opt_group: g, stability: OptionStability::Unstable }
715 // The `opt` local module holds wrappers around the `getopts` API that
716 // adds extra rustc-specific metadata to each option; such metadata
717 // is exposed by . The public
718 // functions below ending with `_u` are the functions that return
719 // *unstable* options, i.e. options that are only enabled when the
720 // user also passes the `-Z unstable-options` debugging flag.
722 // The `fn opt_u` etc below are written so that we can use them
723 // in the future; do not warn about them not being used right now.
727 use super::RustcOptGroup
;
729 pub type R
= RustcOptGroup
;
730 pub type S
<'a
> = &'a
str;
732 fn stable(g
: getopts
::OptGroup
) -> R { RustcOptGroup::stable(g) }
733 fn unstable(g
: getopts
::OptGroup
) -> R { RustcOptGroup::unstable(g) }
735 // FIXME (pnkfelix): We default to stable since the current set of
736 // options is defacto stable. However, it would be good to revise the
737 // code so that a stable option is the thing that takes extra effort
740 pub fn opt(a
: S
, b
: S
, c
: S
, d
: S
) -> R { stable(getopts::optopt(a, b, c, d)) }
741 pub fn multi(a
: S
, b
: S
, c
: S
, d
: S
) -> R { stable(getopts::optmulti(a, b, c, d)) }
742 pub fn flag(a
: S
, b
: S
, c
: S
) -> R { stable(getopts::optflag(a, b, c)) }
743 pub fn flagopt(a
: S
, b
: S
, c
: S
, d
: S
) -> R { stable(getopts::optflagopt(a, b, c, d)) }
744 pub fn flagmulti(a
: S
, b
: S
, c
: S
) -> R { stable(getopts::optflagmulti(a, b, c)) }
747 pub fn opt_u(a
: S
, b
: S
, c
: S
, d
: S
) -> R { unstable(getopts::optopt(a, b, c, d)) }
748 pub fn multi_u(a
: S
, b
: S
, c
: S
, d
: S
) -> R { unstable(getopts::optmulti(a, b, c, d)) }
749 pub fn flag_u(a
: S
, b
: S
, c
: S
) -> R { unstable(getopts::optflag(a, b, c)) }
750 pub fn flagopt_u(a
: S
, b
: S
, c
: S
, d
: S
) -> R { unstable(getopts::optflagopt(a, b, c, d)) }
751 pub fn flagmulti_u(a
: S
, b
: S
, c
: S
) -> R { unstable(getopts::optflagmulti(a, b, c)) }
754 /// Returns the "short" subset of the rustc command line options,
755 /// including metadata for each option, such as whether the option is
756 /// part of the stable long-term interface for rustc.
757 pub fn rustc_short_optgroups() -> Vec
<RustcOptGroup
> {
759 opt
::flag("h", "help", "Display this message"),
760 opt
::multi("", "cfg", "Configure the compilation environment", "SPEC"),
761 opt
::multi("L", "", "Add a directory to the library search path",
763 opt
::multi("l", "", "Link the generated crate(s) to the specified native
764 library NAME. The optional KIND can be one of,
765 static, dylib, or framework. If omitted, dylib is
766 assumed.", "[KIND=]NAME"),
767 opt
::multi("", "crate-type", "Comma separated list of types of crates
768 for the compiler to emit",
769 "[bin|lib|rlib|dylib|staticlib]"),
770 opt
::opt("", "crate-name", "Specify the name of the crate being built",
772 opt
::multi("", "emit", "Comma separated list of types of output for \
773 the compiler to emit",
774 "[asm|llvm-bc|llvm-ir|obj|link|dep-info]"),
775 opt
::multi("", "print", "Comma separated list of compiler information to \
777 "[crate-name|file-names|sysroot]"),
778 opt
::flagmulti("g", "", "Equivalent to -C debuginfo=2"),
779 opt
::flagmulti("O", "", "Equivalent to -C opt-level=2"),
780 opt
::opt("o", "", "Write output to <filename>", "FILENAME"),
781 opt
::opt("", "out-dir", "Write output to compiler-chosen filename \
783 opt
::opt("", "explain", "Provide a detailed explanation of an error \
785 opt
::flag("", "test", "Build a test harness"),
786 opt
::opt("", "target", "Target triple cpu-manufacturer-kernel[-os] \
787 to compile for (see chapter 3.4 of \
788 http://www.sourceware.org/autobook/
791 opt
::multi("W", "warn", "Set lint warnings", "OPT"),
792 opt
::multi("A", "allow", "Set lint allowed", "OPT"),
793 opt
::multi("D", "deny", "Set lint denied", "OPT"),
794 opt
::multi("F", "forbid", "Set lint forbidden", "OPT"),
795 opt
::multi("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
796 opt
::flag("V", "version", "Print version info and exit"),
797 opt
::flag("v", "verbose", "Use verbose output"),
801 /// Returns all rustc command line options, including metadata for
802 /// each option, such as whether the option is part of the stable
803 /// long-term interface for rustc.
804 pub fn rustc_optgroups() -> Vec
<RustcOptGroup
> {
805 let mut opts
= rustc_short_optgroups();
807 opt
::multi("", "extern", "Specify where an external rust library is \
810 opt
::opt("", "sysroot", "Override the system root", "PATH"),
811 opt
::multi("Z", "", "Set internal debugging options", "FLAG"),
812 opt
::opt("", "color", "Configure coloring of output:
813 auto = colorize, if output goes to a tty (default);
814 always = always colorize output;
815 never = never colorize output", "auto|always|never"),
817 opt
::flagopt_u("", "pretty",
818 "Pretty-print the input instead of compiling;
819 valid types are: `normal` (un-annotated source),
820 `expanded` (crates expanded),
821 `typed` (crates expanded, with type annotations), or
822 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
824 opt
::flagopt_u("", "xpretty",
825 "Pretty-print the input instead of compiling, unstable variants;
826 valid types are any of the types for `--pretty`, as well as:
827 `flowgraph=<nodeid>` (graphviz formatted flowgraph for node), or
828 `everybody_loops` (all function bodies replaced with `loop {}`).",
830 opt
::opt_u("", "show-span", "Show spans for compiler debugging", "expr|pat|ty"),
835 // Convert strings provided as --cfg [cfgspec] into a crate_cfg
836 pub fn parse_cfgspecs(cfgspecs
: Vec
<String
> ) -> ast
::CrateConfig
{
837 cfgspecs
.into_iter().map(|s
| {
838 parse
::parse_meta_from_source_str("cfgspec".to_string(),
841 &parse
::ParseSess
::new())
842 }).collect
::<ast
::CrateConfig
>()
845 pub fn build_session_options(matches
: &getopts
::Matches
) -> Options
{
846 let unparsed_crate_types
= matches
.opt_strs("crate-type");
847 let crate_types
= parse_crate_types_from_list(unparsed_crate_types
)
848 .unwrap_or_else(|e
| early_error(&e
[..]));
850 let mut lint_opts
= vec
!();
851 let mut describe_lints
= false;
853 for &level
in &[lint
::Allow
, lint
::Warn
, lint
::Deny
, lint
::Forbid
] {
854 for lint_name
in matches
.opt_strs(level
.as_str()) {
855 if lint_name
== "help" {
856 describe_lints
= true;
858 lint_opts
.push((lint_name
.replace("-", "_"), level
));
863 let debugging_opts
= build_debugging_options(matches
);
865 let parse_only
= debugging_opts
.parse_only
;
866 let no_trans
= debugging_opts
.no_trans
;
867 let treat_err_as_bug
= debugging_opts
.treat_err_as_bug
;
868 let no_analysis
= debugging_opts
.no_analysis
;
870 if debugging_opts
.debug_llvm
{
871 unsafe { llvm::LLVMSetDebug(1); }
874 let mut output_types
= Vec
::new();
875 if !debugging_opts
.parse_only
&& !no_trans
{
876 let unparsed_output_types
= matches
.opt_strs("emit");
877 for unparsed_output_type
in &unparsed_output_types
{
878 for part
in unparsed_output_type
.split('
,'
) {
879 let output_type
= match part
{
880 "asm" => OutputTypeAssembly
,
881 "llvm-ir" => OutputTypeLlvmAssembly
,
882 "llvm-bc" => OutputTypeBitcode
,
883 "obj" => OutputTypeObject
,
884 "link" => OutputTypeExe
,
885 "dep-info" => OutputTypeDepInfo
,
887 early_error(&format
!("unknown emission type: `{}`",
891 output_types
.push(output_type
)
896 output_types
.dedup();
897 if output_types
.is_empty() {
898 output_types
.push(OutputTypeExe
);
901 let cg
= build_codegen_options(matches
);
903 let sysroot_opt
= matches
.opt_str("sysroot").map(|m
| PathBuf
::from(&m
));
904 let target
= matches
.opt_str("target").unwrap_or(
905 host_triple().to_string());
907 if matches
.opt_present("O") {
908 if cg
.opt_level
.is_some() {
909 early_error("-O and -C opt-level both provided");
918 Some(3) => Aggressive
,
920 early_error(&format
!("optimization level needs to be \
921 between 0-3 (instead was `{}`)",
927 let debug_assertions
= cg
.debug_assertions
.unwrap_or(opt_level
== No
);
928 let gc
= debugging_opts
.gc
;
929 let debuginfo
= if matches
.opt_present("g") {
930 if cg
.debuginfo
.is_some() {
931 early_error("-g and -C debuginfo both provided");
936 None
| Some(0) => NoDebugInfo
,
937 Some(1) => LimitedDebugInfo
,
938 Some(2) => FullDebugInfo
,
940 early_error(&format
!("debug info level needs to be between \
941 0-2 (instead was `{}`)",
947 let mut search_paths
= SearchPaths
::new();
948 for s
in &matches
.opt_strs("L") {
949 search_paths
.add_path(&s
[..]);
952 let libs
= matches
.opt_strs("l").into_iter().map(|s
| {
953 let mut parts
= s
.splitn(2, '
='
);
954 let kind
= parts
.next().unwrap();
955 let (name
, kind
) = match (parts
.next(), kind
) {
957 (Some(name
), "dylib") => (name
, cstore
::NativeUnknown
),
958 (Some(name
), "framework") => (name
, cstore
::NativeFramework
),
959 (Some(name
), "static") => (name
, cstore
::NativeStatic
),
961 early_error(&format
!("unknown library kind `{}`, expected \
962 one of dylib, framework, or static",
966 (name
.to_string(), kind
)
969 let cfg
= parse_cfgspecs(matches
.opt_strs("cfg"));
970 let test
= matches
.opt_present("test");
971 let write_dependency_info
= (output_types
.contains(&OutputTypeDepInfo
), None
);
973 let prints
= matches
.opt_strs("print").into_iter().map(|s
| {
975 "crate-name" => PrintRequest
::CrateName
,
976 "file-names" => PrintRequest
::FileNames
,
977 "sysroot" => PrintRequest
::Sysroot
,
979 early_error(&format
!("unknown print request `{}`", req
))
982 }).collect
::<Vec
<_
>>();
984 if !cg
.remark
.is_empty() && debuginfo
== NoDebugInfo
{
985 early_warn("-C remark will not show source locations without \
989 let color
= match matches
.opt_str("color").as_ref().map(|s
| &s
[..]) {
990 Some("auto") => Auto
,
991 Some("always") => Always
,
992 Some("never") => Never
,
997 early_error(&format
!("argument for --color must be auto, always \
998 or never (instead was `{}`)",
1003 let mut externs
= HashMap
::new();
1004 for arg
in &matches
.opt_strs("extern") {
1005 let mut parts
= arg
.splitn(2, '
='
);
1006 let name
= match parts
.next() {
1008 None
=> early_error("--extern value must not be empty"),
1010 let location
= match parts
.next() {
1012 None
=> early_error("--extern value must be of the format `foo=bar`"),
1015 externs
.entry(name
.to_string()).or_insert(vec
![]).push(location
.to_string());
1018 let crate_name
= matches
.opt_str("crate-name");
1021 crate_types
: crate_types
,
1023 optimize
: opt_level
,
1024 debuginfo
: debuginfo
,
1025 lint_opts
: lint_opts
,
1026 describe_lints
: describe_lints
,
1027 output_types
: output_types
,
1028 search_paths
: search_paths
,
1029 maybe_sysroot
: sysroot_opt
,
1030 target_triple
: target
,
1033 parse_only
: parse_only
,
1035 treat_err_as_bug
: treat_err_as_bug
,
1036 no_analysis
: no_analysis
,
1037 debugging_opts
: debugging_opts
,
1038 write_dependency_info
: write_dependency_info
,
1044 crate_name
: crate_name
,
1047 unstable_features
: get_unstable_features_setting(),
1048 debug_assertions
: debug_assertions
,
1052 pub fn get_unstable_features_setting() -> UnstableFeatures
{
1053 // Whether this is a feature-staged build, i.e. on the beta or stable channel
1054 let disable_unstable_features
= option_env
!("CFG_DISABLE_UNSTABLE_FEATURES").is_some();
1055 // The secret key needed to get through the rustc build itself by
1056 // subverting the unstable features lints
1057 let bootstrap_secret_key
= option_env
!("CFG_BOOTSTRAP_KEY");
1058 // The matching key to the above, only known by the build system
1059 let bootstrap_provided_key
= env
::var("RUSTC_BOOTSTRAP_KEY").ok();
1060 match (disable_unstable_features
, bootstrap_secret_key
, bootstrap_provided_key
) {
1061 (_
, Some(ref s
), Some(ref p
)) if s
== p
=> UnstableFeatures
::Cheat
,
1062 (true, _
, _
) => UnstableFeatures
::Disallow
,
1063 (false, _
, _
) => UnstableFeatures
::Allow
1067 pub fn parse_crate_types_from_list(list_list
: Vec
<String
>) -> Result
<Vec
<CrateType
>, String
> {
1069 let mut crate_types
: Vec
<CrateType
> = Vec
::new();
1070 for unparsed_crate_type
in &list_list
{
1071 for part
in unparsed_crate_type
.split('
,'
) {
1072 let new_part
= match part
{
1073 "lib" => default_lib_output(),
1074 "rlib" => CrateTypeRlib
,
1075 "staticlib" => CrateTypeStaticlib
,
1076 "dylib" => CrateTypeDylib
,
1077 "bin" => CrateTypeExecutable
,
1079 return Err(format
!("unknown crate type: `{}`",
1083 if !crate_types
.contains(&new_part
) {
1084 crate_types
.push(new_part
)
1089 return Ok(crate_types
);
1092 impl fmt
::Display
for CrateType
{
1093 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1095 CrateTypeExecutable
=> "bin".fmt(f
),
1096 CrateTypeDylib
=> "dylib".fmt(f
),
1097 CrateTypeRlib
=> "rlib".fmt(f
),
1098 CrateTypeStaticlib
=> "staticlib".fmt(f
)
1106 use session
::config
::{build_configuration, optgroups, build_session_options}
;
1107 use session
::build_session
;
1109 use getopts
::getopts
;
1111 use syntax
::attr
::AttrMetaMethods
;
1112 use syntax
::diagnostics
;
1114 // When the user supplies --test we should implicitly supply --cfg test
1116 fn test_switch_implies_cfg_test() {
1118 &match getopts(&["--test".to_string()], &optgroups()) {
1120 Err(f
) => panic
!("test_switch_implies_cfg_test: {}", f
)
1122 let registry
= diagnostics
::registry
::Registry
::new(&[]);
1123 let sessopts
= build_session_options(matches
);
1124 let sess
= build_session(sessopts
, None
, registry
);
1125 let cfg
= build_configuration(&sess
);
1126 assert
!((attr
::contains_name(&cfg
[..], "test")));
1129 // When the user supplies --test and --cfg test, don't implicitly add
1130 // another --cfg test
1132 fn test_switch_implies_cfg_test_unless_cfg_test() {
1134 &match getopts(&["--test".to_string(), "--cfg=test".to_string()],
1138 panic
!("test_switch_implies_cfg_test_unless_cfg_test: {}", f
)
1141 let registry
= diagnostics
::registry
::Registry
::new(&[]);
1142 let sessopts
= build_session_options(matches
);
1143 let sess
= build_session(sessopts
, None
, registry
);
1144 let cfg
= build_configuration(&sess
);
1145 let mut test_items
= cfg
.iter().filter(|m
| m
.name() == "test");
1146 assert
!(test_items
.next().is_some());
1147 assert
!(test_items
.next().is_none());
1151 fn test_can_print_warnings() {
1153 let matches
= getopts(&[
1154 "-Awarnings".to_string()
1155 ], &optgroups()).unwrap();
1156 let registry
= diagnostics
::registry
::Registry
::new(&[]);
1157 let sessopts
= build_session_options(&matches
);
1158 let sess
= build_session(sessopts
, None
, registry
);
1159 assert
!(!sess
.can_print_warnings
);
1163 let matches
= getopts(&[
1164 "-Awarnings".to_string(),
1165 "-Dwarnings".to_string()
1166 ], &optgroups()).unwrap();
1167 let registry
= diagnostics
::registry
::Registry
::new(&[]);
1168 let sessopts
= build_session_options(&matches
);
1169 let sess
= build_session(sessopts
, None
, registry
);
1170 assert
!(sess
.can_print_warnings
);
1174 let matches
= getopts(&[
1175 "-Adead_code".to_string()
1176 ], &optgroups()).unwrap();
1177 let registry
= diagnostics
::registry
::Registry
::new(&[]);
1178 let sessopts
= build_session_options(&matches
);
1179 let sess
= build_session(sessopts
, None
, registry
);
1180 assert
!(sess
.can_print_warnings
);