1 //! Contains infrastructure for configuring the compiler, including parsing
2 //! command-line options.
4 pub use crate::options::*;
7 use crate::search_paths::SearchPath;
8 use crate::utils::NativeLibraryKind;
9 use crate::{early_error, early_warn, Session};
11 use rustc_data_structures::fx::FxHashSet;
12 use rustc_data_structures::impl_stable_hash_via_hash;
14 use rustc_target::spec::{Target, TargetTriple};
16 use crate::parse::CrateConfig;
17 use rustc_feature::UnstableFeatures;
18 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST};
19 use rustc_span::source_map::{FileName, FilePathMapping};
20 use rustc_span::symbol::{sym, Symbol};
22 use rustc_errors::emitter::HumanReadableErrorType;
23 use rustc_errors::{ColorConfig, FatalError, Handler, HandlerFlags};
25 use std::collections::btree_map::{
26 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
28 use std::collections::{BTreeMap, BTreeSet};
30 use std::iter::{self, FromIterator};
31 use std::path::{Path, PathBuf};
32 use std::str::{self, FromStr};
39 #[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
47 impl fmt::Display for Sanitizer {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
50 Sanitizer::Address => "address".fmt(f),
51 Sanitizer::Leak => "leak".fmt(f),
52 Sanitizer::Memory => "memory".fmt(f),
53 Sanitizer::Thread => "thread".fmt(f),
58 impl FromStr for Sanitizer {
60 fn from_str(s: &str) -> Result<Sanitizer, ()> {
62 "address" => Ok(Sanitizer::Address),
63 "leak" => Ok(Sanitizer::Leak),
64 "memory" => Ok(Sanitizer::Memory),
65 "thread" => Ok(Sanitizer::Thread),
71 /// The different settings that the `-Z control_flow_guard` flag can have.
72 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
74 /// Do not emit Control Flow Guard metadata or checks.
77 /// Emit Control Flow Guard metadata but no checks.
80 /// Emit Control Flow Guard metadata and checks.
84 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
94 impl_stable_hash_via_hash!(OptLevel);
96 /// This is what the `LtoCli` values get mapped to after resolving defaults and
97 /// and taking other command line options into account.
98 #[derive(Clone, PartialEq)]
100 /// Don't do any LTO whatsoever
103 /// Do a full crate graph LTO with ThinLTO
106 /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
110 /// Do a full crate graph LTO with "fat" LTO
114 /// The different settings that the `-C lto` flag can have.
115 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
127 /// No `-C lto` flag passed
131 #[derive(Clone, PartialEq, Hash)]
132 pub enum LinkerPluginLto {
133 LinkerPlugin(PathBuf),
138 impl LinkerPluginLto {
139 pub fn enabled(&self) -> bool {
141 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
142 LinkerPluginLto::Disabled => false,
147 #[derive(Clone, PartialEq, Hash)]
148 pub enum SwitchWithOptPath {
149 Enabled(Option<PathBuf>),
153 impl SwitchWithOptPath {
154 pub fn enabled(&self) -> bool {
156 SwitchWithOptPath::Enabled(_) => true,
157 SwitchWithOptPath::Disabled => false,
162 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
163 pub enum SymbolManglingVersion {
168 impl_stable_hash_via_hash!(SymbolManglingVersion);
170 #[derive(Clone, Copy, PartialEq, Hash)]
177 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
178 pub enum OutputType {
189 impl_stable_hash_via_hash!(OutputType);
192 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
194 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
196 | OutputType::Assembly
197 | OutputType::LlvmAssembly
199 | OutputType::Object => false,
203 fn shorthand(&self) -> &'static str {
205 OutputType::Bitcode => "llvm-bc",
206 OutputType::Assembly => "asm",
207 OutputType::LlvmAssembly => "llvm-ir",
208 OutputType::Mir => "mir",
209 OutputType::Object => "obj",
210 OutputType::Metadata => "metadata",
211 OutputType::Exe => "link",
212 OutputType::DepInfo => "dep-info",
216 fn from_shorthand(shorthand: &str) -> Option<Self> {
217 Some(match shorthand {
218 "asm" => OutputType::Assembly,
219 "llvm-ir" => OutputType::LlvmAssembly,
220 "mir" => OutputType::Mir,
221 "llvm-bc" => OutputType::Bitcode,
222 "obj" => OutputType::Object,
223 "metadata" => OutputType::Metadata,
224 "link" => OutputType::Exe,
225 "dep-info" => OutputType::DepInfo,
230 fn shorthands_display() -> String {
232 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
233 OutputType::Bitcode.shorthand(),
234 OutputType::Assembly.shorthand(),
235 OutputType::LlvmAssembly.shorthand(),
236 OutputType::Mir.shorthand(),
237 OutputType::Object.shorthand(),
238 OutputType::Metadata.shorthand(),
239 OutputType::Exe.shorthand(),
240 OutputType::DepInfo.shorthand(),
244 pub fn extension(&self) -> &'static str {
246 OutputType::Bitcode => "bc",
247 OutputType::Assembly => "s",
248 OutputType::LlvmAssembly => "ll",
249 OutputType::Mir => "mir",
250 OutputType::Object => "o",
251 OutputType::Metadata => "rmeta",
252 OutputType::DepInfo => "d",
253 OutputType::Exe => "",
258 /// The type of diagnostics output to generate.
259 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
260 pub enum ErrorOutputType {
261 /// Output meant for the consumption of humans.
262 HumanReadable(HumanReadableErrorType),
263 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
265 /// Render the JSON in a human readable way (with indents and newlines).
267 /// The JSON output includes a `rendered` field that includes the rendered
269 json_rendered: HumanReadableErrorType,
273 impl Default for ErrorOutputType {
274 fn default() -> Self {
275 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
279 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
280 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
281 /// dependency tracking for command-line arguments.
282 #[derive(Clone, Hash)]
283 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
285 impl_stable_hash_via_hash!(OutputTypes);
288 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
289 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
292 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
296 pub fn contains_key(&self, key: &OutputType) -> bool {
297 self.0.contains_key(key)
300 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
304 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
308 pub fn len(&self) -> usize {
312 // Returns `true` if any of the output types require codegen or linking.
313 pub fn should_codegen(&self) -> bool {
314 self.0.keys().any(|k| match *k {
316 | OutputType::Assembly
317 | OutputType::LlvmAssembly
320 | OutputType::Exe => true,
321 OutputType::Metadata | OutputType::DepInfo => false,
326 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
327 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
328 /// would break dependency tracking for command-line arguments.
330 pub struct Externs(BTreeMap<String, ExternEntry>);
332 #[derive(Clone, Debug)]
333 pub struct ExternEntry {
334 pub location: ExternLocation,
335 /// Indicates this is a "private" dependency for the
336 /// `exported_private_dependencies` lint.
338 /// This can be set with the `priv` option like
339 /// `--extern priv:name=foo.rlib`.
340 pub is_private_dep: bool,
341 /// Add the extern entry to the extern prelude.
343 /// This can be disabled with the `noprelude` option like
344 /// `--extern noprelude:name`.
345 pub add_prelude: bool,
348 #[derive(Clone, Debug)]
349 pub enum ExternLocation {
350 /// Indicates to look for the library in the search paths.
352 /// Added via `--extern name`.
353 FoundInLibrarySearchDirectories,
354 /// The locations where this extern entry must be found.
356 /// The `CrateLoader` is responsible for loading these and figuring out
357 /// which one to use.
359 /// Added via `--extern prelude_name=some_file.rlib`
360 ExactPaths(BTreeSet<String>),
364 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
368 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
372 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
378 fn new(location: ExternLocation) -> ExternEntry {
379 ExternEntry { location, is_private_dep: false, add_prelude: false }
382 pub fn files(&self) -> Option<impl Iterator<Item = &String>> {
383 match &self.location {
384 ExternLocation::ExactPaths(set) => Some(set.iter()),
390 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
391 pub enum PrintRequest {
406 #[derive(Copy, Clone)]
407 pub enum BorrowckMode {
413 /// Returns whether we should run the MIR-based borrow check, but also fall back
414 /// on the AST borrow check if the MIR-based one errors.
415 pub fn migrate(self) -> bool {
417 BorrowckMode::Mir => false,
418 BorrowckMode::Migrate => true,
424 /// Load source code from a file.
426 /// Load source code from a string.
428 /// A string that is shown in place of a filename.
430 /// An anonymous string containing the source code.
436 pub fn filestem(&self) -> &str {
438 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
439 Input::Str { .. } => "rust_out",
443 pub fn get_input(&mut self) -> Option<&mut String> {
445 Input::File(_) => None,
446 Input::Str { ref mut input, .. } => Some(input),
450 pub fn source_name(&self) -> FileName {
452 Input::File(ref ifile) => ifile.clone().into(),
453 Input::Str { ref name, .. } => name.clone(),
458 #[derive(Clone, Hash)]
459 pub struct OutputFilenames {
460 pub out_directory: PathBuf,
462 pub single_output_file: Option<PathBuf>,
463 pub outputs: OutputTypes,
466 impl_stable_hash_via_hash!(OutputFilenames);
468 pub const RLINK_EXT: &str = "rlink";
469 pub const RUST_CGU_EXT: &str = "rcgu";
471 impl OutputFilenames {
473 out_directory: PathBuf,
474 out_filestem: String,
475 single_output_file: Option<PathBuf>,
477 outputs: OutputTypes,
483 filestem: format!("{}{}", out_filestem, extra),
487 pub fn path(&self, flavor: OutputType) -> PathBuf {
490 .and_then(|p| p.to_owned())
491 .or_else(|| self.single_output_file.clone())
492 .unwrap_or_else(|| self.temp_path(flavor, None))
495 /// Gets the path where a compilation artifact of the given type for the
496 /// given codegen unit should be placed on disk. If codegen_unit_name is
497 /// None, a path distinct from those of any codegen unit will be generated.
498 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
499 let extension = flavor.extension();
500 self.temp_path_ext(extension, codegen_unit_name)
503 /// Like temp_path, but also supports things where there is no corresponding
504 /// OutputType, like noopt-bitcode or lto-bitcode.
505 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
506 let mut extension = String::new();
508 if let Some(codegen_unit_name) = codegen_unit_name {
509 extension.push_str(codegen_unit_name);
513 if !extension.is_empty() {
514 extension.push_str(".");
515 extension.push_str(RUST_CGU_EXT);
516 extension.push_str(".");
519 extension.push_str(ext);
522 self.with_extension(&extension)
525 pub fn with_extension(&self, extension: &str) -> PathBuf {
526 let mut path = self.out_directory.join(&self.filestem);
527 path.set_extension(extension);
532 pub fn host_triple() -> &'static str {
533 // Get the host triple out of the build environment. This ensures that our
534 // idea of the host triple is the same as for the set of libraries we've
535 // actually built. We can't just take LLVM's host triple because they
536 // normalize all ix86 architectures to i386.
538 // Instead of grabbing the host triple (for the current host), we grab (at
539 // compile time) the target triple that this rustc is built with and
540 // calling that (at runtime) the host triple.
541 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
544 impl Default for Options {
545 fn default() -> Options {
547 crate_types: Vec::new(),
548 optimize: OptLevel::No,
549 debuginfo: DebugInfo::None,
550 lint_opts: Vec::new(),
552 describe_lints: false,
553 output_types: OutputTypes(BTreeMap::new()),
554 search_paths: vec![],
556 target_triple: TargetTriple::from_triple(host_triple()),
559 debugging_opts: basic_debugging_options(),
561 borrowck_mode: BorrowckMode::Migrate,
562 cg: basic_codegen_options(),
563 error_format: ErrorOutputType::default(),
564 externs: Externs(BTreeMap::new()),
568 unstable_features: UnstableFeatures::Disallow,
569 debug_assertions: true,
570 actually_rustdoc: false,
571 cli_forced_codegen_units: None,
572 cli_forced_thinlto_off: false,
573 remap_path_prefix: Vec::new(),
574 edition: DEFAULT_EDITION,
575 json_artifact_notifications: false,
582 /// Returns `true` if there is a reason to build the dep graph.
583 pub fn build_dep_graph(&self) -> bool {
584 self.incremental.is_some()
585 || self.debugging_opts.dump_dep_graph
586 || self.debugging_opts.query_dep_graph
590 pub fn enable_dep_node_debug_strs(&self) -> bool {
591 cfg!(debug_assertions)
592 && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
595 pub fn file_path_mapping(&self) -> FilePathMapping {
596 FilePathMapping::new(self.remap_path_prefix.clone())
599 /// Returns `true` if there will be an output file generated.
600 pub fn will_create_output_file(&self) -> bool {
601 !self.debugging_opts.parse_only && // The file is just being parsed
602 !self.debugging_opts.ls // The file is just being queried
606 pub fn share_generics(&self) -> bool {
607 match self.debugging_opts.share_generics {
608 Some(setting) => setting,
609 None => match self.optimize {
610 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
611 OptLevel::Default | OptLevel::Aggressive => false,
617 impl DebuggingOptions {
618 pub fn ui_testing(&self) -> bool {
619 self.ui_testing.unwrap_or(false)
622 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
625 treat_err_as_bug: self.treat_err_as_bug,
626 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
627 report_delayed_bugs: self.report_delayed_bugs,
628 macro_backtrace: self.macro_backtrace,
629 deduplicate_diagnostics: self.deduplicate_diagnostics.unwrap_or(true),
634 // The type of entry function, so users can have their own entry functions
635 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
636 pub enum EntryFnType {
641 impl_stable_hash_via_hash!(EntryFnType);
643 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
653 impl_stable_hash_via_hash!(CrateType);
655 #[derive(Clone, Hash)]
662 pub fn is_empty(&self) -> bool {
664 Passes::Some(ref v) => v.is_empty(),
665 Passes::All => false,
670 pub const fn default_lib_output() -> CrateType {
674 pub fn default_configuration(sess: &Session) -> CrateConfig {
675 let end = &sess.target.target.target_endian;
676 let arch = &sess.target.target.arch;
677 let wordsz = &sess.target.target.target_pointer_width;
678 let os = &sess.target.target.target_os;
679 let env = &sess.target.target.target_env;
680 let vendor = &sess.target.target.target_vendor;
681 let min_atomic_width = sess.target.target.min_atomic_width();
682 let max_atomic_width = sess.target.target.max_atomic_width();
683 let atomic_cas = sess.target.target.options.atomic_cas;
685 let mut ret = FxHashSet::default();
686 ret.reserve(6); // the minimum number of insertions
688 ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
689 if let Some(ref fam) = sess.target.target.options.target_family {
690 ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
691 if fam == "windows" || fam == "unix" {
692 ret.insert((Symbol::intern(fam), None));
695 ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
696 ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
697 ret.insert((Symbol::intern("target_pointer_width"), Some(Symbol::intern(wordsz))));
698 ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
699 ret.insert((Symbol::intern("target_vendor"), Some(Symbol::intern(vendor))));
700 if sess.target.target.options.has_elf_tls {
701 ret.insert((sym::target_thread_local, None));
703 for &i in &[8, 16, 32, 64, 128] {
704 if i >= min_atomic_width && i <= max_atomic_width {
705 let mut insert_atomic = |s| {
706 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
708 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
711 let s = i.to_string();
714 insert_atomic("ptr");
718 if let Some(s) = &sess.opts.debugging_opts.sanitizer {
719 let symbol = Symbol::intern(&s.to_string());
720 ret.insert((sym::sanitize, Some(symbol)));
722 if sess.opts.debug_assertions {
723 ret.insert((Symbol::intern("debug_assertions"), None));
725 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
726 ret.insert((sym::proc_macro, None));
731 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
732 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
733 /// but the symbol interner is not yet set up then, so we must convert it later.
734 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
735 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
738 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
739 // Combine the configuration requested by the session (command line) with
740 // some default and generated configuration items.
741 let default_cfg = default_configuration(sess);
742 // If the user wants a test runner, then add the test cfg.
744 user_cfg.insert((sym::test, None));
746 user_cfg.extend(default_cfg.iter().cloned());
750 pub fn build_target_config(opts: &Options, sp: &Handler) -> Config {
751 let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
752 sp.struct_fatal(&format!("Error loading target specification: {}", e))
753 .help("Use `--print target-list` for a list of built-in targets")
758 let ptr_width = match &target.target_pointer_width[..] {
764 "target specification was invalid: \
765 unrecognized target-pointer-width {}",
771 Config { target, ptr_width }
774 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
775 pub enum OptionStability {
780 pub struct RustcOptGroup {
781 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
782 pub name: &'static str,
783 pub stability: OptionStability,
787 pub fn is_stable(&self) -> bool {
788 self.stability == OptionStability::Stable
791 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
793 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
795 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
798 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
800 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
802 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
806 // The `opt` local module holds wrappers around the `getopts` API that
807 // adds extra rustc-specific metadata to each option; such metadata
808 // is exposed by . The public
809 // functions below ending with `_u` are the functions that return
810 // *unstable* options, i.e., options that are only enabled when the
811 // user also passes the `-Z unstable-options` debugging flag.
813 // The `fn flag*` etc below are written so that we can use them
814 // in the future; do not warn about them not being used right now.
817 use super::RustcOptGroup;
819 pub type R = RustcOptGroup;
820 pub type S = &'static str;
822 fn stable<F>(name: S, f: F) -> R
824 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
826 RustcOptGroup::stable(name, f)
829 fn unstable<F>(name: S, f: F) -> R
831 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
833 RustcOptGroup::unstable(name, f)
836 fn longer(a: S, b: S) -> S {
837 if a.len() > b.len() { a } else { b }
840 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
841 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
843 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
844 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
846 pub fn flag_s(a: S, b: S, c: S) -> R {
847 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
849 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
850 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
852 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
853 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
856 pub fn opt(a: S, b: S, c: S, d: S) -> R {
857 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
859 pub fn multi(a: S, b: S, c: S, d: S) -> R {
860 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
862 pub fn flag(a: S, b: S, c: S) -> R {
863 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
865 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
866 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
868 pub fn flagmulti(a: S, b: S, c: S) -> R {
869 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
873 /// Returns the "short" subset of the rustc command line options,
874 /// including metadata for each option, such as whether the option is
875 /// part of the stable long-term interface for rustc.
876 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
878 opt::flag_s("h", "help", "Display this message"),
879 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
883 "Add a directory to the library search path. The
884 optional KIND can be one of dependency, crate, native,
885 framework, or all (the default).",
891 "Link the generated crate(s) to the specified native
892 library NAME. The optional KIND can be one of
893 static, framework, or dylib (the default).",
896 make_crate_type_option(),
897 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
901 "Specify which edition of the compiler to use when compiling code.",
907 "Comma separated list of types of output for \
908 the compiler to emit",
909 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
914 "Compiler information to print on stdout",
915 "[crate-name|file-names|sysroot|cfg|target-list|\
916 target-cpus|target-features|relocation-models|\
917 code-models|tls-models|target-spec-json|native-static-libs]",
919 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
920 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
921 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
925 "Write output to compiler-chosen filename \
932 "Provide a detailed explanation of an error \
936 opt::flag_s("", "test", "Build a test harness"),
937 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
938 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
939 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
940 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
941 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
945 "Set the most restrictive lint level. \
946 More restrictive lints are capped at this \
950 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
951 opt::flag_s("V", "version", "Print version info and exit"),
952 opt::flag_s("v", "verbose", "Use verbose output"),
956 /// Returns all rustc command line options, including metadata for
957 /// each option, such as whether the option is part of the stable
958 /// long-term interface for rustc.
959 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
960 let mut opts = rustc_short_optgroups();
965 "Specify where an external rust library is located",
968 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
969 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
973 "How errors and other messages are produced",
976 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
980 "Configure coloring of output:
981 auto = colorize, if output goes to a tty (default);
982 always = always colorize output;
983 never = never colorize output",
989 "Pretty-print the input instead of compiling;
990 valid types are: `normal` (un-annotated source),
991 `expanded` (crates expanded), or
992 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
998 "Remap source names in all output (compiler messages and output files)",
1005 pub fn get_cmd_lint_options(
1006 matches: &getopts::Matches,
1007 error_format: ErrorOutputType,
1008 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1009 let mut lint_opts_with_position = vec![];
1010 let mut describe_lints = false;
1012 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1013 for (arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1014 if lint_name == "help" {
1015 describe_lints = true;
1017 lint_opts_with_position.push((arg_pos, lint_name.replace("-", "_"), level));
1022 lint_opts_with_position.sort_by_key(|x| x.0);
1023 let lint_opts = lint_opts_with_position
1026 .map(|(_, lint_name, level)| (lint_name, level))
1029 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1030 lint::Level::from_str(&cap)
1031 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1033 (lint_opts, describe_lints, lint_cap)
1036 /// Parses the `--color` flag.
1037 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1038 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1039 Some("auto") => ColorConfig::Auto,
1040 Some("always") => ColorConfig::Always,
1041 Some("never") => ColorConfig::Never,
1043 None => ColorConfig::Auto,
1045 Some(arg) => early_error(
1046 ErrorOutputType::default(),
1048 "argument for `--color` must be auto, \
1049 always or never (instead was `{}`)",
1056 /// Parse the `--json` flag.
1058 /// The first value returned is how to render JSON diagnostics, and the second
1059 /// is whether or not artifact notifications are enabled.
1060 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1061 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1062 HumanReadableErrorType::Default;
1063 let mut json_color = ColorConfig::Never;
1064 let mut json_artifact_notifications = false;
1065 for option in matches.opt_strs("json") {
1066 // For now conservatively forbid `--color` with `--json` since `--json`
1067 // won't actually be emitting any colors and anything colorized is
1068 // embedded in a diagnostic message anyway.
1069 if matches.opt_str("color").is_some() {
1071 ErrorOutputType::default(),
1072 "cannot specify the `--color` option with `--json`",
1076 for sub_option in option.split(',') {
1078 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1079 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1080 "artifacts" => json_artifact_notifications = true,
1082 ErrorOutputType::default(),
1083 &format!("unknown `--json` option `{}`", s),
1088 (json_rendered(json_color), json_artifact_notifications)
1091 /// Parses the `--error-format` flag.
1092 pub fn parse_error_format(
1093 matches: &getopts::Matches,
1095 json_rendered: HumanReadableErrorType,
1096 ) -> ErrorOutputType {
1097 // We need the `opts_present` check because the driver will send us Matches
1098 // with only stable options if no unstable options are used. Since error-format
1099 // is unstable, it will not be present. We have to use `opts_present` not
1100 // `opt_present` because the latter will panic.
1101 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1102 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1103 None | Some("human") => {
1104 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1106 Some("human-annotate-rs") => {
1107 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1109 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1110 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1111 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1113 Some(arg) => early_error(
1114 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1116 "argument for `--error-format` must be `human`, `json` or \
1117 `short` (instead was `{}`)",
1123 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1126 match error_format {
1127 ErrorOutputType::Json { .. } => {}
1129 // Conservatively require that the `--json` argument is coupled with
1130 // `--error-format=json`. This means that `--json` is specified we
1131 // should actually be emitting JSON blobs.
1132 _ if matches.opt_strs("json").len() > 0 => {
1134 ErrorOutputType::default(),
1135 "using `--json` requires also using `--error-format=json`",
1142 return error_format;
1145 fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1146 let edition = match matches.opt_str("edition") {
1147 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1149 ErrorOutputType::default(),
1151 "argument for `--edition` must be one of: \
1152 {}. (instead was `{}`)",
1153 EDITION_NAME_LIST, arg
1157 None => DEFAULT_EDITION,
1160 if !edition.is_stable() && !nightly_options::is_nightly_build() {
1162 ErrorOutputType::default(),
1164 "edition {} is unstable and only \
1165 available for nightly builds of rustc.",
1174 fn check_debug_option_stability(
1175 debugging_opts: &DebuggingOptions,
1176 error_format: ErrorOutputType,
1177 json_rendered: HumanReadableErrorType,
1179 if !debugging_opts.unstable_options {
1180 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1182 ErrorOutputType::Json { pretty: false, json_rendered },
1183 "`--error-format=pretty-json` is unstable",
1186 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1190 ErrorOutputType::Json { pretty: false, json_rendered },
1191 "`--error-format=human-annotate-rs` is unstable",
1197 fn parse_output_types(
1198 debugging_opts: &DebuggingOptions,
1199 matches: &getopts::Matches,
1200 error_format: ErrorOutputType,
1202 let mut output_types = BTreeMap::new();
1203 if !debugging_opts.parse_only {
1204 for list in matches.opt_strs("emit") {
1205 for output_type in list.split(',') {
1206 let mut parts = output_type.splitn(2, '=');
1207 let shorthand = parts.next().unwrap();
1208 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1212 "unknown emission type: `{}` - expected one of: {}",
1214 OutputType::shorthands_display(),
1218 let path = parts.next().map(PathBuf::from);
1219 output_types.insert(output_type, path);
1223 if output_types.is_empty() {
1224 output_types.insert(OutputType::Exe, None);
1226 OutputTypes(output_types)
1229 fn should_override_cgus_and_disable_thinlto(
1230 output_types: &OutputTypes,
1231 matches: &getopts::Matches,
1232 error_format: ErrorOutputType,
1233 mut codegen_units: Option<usize>,
1234 ) -> (bool, Option<usize>) {
1235 let mut disable_thinlto = false;
1236 // Issue #30063: if user requests LLVM-related output to one
1237 // particular path, disable codegen-units.
1238 let incompatible: Vec<_> = output_types
1241 .map(|ot_path| ot_path.0)
1242 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1243 .map(|ot| ot.shorthand())
1245 if !incompatible.is_empty() {
1246 match codegen_units {
1247 Some(n) if n > 1 => {
1248 if matches.opt_present("o") {
1249 for ot in &incompatible {
1253 "`--emit={}` with `-o` incompatible with \
1254 `-C codegen-units=N` for N > 1",
1259 early_warn(error_format, "resetting to default -C codegen-units=1");
1260 codegen_units = Some(1);
1261 disable_thinlto = true;
1265 codegen_units = Some(1);
1266 disable_thinlto = true;
1271 if codegen_units == Some(0) {
1272 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1275 (disable_thinlto, codegen_units)
1278 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1279 if debugging_opts.threads == 0 {
1280 early_error(error_format, "value for threads must be a positive non-zero integer");
1283 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1284 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1288 fn select_incremental_path(
1289 debugging_opts: &DebuggingOptions,
1290 cg: &CodegenOptions,
1291 error_format: ErrorOutputType,
1292 ) -> Option<PathBuf> {
1293 match (&debugging_opts.incremental, &cg.incremental) {
1294 (Some(path1), Some(path2)) => {
1299 "conflicting paths for `-Z incremental` and \
1300 `-C incremental` specified: {} versus {}",
1308 (Some(path), None) => Some(path),
1309 (None, Some(path)) => Some(path),
1310 (None, None) => None,
1312 .map(|m| PathBuf::from(m))
1315 fn collect_print_requests(
1316 cg: &mut CodegenOptions,
1317 dopts: &mut DebuggingOptions,
1318 matches: &getopts::Matches,
1319 error_format: ErrorOutputType,
1320 ) -> Vec<PrintRequest> {
1321 let mut prints = Vec::<PrintRequest>::new();
1322 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1323 prints.push(PrintRequest::TargetCPUs);
1324 cg.target_cpu = None;
1326 if cg.target_feature == "help" {
1327 prints.push(PrintRequest::TargetFeatures);
1328 cg.target_feature = String::new();
1330 if cg.relocation_model.as_ref().map_or(false, |s| s == "help") {
1331 prints.push(PrintRequest::RelocationModels);
1332 cg.relocation_model = None;
1334 if cg.code_model.as_ref().map_or(false, |s| s == "help") {
1335 prints.push(PrintRequest::CodeModels);
1336 cg.code_model = None;
1338 if dopts.tls_model.as_ref().map_or(false, |s| s == "help") {
1339 prints.push(PrintRequest::TlsModels);
1340 dopts.tls_model = None;
1343 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1344 "crate-name" => PrintRequest::CrateName,
1345 "file-names" => PrintRequest::FileNames,
1346 "sysroot" => PrintRequest::Sysroot,
1347 "cfg" => PrintRequest::Cfg,
1348 "target-list" => PrintRequest::TargetList,
1349 "target-cpus" => PrintRequest::TargetCPUs,
1350 "target-features" => PrintRequest::TargetFeatures,
1351 "relocation-models" => PrintRequest::RelocationModels,
1352 "code-models" => PrintRequest::CodeModels,
1353 "tls-models" => PrintRequest::TlsModels,
1354 "native-static-libs" => PrintRequest::NativeStaticLibs,
1355 "target-spec-json" => {
1356 if dopts.unstable_options {
1357 PrintRequest::TargetSpec
1361 "the `-Z unstable-options` flag must also be passed to \
1362 enable the target-spec-json print option",
1366 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1372 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
1373 match matches.opt_str("target") {
1374 Some(target) if target.ends_with(".json") => {
1375 let path = Path::new(&target);
1376 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1377 early_error(error_format, &format!("target file {:?} does not exist", path))
1380 Some(target) => TargetTriple::TargetTriple(target),
1381 _ => TargetTriple::from_triple(host_triple()),
1386 matches: &getopts::Matches,
1387 cg: &CodegenOptions,
1388 error_format: ErrorOutputType,
1390 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1391 // to use them interchangeably. However, because they're technically different flags,
1392 // we need to work out manually which should take precedence if both are supplied (i.e.
1393 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1394 // comparing them. Note that if a flag is not found, its position will be `None`, which
1395 // always compared less than `Some(_)`.
1396 let max_o = matches.opt_positions("O").into_iter().max();
1402 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1409 match cg.opt_level.as_ref().map(String::as_ref) {
1410 None => OptLevel::No,
1411 Some("0") => OptLevel::No,
1412 Some("1") => OptLevel::Less,
1413 Some("2") => OptLevel::Default,
1414 Some("3") => OptLevel::Aggressive,
1415 Some("s") => OptLevel::Size,
1416 Some("z") => OptLevel::SizeMin,
1421 "optimization level needs to be \
1422 between 0-3, s or z (instead was `{}`)",
1431 fn select_debuginfo(
1432 matches: &getopts::Matches,
1433 cg: &CodegenOptions,
1434 error_format: ErrorOutputType,
1436 let max_g = matches.opt_positions("g").into_iter().max();
1442 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1449 match cg.debuginfo {
1450 None | Some(0) => DebugInfo::None,
1451 Some(1) => DebugInfo::Limited,
1452 Some(2) => DebugInfo::Full,
1457 "debug info level needs to be between \
1458 0-2 (instead was `{}`)",
1468 matches: &getopts::Matches,
1469 error_format: ErrorOutputType,
1470 ) -> Vec<(String, Option<String>, Option<NativeLibraryKind>)> {
1475 // Parse string of the form "[KIND=]lib[:new_name]",
1476 // where KIND is one of "dylib", "framework", "static".
1477 let mut parts = s.splitn(2, '=');
1478 let kind = parts.next().unwrap();
1479 let (name, kind) = match (parts.next(), kind) {
1480 (None, name) => (name, None),
1481 (Some(name), "dylib") => (name, Some(NativeLibraryKind::NativeUnknown)),
1482 (Some(name), "framework") => (name, Some(NativeLibraryKind::NativeFramework)),
1483 (Some(name), "static") => (name, Some(NativeLibraryKind::NativeStatic)),
1484 (Some(name), "static-nobundle") => {
1485 (name, Some(NativeLibraryKind::NativeStaticNobundle))
1491 "unknown library kind `{}`, expected \
1492 one of dylib, framework, or static",
1498 if kind == Some(NativeLibraryKind::NativeStaticNobundle)
1499 && !nightly_options::is_nightly_build()
1504 "the library kind 'static-nobundle' is only \
1505 accepted on the nightly compiler"
1509 let mut name_parts = name.splitn(2, ':');
1510 let name = name_parts.next().unwrap();
1511 let new_name = name_parts.next();
1512 (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
1517 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1518 match dopts.borrowck.as_ref().map(|s| &s[..]) {
1519 None | Some("migrate") => BorrowckMode::Migrate,
1520 Some("mir") => BorrowckMode::Mir,
1521 Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1525 pub fn parse_externs(
1526 matches: &getopts::Matches,
1527 debugging_opts: &DebuggingOptions,
1528 error_format: ErrorOutputType,
1530 let is_unstable_enabled = debugging_opts.unstable_options;
1531 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1532 for arg in matches.opt_strs("extern") {
1533 let mut parts = arg.splitn(2, '=');
1536 .unwrap_or_else(|| early_error(error_format, "--extern value must not be empty"));
1537 let path = parts.next().map(|s| s.to_string());
1539 let mut name_parts = name.splitn(2, ':');
1540 let first_part = name_parts.next();
1541 let second_part = name_parts.next();
1542 let (options, name) = match (first_part, second_part) {
1543 (Some(opts), Some(name)) => (Some(opts), name),
1544 (Some(name), None) => (None, name),
1545 (None, None) => early_error(error_format, "--extern name must not be empty"),
1546 _ => unreachable!(),
1549 let entry = externs.entry(name.to_owned());
1551 use std::collections::btree_map::Entry;
1553 let entry = if let Some(path) = path {
1554 // --extern prelude_name=some_file.rlib
1556 Entry::Vacant(vacant) => {
1557 let files = BTreeSet::from_iter(iter::once(path));
1558 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1560 Entry::Occupied(occupied) => {
1561 let ext_ent = occupied.into_mut();
1563 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1567 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1570 // Exact paths take precedence over search directories.
1571 let files = BTreeSet::from_iter(iter::once(path));
1572 *location = ExternLocation::ExactPaths(files);
1579 // --extern prelude_name
1581 Entry::Vacant(vacant) => {
1582 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1584 Entry::Occupied(occupied) => {
1585 // Ignore if already specified.
1591 let mut is_private_dep = false;
1592 let mut add_prelude = true;
1593 if let Some(opts) = options {
1594 if !is_unstable_enabled {
1597 "the `-Z unstable-options` flag must also be passed to \
1598 enable `--extern options",
1601 for opt in opts.split(',') {
1603 "priv" => is_private_dep = true,
1605 if let ExternLocation::ExactPaths(_) = &entry.location {
1606 add_prelude = false;
1610 "the `noprelude` --extern option requires a file path",
1614 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1619 // Crates start out being not private, and go to being private `priv`
1621 entry.is_private_dep |= is_private_dep;
1622 // If any flag is missing `noprelude`, then add to the prelude.
1623 entry.add_prelude |= add_prelude;
1628 fn parse_remap_path_prefix(
1629 matches: &getopts::Matches,
1630 error_format: ErrorOutputType,
1631 ) -> Vec<(PathBuf, PathBuf)> {
1633 .opt_strs("remap-path-prefix")
1636 let mut parts = remap.rsplitn(2, '='); // reverse iterator
1637 let to = parts.next();
1638 let from = parts.next();
1640 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
1643 "--remap-path-prefix must contain '=' between FROM and TO",
1650 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1651 let color = parse_color(matches);
1653 let edition = parse_crate_edition(matches);
1655 let (json_rendered, json_artifact_notifications) = parse_json(matches);
1657 let error_format = parse_error_format(matches, color, json_rendered);
1659 let unparsed_crate_types = matches.opt_strs("crate-type");
1660 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1661 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1663 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1665 let mut debugging_opts = build_debugging_options(matches, error_format);
1666 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1668 let output_types = parse_output_types(&debugging_opts, matches, error_format);
1670 let mut cg = build_codegen_options(matches, error_format);
1671 let (disable_thinlto, codegen_units) = should_override_cgus_and_disable_thinlto(
1678 check_thread_count(&debugging_opts, error_format);
1680 let incremental = select_incremental_path(&debugging_opts, &cg, error_format);
1682 if debugging_opts.profile && incremental.is_some() {
1685 "can't instrument with gcov profiling when compiling incrementally",
1689 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
1692 "options `-C profile-generate` and `-C profile-use` are exclusive",
1696 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
1700 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1701 let target_triple = parse_target_triple(matches, error_format);
1702 let opt_level = parse_opt_level(matches, &cg, error_format);
1703 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
1704 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
1705 // for more details.
1706 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1707 let debuginfo = select_debuginfo(matches, &cg, error_format);
1709 let mut search_paths = vec![];
1710 for s in &matches.opt_strs("L") {
1711 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
1714 let libs = parse_libs(matches, error_format);
1716 let test = matches.opt_present("test");
1718 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
1720 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
1721 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
1724 let externs = parse_externs(matches, &debugging_opts, error_format);
1726 let crate_name = matches.opt_str("crate-name");
1728 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
1730 let pretty = parse_pretty(matches, &debugging_opts, error_format);
1734 optimize: opt_level,
1741 maybe_sysroot: sysroot_opt,
1754 unstable_features: UnstableFeatures::from_environment(),
1756 actually_rustdoc: false,
1757 cli_forced_codegen_units: codegen_units,
1758 cli_forced_thinlto_off: disable_thinlto,
1761 json_artifact_notifications,
1767 matches: &getopts::Matches,
1768 debugging_opts: &DebuggingOptions,
1769 efmt: ErrorOutputType,
1770 ) -> Option<PpMode> {
1771 let pretty = if debugging_opts.unstable_options {
1772 matches.opt_default("pretty", "normal").map(|a| {
1773 // stable pretty-print variants only
1774 parse_pretty_inner(efmt, &a, false)
1780 return if pretty.is_none() {
1781 debugging_opts.unpretty.as_ref().map(|a| {
1782 // extended with unstable pretty-print variants
1783 parse_pretty_inner(efmt, &a, true)
1789 fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
1791 use PpSourceMode::*;
1792 let first = match (name, extended) {
1793 ("normal", _) => PpmSource(PpmNormal),
1794 ("identified", _) => PpmSource(PpmIdentified),
1795 ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
1796 ("expanded", _) => PpmSource(PpmExpanded),
1797 ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
1798 ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
1799 ("hir", true) => PpmHir(PpmNormal),
1800 ("hir,identified", true) => PpmHir(PpmIdentified),
1801 ("hir,typed", true) => PpmHir(PpmTyped),
1802 ("hir-tree", true) => PpmHirTree(PpmNormal),
1803 ("mir", true) => PpmMir,
1804 ("mir-cfg", true) => PpmMirCFG,
1810 "argument to `unpretty` must be one of `normal`, \
1811 `expanded`, `identified`, `expanded,identified`, \
1812 `expanded,hygiene`, `everybody_loops`, \
1813 `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
1814 `mir` or `mir-cfg`; got {}",
1822 "argument to `pretty` must be one of `normal`, \
1823 `expanded`, `identified`, or `expanded,identified`; got {}",
1834 pub fn make_crate_type_option() -> RustcOptGroup {
1838 "Comma separated list of types of crates
1839 for the compiler to emit",
1840 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
1844 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
1845 let mut crate_types: Vec<CrateType> = Vec::new();
1846 for unparsed_crate_type in &list_list {
1847 for part in unparsed_crate_type.split(',') {
1848 let new_part = match part {
1849 "lib" => default_lib_output(),
1850 "rlib" => CrateType::Rlib,
1851 "staticlib" => CrateType::Staticlib,
1852 "dylib" => CrateType::Dylib,
1853 "cdylib" => CrateType::Cdylib,
1854 "bin" => CrateType::Executable,
1855 "proc-macro" => CrateType::ProcMacro,
1856 _ => return Err(format!("unknown crate type: `{}`", part)),
1858 if !crate_types.contains(&new_part) {
1859 crate_types.push(new_part)
1867 pub mod nightly_options {
1868 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
1869 use crate::early_error;
1870 use rustc_feature::UnstableFeatures;
1872 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
1873 is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
1876 pub fn is_nightly_build() -> bool {
1877 UnstableFeatures::from_environment().is_nightly_build()
1880 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
1881 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
1882 let really_allows_unstable_options =
1883 UnstableFeatures::from_environment().is_nightly_build();
1885 for opt in flags.iter() {
1886 if opt.stability == OptionStability::Stable {
1889 if !matches.opt_present(opt.name) {
1892 if opt.name != "Z" && !has_z_unstable_option {
1894 ErrorOutputType::default(),
1896 "the `-Z unstable-options` flag must also be passed to enable \
1902 if really_allows_unstable_options {
1905 match opt.stability {
1906 OptionStability::Unstable => {
1908 "the option `{}` is only accepted on the \
1912 early_error(ErrorOutputType::default(), &msg);
1914 OptionStability::Stable => {}
1920 impl fmt::Display for CrateType {
1921 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1923 CrateType::Executable => "bin".fmt(f),
1924 CrateType::Dylib => "dylib".fmt(f),
1925 CrateType::Rlib => "rlib".fmt(f),
1926 CrateType::Staticlib => "staticlib".fmt(f),
1927 CrateType::Cdylib => "cdylib".fmt(f),
1928 CrateType::ProcMacro => "proc-macro".fmt(f),
1933 #[derive(Copy, Clone, PartialEq, Debug)]
1934 pub enum PpSourceMode {
1939 PpmExpandedIdentified,
1944 #[derive(Copy, Clone, PartialEq, Debug)]
1946 PpmSource(PpSourceMode),
1947 PpmHir(PpSourceMode),
1948 PpmHirTree(PpSourceMode),
1954 pub fn needs_ast_map(&self) -> bool {
1956 use PpSourceMode::*;
1958 PpmSource(PpmNormal) | PpmSource(PpmEveryBodyLoops) | PpmSource(PpmIdentified) => false,
1960 PpmSource(PpmExpanded)
1961 | PpmSource(PpmExpandedIdentified)
1962 | PpmSource(PpmExpandedHygiene)
1966 | PpmMirCFG => true,
1967 PpmSource(PpmTyped) => panic!("invalid state"),
1971 pub fn needs_analysis(&self) -> bool {
1974 PpmMir | PpmMirCFG => true,
1980 /// Command-line arguments passed to the compiler have to be incorporated with
1981 /// the dependency tracking system for incremental compilation. This module
1982 /// provides some utilities to make this more convenient.
1984 /// The values of all command-line arguments that are relevant for dependency
1985 /// tracking are hashed into a single value that determines whether the
1986 /// incremental compilation cache can be re-used or not. This hashing is done
1987 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
1988 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
1989 /// the hash of which is order dependent, but we might not want the order of
1990 /// arguments to make a difference for the hash).
1992 /// However, since the value provided by `Hash::hash` often *is* suitable,
1993 /// especially for primitive types, there is the
1994 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
1995 /// `Hash` implementation for `DepTrackingHash`. It's important though that
1996 /// we have an opt-in scheme here, so one is hopefully forced to think about
1997 /// how the hash should be calculated when adding a new command-line argument.
1998 crate mod dep_tracking {
2000 CFGuard, CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel,
2001 OutputTypes, Passes, Sanitizer, SwitchWithOptPath, SymbolManglingVersion,
2004 use crate::utils::NativeLibraryKind;
2005 use rustc_feature::UnstableFeatures;
2006 use rustc_span::edition::Edition;
2007 use rustc_target::spec::{MergeFunctions, PanicStrategy, RelroLevel, TargetTriple};
2008 use std::collections::hash_map::DefaultHasher;
2009 use std::collections::BTreeMap;
2010 use std::hash::Hash;
2011 use std::path::PathBuf;
2013 pub trait DepTrackingHash {
2014 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2017 macro_rules! impl_dep_tracking_hash_via_hash {
2019 impl DepTrackingHash for $t {
2020 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2021 Hash::hash(self, hasher);
2027 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2029 impl DepTrackingHash for Vec<$t> {
2030 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2031 let mut elems: Vec<&$t> = self.iter().collect();
2033 Hash::hash(&elems.len(), hasher);
2034 for (index, elem) in elems.iter().enumerate() {
2035 Hash::hash(&index, hasher);
2036 DepTrackingHash::hash(*elem, hasher, error_format);
2043 impl_dep_tracking_hash_via_hash!(bool);
2044 impl_dep_tracking_hash_via_hash!(usize);
2045 impl_dep_tracking_hash_via_hash!(u64);
2046 impl_dep_tracking_hash_via_hash!(String);
2047 impl_dep_tracking_hash_via_hash!(PathBuf);
2048 impl_dep_tracking_hash_via_hash!(lint::Level);
2049 impl_dep_tracking_hash_via_hash!(Option<bool>);
2050 impl_dep_tracking_hash_via_hash!(Option<usize>);
2051 impl_dep_tracking_hash_via_hash!(Option<String>);
2052 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2053 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2054 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2055 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2056 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2057 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2058 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2059 impl_dep_tracking_hash_via_hash!(Option<NativeLibraryKind>);
2060 impl_dep_tracking_hash_via_hash!(CrateType);
2061 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2062 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2063 impl_dep_tracking_hash_via_hash!(RelroLevel);
2064 impl_dep_tracking_hash_via_hash!(Passes);
2065 impl_dep_tracking_hash_via_hash!(OptLevel);
2066 impl_dep_tracking_hash_via_hash!(LtoCli);
2067 impl_dep_tracking_hash_via_hash!(DebugInfo);
2068 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2069 impl_dep_tracking_hash_via_hash!(OutputTypes);
2070 impl_dep_tracking_hash_via_hash!(NativeLibraryKind);
2071 impl_dep_tracking_hash_via_hash!(Sanitizer);
2072 impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
2073 impl_dep_tracking_hash_via_hash!(CFGuard);
2074 impl_dep_tracking_hash_via_hash!(TargetTriple);
2075 impl_dep_tracking_hash_via_hash!(Edition);
2076 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2077 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2078 impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
2080 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2081 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2082 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2083 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2084 impl_dep_tracking_hash_for_sortable_vec_of!((
2087 Option<NativeLibraryKind>
2089 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2090 impl_dep_tracking_hash_for_sortable_vec_of!(Sanitizer);
2092 impl<T1, T2> DepTrackingHash for (T1, T2)
2094 T1: DepTrackingHash,
2095 T2: DepTrackingHash,
2097 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2098 Hash::hash(&0, hasher);
2099 DepTrackingHash::hash(&self.0, hasher, error_format);
2100 Hash::hash(&1, hasher);
2101 DepTrackingHash::hash(&self.1, hasher, error_format);
2105 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2107 T1: DepTrackingHash,
2108 T2: DepTrackingHash,
2109 T3: DepTrackingHash,
2111 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2112 Hash::hash(&0, hasher);
2113 DepTrackingHash::hash(&self.0, hasher, error_format);
2114 Hash::hash(&1, hasher);
2115 DepTrackingHash::hash(&self.1, hasher, error_format);
2116 Hash::hash(&2, hasher);
2117 DepTrackingHash::hash(&self.2, hasher, error_format);
2121 // This is a stable hash because BTreeMap is a sorted container
2123 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2124 hasher: &mut DefaultHasher,
2125 error_format: ErrorOutputType,
2127 for (key, sub_hash) in sub_hashes {
2128 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2129 // the keys, as they are just plain strings
2130 Hash::hash(&key.len(), hasher);
2131 Hash::hash(key, hasher);
2132 sub_hash.hash(hasher, error_format);