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 use driver::early_error;
16 use driver::session::Session;
20 use back::target_strs;
21 use back::{arm, x86, x86_64, mips, mipsel};
26 use syntax::ast::{IntTy, UintTy};
28 use syntax::attr::AttrMetaMethods;
29 use syntax::diagnostic::{ColorConfig, Auto, Always, Never};
31 use syntax::parse::token::InternedString;
33 use std::collections::HashSet;
34 use getopts::{optopt, optmulti, optflag, optflagopt};
37 use std::cell::{RefCell};
43 pub arch: abi::Architecture,
44 pub target_strs: target_strs::t,
46 pub uint_type: UintTy,
49 #[deriving(Clone, PartialEq)]
57 #[deriving(Clone, PartialEq)]
58 pub enum DebugInfoLevel {
66 // The crate config requested for the session, which may be combined
67 // with additional crate configurations during the compile process
68 pub crate_types: Vec<CrateType>,
71 pub optimize: OptLevel,
72 pub debuginfo: DebugInfoLevel,
73 pub lint_opts: Vec<(String, lint::Level)>,
74 pub describe_lints: bool,
75 pub output_types: Vec<back::link::OutputType> ,
76 // This was mutable for rustpkg, which updates search paths based on the
77 // parsed code. It remains mutable in case its replacements wants to use
79 pub addl_lib_search_paths: RefCell<HashSet<Path>>,
80 pub maybe_sysroot: Option<Path>,
81 pub target_triple: String,
82 // User-specified cfg meta items. The compiler itself will add additional
83 // items to the crate config, and during parsing the entire crate config
84 // will be added to the crate AST node. This should not be used for
85 // anything except building the full crate config prior to parsing.
86 pub cfg: ast::CrateConfig,
90 pub no_analysis: bool,
91 pub debugging_opts: u64,
92 /// Whether to write dependency files. It's (enabled, optional filename).
93 pub write_dependency_info: (bool, Option<Path>),
94 /// Crate id-related things to maybe print. It's (crate_id, crate_name, crate_file_name).
95 pub print_metas: (bool, bool, bool),
96 pub cg: CodegenOptions,
97 pub color: ColorConfig,
100 /// Some reasonable defaults
101 pub fn basic_options() -> Options {
103 crate_types: Vec::new(),
106 debuginfo: NoDebugInfo,
107 lint_opts: Vec::new(),
108 describe_lints: false,
109 output_types: Vec::new(),
110 addl_lib_search_paths: RefCell::new(HashSet::new()),
112 target_triple: driver::host_triple().to_string(),
119 write_dependency_info: (false, None),
120 print_metas: (false, false, false),
121 cg: basic_codegen_options(),
126 // The type of entry function, so
127 // users can have their own entry
128 // functions that don't start a
130 #[deriving(PartialEq)]
131 pub enum EntryFnType {
137 #[deriving(PartialEq, PartialOrd, Clone, Ord, Eq, Hash)]
145 macro_rules! debugging_opts(
146 ([ $opt:ident ] $cnt:expr ) => (
147 pub static $opt: u64 = 1 << $cnt;
149 ([ $opt:ident, $($rest:ident),* ] $cnt:expr ) => (
150 pub static $opt: u64 = 1 << $cnt;
151 debugging_opts!([ $($rest),* ] $cnt + 1)
183 pub fn debugging_opts_map() -> Vec<(&'static str, &'static str, u64)> {
184 vec!(("verbose", "in general, enable more debug printouts", VERBOSE),
185 ("time-passes", "measure time of each rustc pass", TIME_PASSES),
186 ("count-llvm-insns", "count where LLVM \
187 instrs originate", COUNT_LLVM_INSNS),
188 ("time-llvm-passes", "measure time of each LLVM pass",
190 ("trans-stats", "gather trans statistics", TRANS_STATS),
191 ("asm-comments", "generate comments into the assembly (may change behavior)",
193 ("no-verify", "skip LLVM verification", NO_VERIFY),
194 ("borrowck-stats", "gather borrowck statistics", BORROWCK_STATS),
195 ("no-landing-pads", "omit landing pads for unwinding",
197 ("debug-llvm", "enable debug output from LLVM", DEBUG_LLVM),
198 ("show-span", "show spans for compiler debugging", SHOW_SPAN),
199 ("count-type-sizes", "count the sizes of aggregate types",
201 ("meta-stats", "gather metadata statistics", META_STATS),
202 ("no-opt", "do not optimize, even if -O is passed", NO_OPT),
203 ("print-link-args", "Print the arguments passed to the linker",
205 ("gc", "Garbage collect shared data (experimental)", GC),
206 ("print-llvm-passes",
207 "Prints the llvm optimization passes being run",
209 ("lto", "Perform LLVM link-time optimizations", LTO),
210 ("ast-json", "Print the AST as JSON and halt", AST_JSON),
211 ("ast-json-noexpand", "Print the pre-expansion AST as JSON and halt", AST_JSON_NOEXPAND),
212 ("ls", "List the symbols defined by a library crate", LS),
213 ("save-analysis", "Write syntax and type analysis information \
214 in addition to normal output", SAVE_ANALYSIS))
217 /// Declare a macro that will define all CodegenOptions fields and parsers all
218 /// at once. The goal of this macro is to define an interface that can be
219 /// programmatically used by the option parser in order to initialize the struct
220 /// without hardcoding field names all over the place.
222 /// The goal is to invoke this macro once with the correct fields, and then this
223 /// macro generates all necessary code. The main gotcha of this macro is the
224 /// cgsetters module which is a bunch of generated code to parse an option into
225 /// its respective field in the struct. There are a few hand-written parsers for
226 /// parsing specific types of values in this module.
227 macro_rules! cgoptions(
228 ($($opt:ident : $t:ty = ($init:expr, $parse:ident, $desc:expr)),* ,) =>
231 pub struct CodegenOptions { $(pub $opt: $t),* }
233 pub fn basic_codegen_options() -> CodegenOptions {
234 CodegenOptions { $($opt: $init),* }
237 pub type CodegenSetter = fn(&mut CodegenOptions, v: Option<&str>) -> bool;
238 pub static CG_OPTIONS: &'static [(&'static str, CodegenSetter,
240 &[ $( (stringify!($opt), cgsetters::$opt, $desc) ),* ];
243 use super::CodegenOptions;
246 pub fn $opt(cg: &mut CodegenOptions, v: Option<&str>) -> bool {
247 $parse(&mut cg.$opt, v)
251 fn parse_bool(slot: &mut bool, v: Option<&str>) -> bool {
254 None => { *slot = true; true }
258 fn parse_opt_string(slot: &mut Option<String>, v: Option<&str>) -> bool {
260 Some(s) => { *slot = Some(s.to_string()); true },
265 fn parse_string(slot: &mut String, v: Option<&str>) -> bool {
267 Some(s) => { *slot = s.to_string(); true },
272 fn parse_list(slot: &mut Vec<String>, v: Option<&str>)
277 slot.push(s.to_string());
289 ar: Option<String> = (None, parse_opt_string,
290 "tool to assemble archives with"),
291 linker: Option<String> = (None, parse_opt_string,
292 "system linker to link outputs with"),
293 link_args: Vec<String> = (Vec::new(), parse_list,
294 "extra arguments to pass to the linker (space separated)"),
295 target_cpu: String = ("generic".to_string(), parse_string,
296 "select target processor (llc -mcpu=help for details)"),
297 target_feature: String = ("".to_string(), parse_string,
298 "target specific attributes (llc -mattr=help for details)"),
299 passes: Vec<String> = (Vec::new(), parse_list,
300 "a list of extra LLVM passes to run (space separated)"),
301 llvm_args: Vec<String> = (Vec::new(), parse_list,
302 "a list of arguments to pass to llvm (space separated)"),
303 save_temps: bool = (false, parse_bool,
304 "save all temporary output files during compilation"),
305 no_rpath: bool = (false, parse_bool,
306 "disables setting the rpath in libs/exes"),
307 no_prepopulate_passes: bool = (false, parse_bool,
308 "don't pre-populate the pass manager with a list of passes"),
309 no_vectorize_loops: bool = (false, parse_bool,
310 "don't run the loop vectorization optimization passes"),
311 no_vectorize_slp: bool = (false, parse_bool,
312 "don't run LLVM's SLP vectorization pass"),
313 soft_float: bool = (false, parse_bool,
314 "generate software floating point library calls"),
315 prefer_dynamic: bool = (false, parse_bool,
316 "prefer dynamic linking to static linking"),
317 no_integrated_as: bool = (false, parse_bool,
318 "use an external assembler rather than LLVM's integrated one"),
319 relocation_model: String = ("pic".to_string(), parse_string,
320 "choose the relocation model to use (llc -relocation-model for details)"),
323 pub fn build_codegen_options(matches: &getopts::Matches) -> CodegenOptions
325 let mut cg = basic_codegen_options();
326 for option in matches.opt_strs("C").move_iter() {
327 let mut iter = option.as_slice().splitn('=', 1);
328 let key = iter.next().unwrap();
329 let value = iter.next();
330 let option_to_lookup = key.replace("-", "_");
331 let mut found = false;
332 for &(candidate, setter, _) in CG_OPTIONS.iter() {
333 if option_to_lookup.as_slice() != candidate { continue }
334 if !setter(&mut cg, value) {
337 early_error(format!("codegen option `{}` takes no \
338 value", key).as_slice())
341 early_error(format!("codegen option `{0}` requires \
342 a value (-C {0}=<value>)",
351 early_error(format!("unknown codegen option: `{}`",
358 pub fn default_lib_output() -> CrateType {
362 pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
363 let tos = match sess.targ_cfg.os {
364 abi::OsWin32 => InternedString::new("win32"),
365 abi::OsMacos => InternedString::new("macos"),
366 abi::OsLinux => InternedString::new("linux"),
367 abi::OsAndroid => InternedString::new("android"),
368 abi::OsFreebsd => InternedString::new("freebsd"),
369 abi::OsiOS => InternedString::new("ios"),
372 // ARM is bi-endian, however using NDK seems to default
373 // to little-endian unless a flag is provided.
374 let (end,arch,wordsz) = match sess.targ_cfg.arch {
375 abi::X86 => ("little", "x86", "32"),
376 abi::X86_64 => ("little", "x86_64", "64"),
377 abi::Arm => ("little", "arm", "32"),
378 abi::Mips => ("big", "mips", "32"),
379 abi::Mipsel => ("little", "mipsel", "32")
382 let fam = match sess.targ_cfg.os {
383 abi::OsWin32 => InternedString::new("windows"),
384 _ => InternedString::new("unix")
387 let mk = attr::mk_name_value_item_str;
388 return vec!(// Target bindings.
389 attr::mk_word_item(fam.clone()),
390 mk(InternedString::new("target_os"), tos),
391 mk(InternedString::new("target_family"), fam),
392 mk(InternedString::new("target_arch"), InternedString::new(arch)),
393 mk(InternedString::new("target_endian"), InternedString::new(end)),
394 mk(InternedString::new("target_word_size"),
395 InternedString::new(wordsz))
399 pub fn append_configuration(cfg: &mut ast::CrateConfig,
400 name: InternedString) {
401 if !cfg.iter().any(|mi| mi.name() == name) {
402 cfg.push(attr::mk_word_item(name))
406 pub fn build_configuration(sess: &Session) -> ast::CrateConfig {
407 // Combine the configuration requested by the session (command line) with
408 // some default and generated configuration items
409 let default_cfg = default_configuration(sess);
410 let mut user_cfg = sess.opts.cfg.clone();
411 // If the user wants a test runner, then add the test cfg
413 append_configuration(&mut user_cfg, InternedString::new("test"))
415 // If the user requested GC, then add the GC cfg
416 append_configuration(&mut user_cfg, if sess.opts.gc {
417 InternedString::new("gc")
419 InternedString::new("nogc")
421 user_cfg.move_iter().collect::<Vec<_>>().append(default_cfg.as_slice())
424 pub fn get_os(triple: &str) -> Option<abi::Os> {
425 for &(name, os) in os_names.iter() {
426 if triple.contains(name) { return Some(os) }
430 static os_names : &'static [(&'static str, abi::Os)] = &[
431 ("mingw32", abi::OsWin32),
432 ("win32", abi::OsWin32),
433 ("darwin", abi::OsMacos),
434 ("android", abi::OsAndroid),
435 ("linux", abi::OsLinux),
436 ("freebsd", abi::OsFreebsd),
437 ("ios", abi::OsiOS)];
439 pub fn get_arch(triple: &str) -> Option<abi::Architecture> {
440 for &(arch, abi) in architecture_abis.iter() {
441 if triple.contains(arch) { return Some(abi) }
445 static architecture_abis : &'static [(&'static str, abi::Architecture)] = &[
452 ("x86_64", abi::X86_64),
455 ("xscale", abi::Arm),
458 ("mipsel", abi::Mipsel),
459 ("mips", abi::Mips)];
461 pub fn build_target_config(sopts: &Options) -> Config {
462 let os = match get_os(sopts.target_triple.as_slice()) {
464 None => early_error("unknown operating system")
466 let arch = match get_arch(sopts.target_triple.as_slice()) {
469 early_error(format!("unknown architecture: {}",
470 sopts.target_triple.as_slice()).as_slice())
473 let (int_type, uint_type) = match arch {
474 abi::X86 => (ast::TyI32, ast::TyU32),
475 abi::X86_64 => (ast::TyI64, ast::TyU64),
476 abi::Arm => (ast::TyI32, ast::TyU32),
477 abi::Mips => (ast::TyI32, ast::TyU32),
478 abi::Mipsel => (ast::TyI32, ast::TyU32)
480 let target_triple = sopts.target_triple.clone();
481 let target_strs = match arch {
482 abi::X86 => x86::get_target_strs(target_triple, os),
483 abi::X86_64 => x86_64::get_target_strs(target_triple, os),
484 abi::Arm => arm::get_target_strs(target_triple, os),
485 abi::Mips => mips::get_target_strs(target_triple, os),
486 abi::Mipsel => mipsel::get_target_strs(target_triple, os)
491 target_strs: target_strs,
493 uint_type: uint_type,
497 // rustc command line options
498 pub fn optgroups() -> Vec<getopts::OptGroup> {
500 optflag("h", "help", "Display this message"),
501 optmulti("", "cfg", "Configure the compilation environment", "SPEC"),
502 optmulti("L", "", "Add a directory to the library search path", "PATH"),
503 optmulti("", "crate-type", "Comma separated list of types of crates
504 for the compiler to emit",
505 "[bin|lib|rlib|dylib|staticlib]"),
506 optmulti("", "emit", "Comma separated list of types of output for the compiler to emit",
507 "[asm|bc|ir|obj|link]"),
508 optflag("", "crate-id", "Output the crate id and exit"),
509 optflag("", "crate-name", "Output the crate name and exit"),
510 optflag("", "crate-file-name", "Output the file(s) that would be written if compilation \
511 continued and exit"),
512 optflag("g", "", "Equivalent to --debuginfo=2"),
513 optopt("", "debuginfo", "Emit DWARF debug info to the objects created:
515 1 = line-tables only (for stacktraces and breakpoints),
516 2 = full debug info with variable and type information (same as -g)", "LEVEL"),
517 optflag("", "no-trans", "Run all passes except translation; no output"),
518 optflag("", "no-analysis",
519 "Parse and expand the source, but run no analysis and produce no output"),
520 optflag("O", "", "Equivalent to --opt-level=2"),
521 optopt("o", "", "Write output to <filename>", "FILENAME"),
522 optopt("", "opt-level", "Optimize with possible levels 0-3", "LEVEL"),
523 optopt( "", "out-dir", "Write output to compiler-chosen filename in <dir>", "DIR"),
524 optflag("", "parse-only", "Parse only; do not compile, assemble, or link"),
525 optflagopt("", "pretty",
526 "Pretty-print the input instead of compiling;
527 valid types are: `normal` (un-annotated source),
528 `expanded` (crates expanded),
529 `typed` (crates expanded, with type annotations),
530 `expanded,identified` (fully parenthesized, AST nodes with IDs), or
531 `flowgraph=<nodeid>` (graphviz formatted flowgraph for node)",
533 optflagopt("", "dep-info",
534 "Output dependency info to <filename> after compiling, \
535 in a format suitable for use by Makefiles", "FILENAME"),
536 optopt("", "sysroot", "Override the system root", "PATH"),
537 optflag("", "test", "Build a test harness"),
538 optopt("", "target", "Target triple cpu-manufacturer-kernel[-os]
539 to compile for (see chapter 3.4 of http://www.sourceware.org/autobook/
540 for details)", "TRIPLE"),
541 optmulti("W", "warn", "Set lint warnings", "OPT"),
542 optmulti("A", "allow", "Set lint allowed", "OPT"),
543 optmulti("D", "deny", "Set lint denied", "OPT"),
544 optmulti("F", "forbid", "Set lint forbidden", "OPT"),
545 optmulti("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
546 optmulti("Z", "", "Set internal debugging options", "FLAG"),
547 optflagopt("v", "version", "Print version info and exit", "verbose"),
548 optopt("", "color", "Configure coloring of output:
549 auto = colorize, if output goes to a tty (default);
550 always = always colorize output;
551 never = never colorize output", "auto|always|never")
556 // Convert strings provided as --cfg [cfgspec] into a crate_cfg
557 fn parse_cfgspecs(cfgspecs: Vec<String> ) -> ast::CrateConfig {
558 cfgspecs.move_iter().map(|s| {
559 parse::parse_meta_from_source_str("cfgspec".to_string(),
562 &parse::new_parse_sess())
563 }).collect::<ast::CrateConfig>()
566 pub fn build_session_options(matches: &getopts::Matches) -> Options {
567 let mut crate_types: Vec<CrateType> = Vec::new();
568 let unparsed_crate_types = matches.opt_strs("crate-type");
569 for unparsed_crate_type in unparsed_crate_types.iter() {
570 for part in unparsed_crate_type.as_slice().split(',') {
571 let new_part = match part {
572 "lib" => default_lib_output(),
573 "rlib" => CrateTypeRlib,
574 "staticlib" => CrateTypeStaticlib,
575 "dylib" => CrateTypeDylib,
576 "bin" => CrateTypeExecutable,
578 early_error(format!("unknown crate type: `{}`",
582 crate_types.push(new_part)
586 let parse_only = matches.opt_present("parse-only");
587 let no_trans = matches.opt_present("no-trans");
588 let no_analysis = matches.opt_present("no-analysis");
590 let mut lint_opts = vec!();
591 let mut describe_lints = false;
593 for &level in [lint::Allow, lint::Warn, lint::Deny, lint::Forbid].iter() {
594 for lint_name in matches.opt_strs(level.as_str()).move_iter() {
595 if lint_name.as_slice() == "help" {
596 describe_lints = true;
598 lint_opts.push((lint_name.replace("-", "_").into_string(), level));
603 let mut debugging_opts = 0;
604 let debug_flags = matches.opt_strs("Z");
605 let debug_map = debugging_opts_map();
606 for debug_flag in debug_flags.iter() {
607 let mut this_bit = 0;
608 for tuple in debug_map.iter() {
609 let (name, bit) = match *tuple { (ref a, _, b) => (a, b) };
610 if *name == debug_flag.as_slice() {
616 early_error(format!("unknown debug flag: {}",
617 *debug_flag).as_slice())
619 debugging_opts |= this_bit;
622 if debugging_opts & DEBUG_LLVM != 0 {
623 unsafe { llvm::LLVMSetDebug(1); }
626 let mut output_types = Vec::new();
627 if !parse_only && !no_trans {
628 let unparsed_output_types = matches.opt_strs("emit");
629 for unparsed_output_type in unparsed_output_types.iter() {
630 for part in unparsed_output_type.as_slice().split(',') {
631 let output_type = match part.as_slice() {
632 "asm" => link::OutputTypeAssembly,
633 "ir" => link::OutputTypeLlvmAssembly,
634 "bc" => link::OutputTypeBitcode,
635 "obj" => link::OutputTypeObject,
636 "link" => link::OutputTypeExe,
638 early_error(format!("unknown emission type: `{}`",
642 output_types.push(output_type)
646 output_types.as_mut_slice().sort();
647 output_types.dedup();
648 if output_types.len() == 0 {
649 output_types.push(link::OutputTypeExe);
652 let sysroot_opt = matches.opt_str("sysroot").map(|m| Path::new(m));
653 let target = matches.opt_str("target").unwrap_or(
654 driver::host_triple().to_string());
656 if (debugging_opts & NO_OPT) != 0 {
658 } else if matches.opt_present("O") {
659 if matches.opt_present("opt-level") {
660 early_error("-O and --opt-level both provided");
663 } else if matches.opt_present("opt-level") {
664 match matches.opt_str("opt-level").as_ref().map(|s| s.as_slice()) {
668 Some("2") => Default,
669 Some("3") => Aggressive,
671 early_error(format!("optimization level needs to be \
672 between 0-3 (instead was `{}`)",
680 let gc = debugging_opts & GC != 0;
681 let debuginfo = if matches.opt_present("g") {
682 if matches.opt_present("debuginfo") {
683 early_error("-g and --debuginfo both provided");
686 } else if matches.opt_present("debuginfo") {
687 match matches.opt_str("debuginfo").as_ref().map(|s| s.as_slice()) {
688 Some("0") => NoDebugInfo,
689 Some("1") => LimitedDebugInfo,
691 Some("2") => FullDebugInfo,
693 early_error(format!("optimization level needs to be between \
694 0-3 (instead was `{}`)",
702 let addl_lib_search_paths = matches.opt_strs("L").iter().map(|s| {
703 Path::new(s.as_slice())
706 let cfg = parse_cfgspecs(matches.opt_strs("cfg"));
707 let test = matches.opt_present("test");
708 let write_dependency_info = (matches.opt_present("dep-info"),
709 matches.opt_str("dep-info")
710 .map(|p| Path::new(p)));
712 let print_metas = (matches.opt_present("crate-id"),
713 matches.opt_present("crate-name"),
714 matches.opt_present("crate-file-name"));
715 let cg = build_codegen_options(matches);
717 let color = match matches.opt_str("color").as_ref().map(|s| s.as_slice()) {
718 Some("auto") => Auto,
719 Some("always") => Always,
720 Some("never") => Never,
725 early_error(format!("argument for --color must be auto, always \
726 or never (instead was `{}`)",
732 crate_types: crate_types,
735 debuginfo: debuginfo,
736 lint_opts: lint_opts,
737 describe_lints: describe_lints,
738 output_types: output_types,
739 addl_lib_search_paths: RefCell::new(addl_lib_search_paths),
740 maybe_sysroot: sysroot_opt,
741 target_triple: target,
744 parse_only: parse_only,
746 no_analysis: no_analysis,
747 debugging_opts: debugging_opts,
748 write_dependency_info: write_dependency_info,
749 print_metas: print_metas,
755 impl fmt::Show for CrateType {
756 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
758 CrateTypeExecutable => "bin".fmt(f),
759 CrateTypeDylib => "dylib".fmt(f),
760 CrateTypeRlib => "rlib".fmt(f),
761 CrateTypeStaticlib => "staticlib".fmt(f)
769 use driver::config::{build_configuration, optgroups, build_session_options};
770 use driver::session::build_session;
772 use getopts::getopts;
774 use syntax::attr::AttrMetaMethods;
776 // When the user supplies --test we should implicitly supply --cfg test
778 fn test_switch_implies_cfg_test() {
780 &match getopts(["--test".to_string()], optgroups().as_slice()) {
782 Err(f) => fail!("test_switch_implies_cfg_test: {}", f)
784 let sessopts = build_session_options(matches);
785 let sess = build_session(sessopts, None);
786 let cfg = build_configuration(&sess);
787 assert!((attr::contains_name(cfg.as_slice(), "test")));
790 // When the user supplies --test and --cfg test, don't implicitly add
791 // another --cfg test
793 fn test_switch_implies_cfg_test_unless_cfg_test() {
795 &match getopts(["--test".to_string(), "--cfg=test".to_string()],
796 optgroups().as_slice()) {
799 fail!("test_switch_implies_cfg_test_unless_cfg_test: {}", f)
802 let sessopts = build_session_options(matches);
803 let sess = build_session(sessopts, None);
804 let cfg = build_configuration(&sess);
805 let mut test_items = cfg.iter().filter(|m| m.name().equiv(&("test")));
806 assert!(test_items.next().is_some());
807 assert!(test_items.next().is_none());