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::NativeLibKind;
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;
13 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
15 use rustc_target::spec::{Target, TargetTriple};
17 use crate::parse::CrateConfig;
18 use rustc_feature::UnstableFeatures;
19 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST};
20 use rustc_span::source_map::{FileName, FilePathMapping};
21 use rustc_span::symbol::{sym, Symbol};
22 use rustc_span::SourceFileHashAlgorithm;
24 use rustc_errors::emitter::HumanReadableErrorType;
25 use rustc_errors::{ColorConfig, HandlerFlags};
27 use std::collections::btree_map::{
28 Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
30 use std::collections::{BTreeMap, BTreeSet};
32 use std::iter::{self, FromIterator};
33 use std::path::{Path, PathBuf};
34 use std::str::{self, FromStr};
42 #[derive(Default, RustcEncodable, RustcDecodable)]
43 pub struct SanitizerSet: u8 {
44 const ADDRESS = 1 << 0;
46 const MEMORY = 1 << 2;
47 const THREAD = 1 << 3;
51 /// Formats a sanitizer set as a comma separated list of sanitizers' names.
52 impl fmt::Display for SanitizerSet {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 SanitizerSet::ADDRESS => "address",
58 SanitizerSet::LEAK => "leak",
59 SanitizerSet::MEMORY => "memory",
60 SanitizerSet::THREAD => "thread",
61 _ => panic!("unrecognized sanitizer {:?}", s),
73 impl IntoIterator for SanitizerSet {
74 type Item = SanitizerSet;
75 type IntoIter = std::vec::IntoIter<SanitizerSet>;
77 fn into_iter(self) -> Self::IntoIter {
78 [SanitizerSet::ADDRESS, SanitizerSet::LEAK, SanitizerSet::MEMORY, SanitizerSet::THREAD]
81 .filter(|&s| self.contains(s))
87 impl<CTX> HashStable<CTX> for SanitizerSet {
88 fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
89 self.bits().hash_stable(ctx, hasher);
93 /// The different settings that the `-Z strip` flag can have.
94 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
96 /// Do not strip at all.
102 /// Strip all symbols.
106 /// The different settings that the `-C control-flow-guard` flag can have.
107 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
109 /// Do not emit Control Flow Guard metadata or checks.
112 /// Emit Control Flow Guard metadata but no checks.
115 /// Emit Control Flow Guard metadata and checks.
119 #[derive(Clone, Copy, Debug, PartialEq, Hash)]
129 impl_stable_hash_via_hash!(OptLevel);
131 /// This is what the `LtoCli` values get mapped to after resolving defaults and
132 /// and taking other command line options into account.
133 #[derive(Clone, PartialEq)]
135 /// Don't do any LTO whatsoever
138 /// Do a full crate graph LTO with ThinLTO
141 /// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
145 /// Do a full crate graph LTO with "fat" LTO
149 /// The different settings that the `-C lto` flag can have.
150 #[derive(Clone, Copy, PartialEq, Hash, Debug)]
162 /// No `-C lto` flag passed
166 #[derive(Clone, PartialEq, Hash)]
167 pub enum LinkerPluginLto {
168 LinkerPlugin(PathBuf),
173 impl LinkerPluginLto {
174 pub fn enabled(&self) -> bool {
176 LinkerPluginLto::LinkerPlugin(_) | LinkerPluginLto::LinkerPluginAuto => true,
177 LinkerPluginLto::Disabled => false,
182 #[derive(Clone, PartialEq, Hash)]
183 pub enum SwitchWithOptPath {
184 Enabled(Option<PathBuf>),
188 impl SwitchWithOptPath {
189 pub fn enabled(&self) -> bool {
191 SwitchWithOptPath::Enabled(_) => true,
192 SwitchWithOptPath::Disabled => false,
197 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
198 pub enum SymbolManglingVersion {
203 impl_stable_hash_via_hash!(SymbolManglingVersion);
205 #[derive(Clone, Copy, PartialEq, Hash)]
212 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
213 pub enum OutputType {
224 impl_stable_hash_via_hash!(OutputType);
227 fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
229 OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
231 | OutputType::Assembly
232 | OutputType::LlvmAssembly
234 | OutputType::Object => false,
238 fn shorthand(&self) -> &'static str {
240 OutputType::Bitcode => "llvm-bc",
241 OutputType::Assembly => "asm",
242 OutputType::LlvmAssembly => "llvm-ir",
243 OutputType::Mir => "mir",
244 OutputType::Object => "obj",
245 OutputType::Metadata => "metadata",
246 OutputType::Exe => "link",
247 OutputType::DepInfo => "dep-info",
251 fn from_shorthand(shorthand: &str) -> Option<Self> {
252 Some(match shorthand {
253 "asm" => OutputType::Assembly,
254 "llvm-ir" => OutputType::LlvmAssembly,
255 "mir" => OutputType::Mir,
256 "llvm-bc" => OutputType::Bitcode,
257 "obj" => OutputType::Object,
258 "metadata" => OutputType::Metadata,
259 "link" => OutputType::Exe,
260 "dep-info" => OutputType::DepInfo,
265 fn shorthands_display() -> String {
267 "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
268 OutputType::Bitcode.shorthand(),
269 OutputType::Assembly.shorthand(),
270 OutputType::LlvmAssembly.shorthand(),
271 OutputType::Mir.shorthand(),
272 OutputType::Object.shorthand(),
273 OutputType::Metadata.shorthand(),
274 OutputType::Exe.shorthand(),
275 OutputType::DepInfo.shorthand(),
279 pub fn extension(&self) -> &'static str {
281 OutputType::Bitcode => "bc",
282 OutputType::Assembly => "s",
283 OutputType::LlvmAssembly => "ll",
284 OutputType::Mir => "mir",
285 OutputType::Object => "o",
286 OutputType::Metadata => "rmeta",
287 OutputType::DepInfo => "d",
288 OutputType::Exe => "",
293 /// The type of diagnostics output to generate.
294 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
295 pub enum ErrorOutputType {
296 /// Output meant for the consumption of humans.
297 HumanReadable(HumanReadableErrorType),
298 /// Output that's consumed by other tools such as `rustfix` or the `RLS`.
300 /// Render the JSON in a human readable way (with indents and newlines).
302 /// The JSON output includes a `rendered` field that includes the rendered
304 json_rendered: HumanReadableErrorType,
308 impl Default for ErrorOutputType {
309 fn default() -> Self {
310 Self::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto))
314 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
315 /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
316 /// dependency tracking for command-line arguments.
317 #[derive(Clone, Hash)]
318 pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
320 impl_stable_hash_via_hash!(OutputTypes);
323 pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
324 OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
327 pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
331 pub fn contains_key(&self, key: &OutputType) -> bool {
332 self.0.contains_key(key)
335 pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
339 pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
343 pub fn len(&self) -> usize {
347 // Returns `true` if any of the output types require codegen or linking.
348 pub fn should_codegen(&self) -> bool {
349 self.0.keys().any(|k| match *k {
351 | OutputType::Assembly
352 | OutputType::LlvmAssembly
355 | OutputType::Exe => true,
356 OutputType::Metadata | OutputType::DepInfo => false,
361 /// Use tree-based collections to cheaply get a deterministic `Hash` implementation.
362 /// *Do not* switch `BTreeMap` or `BTreeSet` out for an unsorted container type! That
363 /// would break dependency tracking for command-line arguments.
365 pub struct Externs(BTreeMap<String, ExternEntry>);
367 #[derive(Clone, Debug)]
368 pub struct ExternEntry {
369 pub location: ExternLocation,
370 /// Indicates this is a "private" dependency for the
371 /// `exported_private_dependencies` lint.
373 /// This can be set with the `priv` option like
374 /// `--extern priv:name=foo.rlib`.
375 pub is_private_dep: bool,
376 /// Add the extern entry to the extern prelude.
378 /// This can be disabled with the `noprelude` option like
379 /// `--extern noprelude:name`.
380 pub add_prelude: bool,
383 #[derive(Clone, Debug)]
384 pub enum ExternLocation {
385 /// Indicates to look for the library in the search paths.
387 /// Added via `--extern name`.
388 FoundInLibrarySearchDirectories,
389 /// The locations where this extern entry must be found.
391 /// The `CrateLoader` is responsible for loading these and figuring out
392 /// which one to use.
394 /// Added via `--extern prelude_name=some_file.rlib`
395 ExactPaths(BTreeSet<String>),
399 pub fn new(data: BTreeMap<String, ExternEntry>) -> Externs {
403 pub fn get(&self, key: &str) -> Option<&ExternEntry> {
407 pub fn iter(&self) -> BTreeMapIter<'_, String, ExternEntry> {
413 fn new(location: ExternLocation) -> ExternEntry {
414 ExternEntry { location, is_private_dep: false, add_prelude: false }
417 pub fn files(&self) -> Option<impl Iterator<Item = &String>> {
418 match &self.location {
419 ExternLocation::ExactPaths(set) => Some(set.iter()),
425 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
426 pub enum PrintRequest {
442 #[derive(Copy, Clone)]
443 pub enum BorrowckMode {
449 /// Returns whether we should run the MIR-based borrow check, but also fall back
450 /// on the AST borrow check if the MIR-based one errors.
451 pub fn migrate(self) -> bool {
453 BorrowckMode::Mir => false,
454 BorrowckMode::Migrate => true,
460 /// Load source code from a file.
462 /// Load source code from a string.
464 /// A string that is shown in place of a filename.
466 /// An anonymous string containing the source code.
472 pub fn filestem(&self) -> &str {
474 Input::File(ref ifile) => ifile.file_stem().unwrap().to_str().unwrap(),
475 Input::Str { .. } => "rust_out",
479 pub fn get_input(&mut self) -> Option<&mut String> {
481 Input::File(_) => None,
482 Input::Str { ref mut input, .. } => Some(input),
486 pub fn source_name(&self) -> FileName {
488 Input::File(ref ifile) => ifile.clone().into(),
489 Input::Str { ref name, .. } => name.clone(),
494 #[derive(Clone, Hash)]
495 pub struct OutputFilenames {
496 pub out_directory: PathBuf,
498 pub single_output_file: Option<PathBuf>,
499 pub outputs: OutputTypes,
502 impl_stable_hash_via_hash!(OutputFilenames);
504 pub const RLINK_EXT: &str = "rlink";
505 pub const RUST_CGU_EXT: &str = "rcgu";
507 impl OutputFilenames {
509 out_directory: PathBuf,
510 out_filestem: String,
511 single_output_file: Option<PathBuf>,
513 outputs: OutputTypes,
519 filestem: format!("{}{}", out_filestem, extra),
523 pub fn path(&self, flavor: OutputType) -> PathBuf {
526 .and_then(|p| p.to_owned())
527 .or_else(|| self.single_output_file.clone())
528 .unwrap_or_else(|| self.temp_path(flavor, None))
531 /// Gets the path where a compilation artifact of the given type for the
532 /// given codegen unit should be placed on disk. If codegen_unit_name is
533 /// None, a path distinct from those of any codegen unit will be generated.
534 pub fn temp_path(&self, flavor: OutputType, codegen_unit_name: Option<&str>) -> PathBuf {
535 let extension = flavor.extension();
536 self.temp_path_ext(extension, codegen_unit_name)
539 /// Like temp_path, but also supports things where there is no corresponding
540 /// OutputType, like noopt-bitcode or lto-bitcode.
541 pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
542 let mut extension = String::new();
544 if let Some(codegen_unit_name) = codegen_unit_name {
545 extension.push_str(codegen_unit_name);
549 if !extension.is_empty() {
550 extension.push_str(".");
551 extension.push_str(RUST_CGU_EXT);
552 extension.push_str(".");
555 extension.push_str(ext);
558 self.with_extension(&extension)
561 pub fn with_extension(&self, extension: &str) -> PathBuf {
562 let mut path = self.out_directory.join(&self.filestem);
563 path.set_extension(extension);
568 pub fn host_triple() -> &'static str {
569 // Get the host triple out of the build environment. This ensures that our
570 // idea of the host triple is the same as for the set of libraries we've
571 // actually built. We can't just take LLVM's host triple because they
572 // normalize all ix86 architectures to i386.
574 // Instead of grabbing the host triple (for the current host), we grab (at
575 // compile time) the target triple that this rustc is built with and
576 // calling that (at runtime) the host triple.
577 (option_env!("CFG_COMPILER_HOST_TRIPLE")).expect("CFG_COMPILER_HOST_TRIPLE")
580 impl Default for Options {
581 fn default() -> Options {
583 crate_types: Vec::new(),
584 optimize: OptLevel::No,
585 debuginfo: DebugInfo::None,
586 lint_opts: Vec::new(),
588 describe_lints: false,
589 output_types: OutputTypes(BTreeMap::new()),
590 search_paths: vec![],
592 target_triple: TargetTriple::from_triple(host_triple()),
595 debugging_opts: basic_debugging_options(),
597 borrowck_mode: BorrowckMode::Migrate,
598 cg: basic_codegen_options(),
599 error_format: ErrorOutputType::default(),
600 externs: Externs(BTreeMap::new()),
604 unstable_features: UnstableFeatures::Disallow,
605 debug_assertions: true,
606 actually_rustdoc: false,
607 cli_forced_codegen_units: None,
608 cli_forced_thinlto_off: false,
609 remap_path_prefix: Vec::new(),
610 edition: DEFAULT_EDITION,
611 json_artifact_notifications: false,
618 /// Returns `true` if there is a reason to build the dep graph.
619 pub fn build_dep_graph(&self) -> bool {
620 self.incremental.is_some()
621 || self.debugging_opts.dump_dep_graph
622 || self.debugging_opts.query_dep_graph
626 pub fn enable_dep_node_debug_strs(&self) -> bool {
627 cfg!(debug_assertions)
628 && (self.debugging_opts.query_dep_graph || self.debugging_opts.incremental_info)
631 pub fn file_path_mapping(&self) -> FilePathMapping {
632 FilePathMapping::new(self.remap_path_prefix.clone())
635 /// Returns `true` if there will be an output file generated.
636 pub fn will_create_output_file(&self) -> bool {
637 !self.debugging_opts.parse_only && // The file is just being parsed
638 !self.debugging_opts.ls // The file is just being queried
642 pub fn share_generics(&self) -> bool {
643 match self.debugging_opts.share_generics {
644 Some(setting) => setting,
645 None => match self.optimize {
646 OptLevel::No | OptLevel::Less | OptLevel::Size | OptLevel::SizeMin => true,
647 OptLevel::Default | OptLevel::Aggressive => false,
653 impl DebuggingOptions {
654 pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
657 treat_err_as_bug: self.treat_err_as_bug,
658 dont_buffer_diagnostics: self.dont_buffer_diagnostics,
659 report_delayed_bugs: self.report_delayed_bugs,
660 macro_backtrace: self.macro_backtrace,
661 deduplicate_diagnostics: self.deduplicate_diagnostics,
666 // The type of entry function, so users can have their own entry functions
667 #[derive(Copy, Clone, PartialEq, Hash, Debug)]
668 pub enum EntryFnType {
673 impl_stable_hash_via_hash!(EntryFnType);
675 #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
685 impl_stable_hash_via_hash!(CrateType);
687 #[derive(Clone, Hash)]
694 pub fn is_empty(&self) -> bool {
696 Passes::Some(ref v) => v.is_empty(),
697 Passes::All => false,
702 pub const fn default_lib_output() -> CrateType {
706 pub fn default_configuration(sess: &Session) -> CrateConfig {
707 let end = &sess.target.target.target_endian;
708 let arch = &sess.target.target.arch;
709 let wordsz = &sess.target.target.target_pointer_width;
710 let os = &sess.target.target.target_os;
711 let env = &sess.target.target.target_env;
712 let vendor = &sess.target.target.target_vendor;
713 let min_atomic_width = sess.target.target.min_atomic_width();
714 let max_atomic_width = sess.target.target.max_atomic_width();
715 let atomic_cas = sess.target.target.options.atomic_cas;
717 let mut ret = FxHashSet::default();
718 ret.reserve(6); // the minimum number of insertions
720 ret.insert((sym::target_os, Some(Symbol::intern(os))));
721 if let Some(ref fam) = sess.target.target.options.target_family {
722 ret.insert((sym::target_family, Some(Symbol::intern(fam))));
723 if fam == "windows" {
724 ret.insert((sym::windows, None));
725 } else if fam == "unix" {
726 ret.insert((sym::unix, None));
729 ret.insert((sym::target_arch, Some(Symbol::intern(arch))));
730 ret.insert((sym::target_endian, Some(Symbol::intern(end))));
731 ret.insert((sym::target_pointer_width, Some(Symbol::intern(wordsz))));
732 ret.insert((sym::target_env, Some(Symbol::intern(env))));
733 ret.insert((sym::target_vendor, Some(Symbol::intern(vendor))));
734 if sess.target.target.options.has_elf_tls {
735 ret.insert((sym::target_thread_local, None));
737 for &i in &[8, 16, 32, 64, 128] {
738 if i >= min_atomic_width && i <= max_atomic_width {
739 let mut insert_atomic = |s| {
740 ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s))));
742 ret.insert((sym::target_has_atomic, Some(Symbol::intern(s))));
745 let s = i.to_string();
748 insert_atomic("ptr");
753 for s in sess.opts.debugging_opts.sanitizer {
754 let symbol = Symbol::intern(&s.to_string());
755 ret.insert((sym::sanitize, Some(symbol)));
758 if sess.opts.debug_assertions {
759 ret.insert((sym::debug_assertions, None));
761 if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
762 ret.insert((sym::proc_macro, None));
767 /// Converts the crate `cfg!` configuration from `String` to `Symbol`.
768 /// `rustc_interface::interface::Config` accepts this in the compiler configuration,
769 /// but the symbol interner is not yet set up then, so we must convert it later.
770 pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig {
771 cfg.into_iter().map(|(a, b)| (Symbol::intern(&a), b.map(|b| Symbol::intern(&b)))).collect()
774 pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
775 // Combine the configuration requested by the session (command line) with
776 // some default and generated configuration items.
777 let default_cfg = default_configuration(sess);
778 // If the user wants a test runner, then add the test cfg.
780 user_cfg.insert((sym::test, None));
782 user_cfg.extend(default_cfg.iter().cloned());
786 pub fn build_target_config(opts: &Options, error_format: ErrorOutputType) -> Config {
787 let target = Target::search(&opts.target_triple).unwrap_or_else(|e| {
791 "Error loading target specification: {}. \
792 Use `--print target-list` for a list of built-in targets",
798 let ptr_width = match &target.target_pointer_width[..] {
805 "target specification was invalid: \
806 unrecognized target-pointer-width {}",
812 Config { target, ptr_width }
815 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
816 pub enum OptionStability {
821 pub struct RustcOptGroup {
822 pub apply: Box<dyn Fn(&mut getopts::Options) -> &mut getopts::Options>,
823 pub name: &'static str,
824 pub stability: OptionStability,
828 pub fn is_stable(&self) -> bool {
829 self.stability == OptionStability::Stable
832 pub fn stable<F>(name: &'static str, f: F) -> RustcOptGroup
834 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
836 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Stable }
839 pub fn unstable<F>(name: &'static str, f: F) -> RustcOptGroup
841 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
843 RustcOptGroup { name, apply: Box::new(f), stability: OptionStability::Unstable }
847 // The `opt` local module holds wrappers around the `getopts` API that
848 // adds extra rustc-specific metadata to each option; such metadata
849 // is exposed by . The public
850 // functions below ending with `_u` are the functions that return
851 // *unstable* options, i.e., options that are only enabled when the
852 // user also passes the `-Z unstable-options` debugging flag.
854 // The `fn flag*` etc below are written so that we can use them
855 // in the future; do not warn about them not being used right now.
858 use super::RustcOptGroup;
860 pub type R = RustcOptGroup;
861 pub type S = &'static str;
863 fn stable<F>(name: S, f: F) -> R
865 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
867 RustcOptGroup::stable(name, f)
870 fn unstable<F>(name: S, f: F) -> R
872 F: Fn(&mut getopts::Options) -> &mut getopts::Options + 'static,
874 RustcOptGroup::unstable(name, f)
877 fn longer(a: S, b: S) -> S {
878 if a.len() > b.len() { a } else { b }
881 pub fn opt_s(a: S, b: S, c: S, d: S) -> R {
882 stable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
884 pub fn multi_s(a: S, b: S, c: S, d: S) -> R {
885 stable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
887 pub fn flag_s(a: S, b: S, c: S) -> R {
888 stable(longer(a, b), move |opts| opts.optflag(a, b, c))
890 pub fn flagopt_s(a: S, b: S, c: S, d: S) -> R {
891 stable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
893 pub fn flagmulti_s(a: S, b: S, c: S) -> R {
894 stable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
897 pub fn opt(a: S, b: S, c: S, d: S) -> R {
898 unstable(longer(a, b), move |opts| opts.optopt(a, b, c, d))
900 pub fn multi(a: S, b: S, c: S, d: S) -> R {
901 unstable(longer(a, b), move |opts| opts.optmulti(a, b, c, d))
903 pub fn flag(a: S, b: S, c: S) -> R {
904 unstable(longer(a, b), move |opts| opts.optflag(a, b, c))
906 pub fn flagopt(a: S, b: S, c: S, d: S) -> R {
907 unstable(longer(a, b), move |opts| opts.optflagopt(a, b, c, d))
909 pub fn flagmulti(a: S, b: S, c: S) -> R {
910 unstable(longer(a, b), move |opts| opts.optflagmulti(a, b, c))
914 /// Returns the "short" subset of the rustc command line options,
915 /// including metadata for each option, such as whether the option is
916 /// part of the stable long-term interface for rustc.
917 pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
919 opt::flag_s("h", "help", "Display this message"),
920 opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
924 "Add a directory to the library search path. The
925 optional KIND can be one of dependency, crate, native,
926 framework, or all (the default).",
932 "Link the generated crate(s) to the specified native
933 library NAME. The optional KIND can be one of
934 static, framework, or dylib (the default).",
937 make_crate_type_option(),
938 opt::opt_s("", "crate-name", "Specify the name of the crate being built", "NAME"),
942 "Specify which edition of the compiler to use when compiling code.",
948 "Comma separated list of types of output for \
949 the compiler to emit",
950 "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
955 "Compiler information to print on stdout",
956 "[crate-name|file-names|sysroot|target-libdir|cfg|target-list|\
957 target-cpus|target-features|relocation-models|\
958 code-models|tls-models|target-spec-json|native-static-libs]",
960 opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
961 opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
962 opt::opt_s("o", "", "Write output to <filename>", "FILENAME"),
966 "Write output to compiler-chosen filename \
973 "Provide a detailed explanation of an error \
977 opt::flag_s("", "test", "Build a test harness"),
978 opt::opt_s("", "target", "Target triple for which the code is compiled", "TARGET"),
979 opt::multi_s("W", "warn", "Set lint warnings", "OPT"),
980 opt::multi_s("A", "allow", "Set lint allowed", "OPT"),
981 opt::multi_s("D", "deny", "Set lint denied", "OPT"),
982 opt::multi_s("F", "forbid", "Set lint forbidden", "OPT"),
986 "Set the most restrictive lint level. \
987 More restrictive lints are capped at this \
991 opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"),
992 opt::flag_s("V", "version", "Print version info and exit"),
993 opt::flag_s("v", "verbose", "Use verbose output"),
997 /// Returns all rustc command line options, including metadata for
998 /// each option, such as whether the option is part of the stable
999 /// long-term interface for rustc.
1000 pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
1001 let mut opts = rustc_short_optgroups();
1006 "Specify where an external rust library is located",
1009 opt::opt_s("", "sysroot", "Override the system root", "PATH"),
1010 opt::multi("Z", "", "Set internal debugging options", "FLAG"),
1014 "How errors and other messages are produced",
1017 opt::multi_s("", "json", "Configure the JSON output of the compiler", "CONFIG"),
1021 "Configure coloring of output:
1022 auto = colorize, if output goes to a tty (default);
1023 always = always colorize output;
1024 never = never colorize output",
1025 "auto|always|never",
1030 "Pretty-print the input instead of compiling;
1031 valid types are: `normal` (un-annotated source),
1032 `expanded` (crates expanded), or
1033 `expanded,identified` (fully parenthesized, AST nodes with IDs).",
1038 "remap-path-prefix",
1039 "Remap source names in all output (compiler messages and output files)",
1046 pub fn get_cmd_lint_options(
1047 matches: &getopts::Matches,
1048 error_format: ErrorOutputType,
1049 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
1050 let mut lint_opts_with_position = vec![];
1051 let mut describe_lints = false;
1053 for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] {
1054 for (passed_arg_pos, lint_name) in matches.opt_strs_pos(level.as_str()) {
1055 let arg_pos = if let lint::Forbid = level {
1056 // HACK: forbid is always specified last, so it can't be overridden.
1057 // FIXME: remove this once <https://github.com/rust-lang/rust/issues/70819> is
1058 // fixed and `forbid` works as expected.
1063 if lint_name == "help" {
1064 describe_lints = true;
1066 lint_opts_with_position.push((arg_pos, lint_name.replace("-", "_"), level));
1071 lint_opts_with_position.sort_by_key(|x| x.0);
1072 let lint_opts = lint_opts_with_position
1075 .map(|(_, lint_name, level)| (lint_name, level))
1078 let lint_cap = matches.opt_str("cap-lints").map(|cap| {
1079 lint::Level::from_str(&cap)
1080 .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap)))
1082 (lint_opts, describe_lints, lint_cap)
1085 /// Parses the `--color` flag.
1086 pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
1087 match matches.opt_str("color").as_ref().map(|s| &s[..]) {
1088 Some("auto") => ColorConfig::Auto,
1089 Some("always") => ColorConfig::Always,
1090 Some("never") => ColorConfig::Never,
1092 None => ColorConfig::Auto,
1094 Some(arg) => early_error(
1095 ErrorOutputType::default(),
1097 "argument for `--color` must be auto, \
1098 always or never (instead was `{}`)",
1105 /// Parse the `--json` flag.
1107 /// The first value returned is how to render JSON diagnostics, and the second
1108 /// is whether or not artifact notifications are enabled.
1109 pub fn parse_json(matches: &getopts::Matches) -> (HumanReadableErrorType, bool) {
1110 let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
1111 HumanReadableErrorType::Default;
1112 let mut json_color = ColorConfig::Never;
1113 let mut json_artifact_notifications = false;
1114 for option in matches.opt_strs("json") {
1115 // For now conservatively forbid `--color` with `--json` since `--json`
1116 // won't actually be emitting any colors and anything colorized is
1117 // embedded in a diagnostic message anyway.
1118 if matches.opt_str("color").is_some() {
1120 ErrorOutputType::default(),
1121 "cannot specify the `--color` option with `--json`",
1125 for sub_option in option.split(',') {
1127 "diagnostic-short" => json_rendered = HumanReadableErrorType::Short,
1128 "diagnostic-rendered-ansi" => json_color = ColorConfig::Always,
1129 "artifacts" => json_artifact_notifications = true,
1131 ErrorOutputType::default(),
1132 &format!("unknown `--json` option `{}`", s),
1137 (json_rendered(json_color), json_artifact_notifications)
1140 /// Parses the `--error-format` flag.
1141 pub fn parse_error_format(
1142 matches: &getopts::Matches,
1144 json_rendered: HumanReadableErrorType,
1145 ) -> ErrorOutputType {
1146 // We need the `opts_present` check because the driver will send us Matches
1147 // with only stable options if no unstable options are used. Since error-format
1148 // is unstable, it will not be present. We have to use `opts_present` not
1149 // `opt_present` because the latter will panic.
1150 let error_format = if matches.opts_present(&["error-format".to_owned()]) {
1151 match matches.opt_str("error-format").as_ref().map(|s| &s[..]) {
1152 None | Some("human") => {
1153 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1155 Some("human-annotate-rs") => {
1156 ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(color))
1158 Some("json") => ErrorOutputType::Json { pretty: false, json_rendered },
1159 Some("pretty-json") => ErrorOutputType::Json { pretty: true, json_rendered },
1160 Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
1162 Some(arg) => early_error(
1163 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
1165 "argument for `--error-format` must be `human`, `json` or \
1166 `short` (instead was `{}`)",
1172 ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color))
1175 match error_format {
1176 ErrorOutputType::Json { .. } => {}
1178 // Conservatively require that the `--json` argument is coupled with
1179 // `--error-format=json`. This means that `--json` is specified we
1180 // should actually be emitting JSON blobs.
1181 _ if !matches.opt_strs("json").is_empty() => {
1183 ErrorOutputType::default(),
1184 "using `--json` requires also using `--error-format=json`",
1194 fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
1195 let edition = match matches.opt_str("edition") {
1196 Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
1198 ErrorOutputType::default(),
1200 "argument for `--edition` must be one of: \
1201 {}. (instead was `{}`)",
1202 EDITION_NAME_LIST, arg
1206 None => DEFAULT_EDITION,
1209 if !edition.is_stable() && !nightly_options::is_nightly_build() {
1211 ErrorOutputType::default(),
1213 "edition {} is unstable and only \
1214 available for nightly builds of rustc.",
1223 fn check_debug_option_stability(
1224 debugging_opts: &DebuggingOptions,
1225 error_format: ErrorOutputType,
1226 json_rendered: HumanReadableErrorType,
1228 if !debugging_opts.unstable_options {
1229 if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
1231 ErrorOutputType::Json { pretty: false, json_rendered },
1232 "`--error-format=pretty-json` is unstable",
1235 if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
1239 ErrorOutputType::Json { pretty: false, json_rendered },
1240 "`--error-format=human-annotate-rs` is unstable",
1246 fn parse_output_types(
1247 debugging_opts: &DebuggingOptions,
1248 matches: &getopts::Matches,
1249 error_format: ErrorOutputType,
1251 let mut output_types = BTreeMap::new();
1252 if !debugging_opts.parse_only {
1253 for list in matches.opt_strs("emit") {
1254 for output_type in list.split(',') {
1255 let mut parts = output_type.splitn(2, '=');
1256 let shorthand = parts.next().unwrap();
1257 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
1261 "unknown emission type: `{}` - expected one of: {}",
1263 OutputType::shorthands_display(),
1267 let path = parts.next().map(PathBuf::from);
1268 output_types.insert(output_type, path);
1272 if output_types.is_empty() {
1273 output_types.insert(OutputType::Exe, None);
1275 OutputTypes(output_types)
1278 fn should_override_cgus_and_disable_thinlto(
1279 output_types: &OutputTypes,
1280 matches: &getopts::Matches,
1281 error_format: ErrorOutputType,
1282 mut codegen_units: Option<usize>,
1283 ) -> (bool, Option<usize>) {
1284 let mut disable_thinlto = false;
1285 // Issue #30063: if user requests LLVM-related output to one
1286 // particular path, disable codegen-units.
1287 let incompatible: Vec<_> = output_types
1290 .map(|ot_path| ot_path.0)
1291 .filter(|ot| !ot.is_compatible_with_codegen_units_and_single_output_file())
1292 .map(|ot| ot.shorthand())
1294 if !incompatible.is_empty() {
1295 match codegen_units {
1296 Some(n) if n > 1 => {
1297 if matches.opt_present("o") {
1298 for ot in &incompatible {
1302 "`--emit={}` with `-o` incompatible with \
1303 `-C codegen-units=N` for N > 1",
1308 early_warn(error_format, "resetting to default -C codegen-units=1");
1309 codegen_units = Some(1);
1310 disable_thinlto = true;
1314 codegen_units = Some(1);
1315 disable_thinlto = true;
1320 if codegen_units == Some(0) {
1321 early_error(error_format, "value for codegen units must be a positive non-zero integer");
1324 (disable_thinlto, codegen_units)
1327 fn check_thread_count(debugging_opts: &DebuggingOptions, error_format: ErrorOutputType) {
1328 if debugging_opts.threads == 0 {
1329 early_error(error_format, "value for threads must be a positive non-zero integer");
1332 if debugging_opts.threads > 1 && debugging_opts.fuel.is_some() {
1333 early_error(error_format, "optimization fuel is incompatible with multiple threads");
1337 fn collect_print_requests(
1338 cg: &mut CodegenOptions,
1339 dopts: &mut DebuggingOptions,
1340 matches: &getopts::Matches,
1341 error_format: ErrorOutputType,
1342 ) -> Vec<PrintRequest> {
1343 let mut prints = Vec::<PrintRequest>::new();
1344 if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
1345 prints.push(PrintRequest::TargetCPUs);
1346 cg.target_cpu = None;
1348 if cg.target_feature == "help" {
1349 prints.push(PrintRequest::TargetFeatures);
1350 cg.target_feature = String::new();
1353 prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
1354 "crate-name" => PrintRequest::CrateName,
1355 "file-names" => PrintRequest::FileNames,
1356 "sysroot" => PrintRequest::Sysroot,
1357 "target-libdir" => PrintRequest::TargetLibdir,
1358 "cfg" => PrintRequest::Cfg,
1359 "target-list" => PrintRequest::TargetList,
1360 "target-cpus" => PrintRequest::TargetCPUs,
1361 "target-features" => PrintRequest::TargetFeatures,
1362 "relocation-models" => PrintRequest::RelocationModels,
1363 "code-models" => PrintRequest::CodeModels,
1364 "tls-models" => PrintRequest::TlsModels,
1365 "native-static-libs" => PrintRequest::NativeStaticLibs,
1366 "target-spec-json" => {
1367 if dopts.unstable_options {
1368 PrintRequest::TargetSpec
1372 "the `-Z unstable-options` flag must also be passed to \
1373 enable the target-spec-json print option",
1377 req => early_error(error_format, &format!("unknown print request `{}`", req)),
1383 fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple {
1384 match matches.opt_str("target") {
1385 Some(target) if target.ends_with(".json") => {
1386 let path = Path::new(&target);
1387 TargetTriple::from_path(&path).unwrap_or_else(|_| {
1388 early_error(error_format, &format!("target file {:?} does not exist", path))
1391 Some(target) => TargetTriple::TargetTriple(target),
1392 _ => TargetTriple::from_triple(host_triple()),
1397 matches: &getopts::Matches,
1398 cg: &CodegenOptions,
1399 error_format: ErrorOutputType,
1401 // The `-O` and `-C opt-level` flags specify the same setting, so we want to be able
1402 // to use them interchangeably. However, because they're technically different flags,
1403 // we need to work out manually which should take precedence if both are supplied (i.e.
1404 // the rightmost flag). We do this by finding the (rightmost) position of both flags and
1405 // comparing them. Note that if a flag is not found, its position will be `None`, which
1406 // always compared less than `Some(_)`.
1407 let max_o = matches.opt_positions("O").into_iter().max();
1413 if let Some("opt-level") = s.splitn(2, '=').next() { Some(i) } else { None }
1420 match cg.opt_level.as_ref() {
1421 "0" => OptLevel::No,
1422 "1" => OptLevel::Less,
1423 "2" => OptLevel::Default,
1424 "3" => OptLevel::Aggressive,
1425 "s" => OptLevel::Size,
1426 "z" => OptLevel::SizeMin,
1431 "optimization level needs to be \
1432 between 0-3, s or z (instead was `{}`)",
1441 fn select_debuginfo(
1442 matches: &getopts::Matches,
1443 cg: &CodegenOptions,
1444 error_format: ErrorOutputType,
1446 let max_g = matches.opt_positions("g").into_iter().max();
1452 if let Some("debuginfo") = s.splitn(2, '=').next() { Some(i) } else { None }
1459 match cg.debuginfo {
1460 0 => DebugInfo::None,
1461 1 => DebugInfo::Limited,
1462 2 => DebugInfo::Full,
1467 "debug info level needs to be between \
1468 0-2 (instead was `{}`)",
1478 matches: &getopts::Matches,
1479 error_format: ErrorOutputType,
1480 ) -> Vec<(String, Option<String>, NativeLibKind)> {
1485 // Parse string of the form "[KIND=]lib[:new_name]",
1486 // where KIND is one of "dylib", "framework", "static".
1487 let mut parts = s.splitn(2, '=');
1488 let kind = parts.next().unwrap();
1489 let (name, kind) = match (parts.next(), kind) {
1490 (None, name) => (name, NativeLibKind::Unspecified),
1491 (Some(name), "dylib") => (name, NativeLibKind::Dylib),
1492 (Some(name), "framework") => (name, NativeLibKind::Framework),
1493 (Some(name), "static") => (name, NativeLibKind::StaticBundle),
1494 (Some(name), "static-nobundle") => (name, NativeLibKind::StaticNoBundle),
1499 "unknown library kind `{}`, expected \
1500 one of dylib, framework, or static",
1506 if kind == NativeLibKind::StaticNoBundle && !nightly_options::is_nightly_build() {
1509 "the library kind 'static-nobundle' is only \
1510 accepted on the nightly compiler",
1513 let mut name_parts = name.splitn(2, ':');
1514 let name = name_parts.next().unwrap();
1515 let new_name = name_parts.next();
1516 (name.to_owned(), new_name.map(|n| n.to_owned()), kind)
1521 fn parse_borrowck_mode(dopts: &DebuggingOptions, error_format: ErrorOutputType) -> BorrowckMode {
1522 match dopts.borrowck.as_ref() {
1523 "migrate" => BorrowckMode::Migrate,
1524 "mir" => BorrowckMode::Mir,
1525 m => early_error(error_format, &format!("unknown borrowck mode `{}`", m)),
1529 pub fn parse_externs(
1530 matches: &getopts::Matches,
1531 debugging_opts: &DebuggingOptions,
1532 error_format: ErrorOutputType,
1534 let is_unstable_enabled = debugging_opts.unstable_options;
1535 let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
1536 for arg in matches.opt_strs("extern") {
1537 let mut parts = arg.splitn(2, '=');
1540 .unwrap_or_else(|| early_error(error_format, "--extern value must not be empty"));
1541 let path = parts.next().map(|s| s.to_string());
1543 let mut name_parts = name.splitn(2, ':');
1544 let first_part = name_parts.next();
1545 let second_part = name_parts.next();
1546 let (options, name) = match (first_part, second_part) {
1547 (Some(opts), Some(name)) => (Some(opts), name),
1548 (Some(name), None) => (None, name),
1549 (None, None) => early_error(error_format, "--extern name must not be empty"),
1550 _ => unreachable!(),
1553 let entry = externs.entry(name.to_owned());
1555 use std::collections::btree_map::Entry;
1557 let entry = if let Some(path) = path {
1558 // --extern prelude_name=some_file.rlib
1560 Entry::Vacant(vacant) => {
1561 let files = BTreeSet::from_iter(iter::once(path));
1562 vacant.insert(ExternEntry::new(ExternLocation::ExactPaths(files)))
1564 Entry::Occupied(occupied) => {
1565 let ext_ent = occupied.into_mut();
1567 ExternEntry { location: ExternLocation::ExactPaths(files), .. } => {
1571 location: location @ ExternLocation::FoundInLibrarySearchDirectories,
1574 // Exact paths take precedence over search directories.
1575 let files = BTreeSet::from_iter(iter::once(path));
1576 *location = ExternLocation::ExactPaths(files);
1583 // --extern prelude_name
1585 Entry::Vacant(vacant) => {
1586 vacant.insert(ExternEntry::new(ExternLocation::FoundInLibrarySearchDirectories))
1588 Entry::Occupied(occupied) => {
1589 // Ignore if already specified.
1595 let mut is_private_dep = false;
1596 let mut add_prelude = true;
1597 if let Some(opts) = options {
1598 if !is_unstable_enabled {
1601 "the `-Z unstable-options` flag must also be passed to \
1602 enable `--extern options",
1605 for opt in opts.split(',') {
1607 "priv" => is_private_dep = true,
1609 if let ExternLocation::ExactPaths(_) = &entry.location {
1610 add_prelude = false;
1614 "the `noprelude` --extern option requires a file path",
1618 _ => early_error(error_format, &format!("unknown --extern option `{}`", opt)),
1623 // Crates start out being not private, and go to being private `priv`
1625 entry.is_private_dep |= is_private_dep;
1626 // If any flag is missing `noprelude`, then add to the prelude.
1627 entry.add_prelude |= add_prelude;
1632 fn parse_remap_path_prefix(
1633 matches: &getopts::Matches,
1634 error_format: ErrorOutputType,
1635 ) -> Vec<(PathBuf, PathBuf)> {
1637 .opt_strs("remap-path-prefix")
1640 let mut parts = remap.rsplitn(2, '='); // reverse iterator
1641 let to = parts.next();
1642 let from = parts.next();
1644 (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
1647 "--remap-path-prefix must contain '=' between FROM and TO",
1654 pub fn build_session_options(matches: &getopts::Matches) -> Options {
1655 let color = parse_color(matches);
1657 let edition = parse_crate_edition(matches);
1659 let (json_rendered, json_artifact_notifications) = parse_json(matches);
1661 let error_format = parse_error_format(matches, color, json_rendered);
1663 let unparsed_crate_types = matches.opt_strs("crate-type");
1664 let crate_types = parse_crate_types_from_list(unparsed_crate_types)
1665 .unwrap_or_else(|e| early_error(error_format, &e[..]));
1667 let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
1669 let mut debugging_opts = build_debugging_options(matches, error_format);
1670 check_debug_option_stability(&debugging_opts, error_format, json_rendered);
1672 let output_types = parse_output_types(&debugging_opts, matches, error_format);
1674 let mut cg = build_codegen_options(matches, error_format);
1675 let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
1682 check_thread_count(&debugging_opts, error_format);
1684 let incremental = cg.incremental.as_ref().map(PathBuf::from);
1686 if debugging_opts.profile && incremental.is_some() {
1689 "can't instrument with gcov profiling when compiling incrementally",
1692 if debugging_opts.profile {
1693 match codegen_units {
1695 None => codegen_units = Some(1),
1696 Some(_) => early_error(
1698 "can't instrument with gcov profiling with multiple codegen units",
1703 if cg.profile_generate.enabled() && cg.profile_use.is_some() {
1706 "options `-C profile-generate` and `-C profile-use` are exclusive",
1710 if debugging_opts.instrument_coverage {
1711 if cg.profile_generate.enabled() || cg.profile_use.is_some() {
1714 "option `-Z instrument-coverage` is not compatible with either `-C profile-use` \
1715 or `-C profile-generate`",
1719 // `-Z instrument-coverage` implies:
1720 // * `-Z symbol-mangling-version=v0` - to ensure consistent and reversable name mangling.
1721 // Note, LLVM coverage tools can analyze coverage over multiple runs, including some
1722 // changes to source code; so mangled names must be consistent across compilations.
1723 // * `-C link-dead-code` - so unexecuted code is still counted as zero, rather than be
1724 // optimized out. Note that instrumenting dead code can be explicitly disabled with:
1725 // `-Z instrument-coverage -C link-dead-code=no`.
1726 debugging_opts.symbol_mangling_version = SymbolManglingVersion::V0;
1727 if cg.link_dead_code == None {
1728 // FIXME(richkadel): Investigate if the `instrument-coverage` implementation can
1729 // inject ["zero counters"](https://llvm.org/docs/CoverageMappingFormat.html#counter)
1730 // in the coverage map when "dead code" is removed, rather than forcing `link-dead-code`.
1731 cg.link_dead_code = Some(true);
1735 if !cg.embed_bitcode {
1737 LtoCli::No | LtoCli::Unspecified => {}
1738 LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => early_error(
1740 "options `-C embed-bitcode=no` and `-C lto` are incompatible",
1745 let prints = collect_print_requests(&mut cg, &mut debugging_opts, matches, error_format);
1749 let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
1750 let target_triple = parse_target_triple(matches, error_format);
1751 let opt_level = parse_opt_level(matches, &cg, error_format);
1752 // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
1753 // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
1754 // for more details.
1755 let debug_assertions = cg.debug_assertions.unwrap_or(opt_level == OptLevel::No);
1756 let debuginfo = select_debuginfo(matches, &cg, error_format);
1758 let mut search_paths = vec![];
1759 for s in &matches.opt_strs("L") {
1760 search_paths.push(SearchPath::from_cli_opt(&s[..], error_format));
1763 let libs = parse_libs(matches, error_format);
1765 let test = matches.opt_present("test");
1767 let borrowck_mode = parse_borrowck_mode(&debugging_opts, error_format);
1769 if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
1770 early_warn(error_format, "-C remark requires \"-C debuginfo=n\" to show source locations");
1773 let externs = parse_externs(matches, &debugging_opts, error_format);
1775 let crate_name = matches.opt_str("crate-name");
1777 let remap_path_prefix = parse_remap_path_prefix(matches, error_format);
1779 let pretty = parse_pretty(matches, &debugging_opts, error_format);
1783 optimize: opt_level,
1790 maybe_sysroot: sysroot_opt,
1803 unstable_features: UnstableFeatures::from_environment(),
1805 actually_rustdoc: false,
1806 cli_forced_codegen_units: codegen_units,
1807 cli_forced_thinlto_off: disable_thinlto,
1810 json_artifact_notifications,
1816 matches: &getopts::Matches,
1817 debugging_opts: &DebuggingOptions,
1818 efmt: ErrorOutputType,
1819 ) -> Option<PpMode> {
1820 let pretty = if debugging_opts.unstable_options {
1821 matches.opt_default("pretty", "normal").map(|a| {
1822 // stable pretty-print variants only
1823 parse_pretty_inner(efmt, &a, false)
1829 return if pretty.is_none() {
1830 debugging_opts.unpretty.as_ref().map(|a| {
1831 // extended with unstable pretty-print variants
1832 parse_pretty_inner(efmt, &a, true)
1838 fn parse_pretty_inner(efmt: ErrorOutputType, name: &str, extended: bool) -> PpMode {
1840 use PpSourceMode::*;
1841 let first = match (name, extended) {
1842 ("normal", _) => PpmSource(PpmNormal),
1843 ("identified", _) => PpmSource(PpmIdentified),
1844 ("everybody_loops", true) => PpmSource(PpmEveryBodyLoops),
1845 ("expanded", _) => PpmSource(PpmExpanded),
1846 ("expanded,identified", _) => PpmSource(PpmExpandedIdentified),
1847 ("expanded,hygiene", _) => PpmSource(PpmExpandedHygiene),
1848 ("hir", true) => PpmHir(PpmNormal),
1849 ("hir,identified", true) => PpmHir(PpmIdentified),
1850 ("hir,typed", true) => PpmHir(PpmTyped),
1851 ("hir-tree", true) => PpmHirTree(PpmNormal),
1852 ("mir", true) => PpmMir,
1853 ("mir-cfg", true) => PpmMirCFG,
1859 "argument to `unpretty` must be one of `normal`, \
1860 `expanded`, `identified`, `expanded,identified`, \
1861 `expanded,hygiene`, `everybody_loops`, \
1862 `hir`, `hir,identified`, `hir,typed`, `hir-tree`, \
1863 `mir` or `mir-cfg`; got {}",
1871 "argument to `pretty` must be one of `normal`, \
1872 `expanded`, `identified`, or `expanded,identified`; got {}",
1879 log::debug!("got unpretty option: {:?}", first);
1884 pub fn make_crate_type_option() -> RustcOptGroup {
1888 "Comma separated list of types of crates
1889 for the compiler to emit",
1890 "[bin|lib|rlib|dylib|cdylib|staticlib|proc-macro]",
1894 pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
1895 let mut crate_types: Vec<CrateType> = Vec::new();
1896 for unparsed_crate_type in &list_list {
1897 for part in unparsed_crate_type.split(',') {
1898 let new_part = match part {
1899 "lib" => default_lib_output(),
1900 "rlib" => CrateType::Rlib,
1901 "staticlib" => CrateType::Staticlib,
1902 "dylib" => CrateType::Dylib,
1903 "cdylib" => CrateType::Cdylib,
1904 "bin" => CrateType::Executable,
1905 "proc-macro" => CrateType::ProcMacro,
1906 _ => return Err(format!("unknown crate type: `{}`", part)),
1908 if !crate_types.contains(&new_part) {
1909 crate_types.push(new_part)
1917 pub mod nightly_options {
1918 use super::{ErrorOutputType, OptionStability, RustcOptGroup};
1919 use crate::early_error;
1920 use rustc_feature::UnstableFeatures;
1922 pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
1923 is_nightly_build() && matches.opt_strs("Z").iter().any(|x| *x == "unstable-options")
1926 pub fn is_nightly_build() -> bool {
1927 UnstableFeatures::from_environment().is_nightly_build()
1930 pub fn check_nightly_options(matches: &getopts::Matches, flags: &[RustcOptGroup]) {
1931 let has_z_unstable_option = matches.opt_strs("Z").iter().any(|x| *x == "unstable-options");
1932 let really_allows_unstable_options =
1933 UnstableFeatures::from_environment().is_nightly_build();
1935 for opt in flags.iter() {
1936 if opt.stability == OptionStability::Stable {
1939 if !matches.opt_present(opt.name) {
1942 if opt.name != "Z" && !has_z_unstable_option {
1944 ErrorOutputType::default(),
1946 "the `-Z unstable-options` flag must also be passed to enable \
1952 if really_allows_unstable_options {
1955 match opt.stability {
1956 OptionStability::Unstable => {
1958 "the option `{}` is only accepted on the \
1962 early_error(ErrorOutputType::default(), &msg);
1964 OptionStability::Stable => {}
1970 impl fmt::Display for CrateType {
1971 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1973 CrateType::Executable => "bin".fmt(f),
1974 CrateType::Dylib => "dylib".fmt(f),
1975 CrateType::Rlib => "rlib".fmt(f),
1976 CrateType::Staticlib => "staticlib".fmt(f),
1977 CrateType::Cdylib => "cdylib".fmt(f),
1978 CrateType::ProcMacro => "proc-macro".fmt(f),
1983 #[derive(Copy, Clone, PartialEq, Debug)]
1984 pub enum PpSourceMode {
1989 PpmExpandedIdentified,
1994 #[derive(Copy, Clone, PartialEq, Debug)]
1996 PpmSource(PpSourceMode),
1997 PpmHir(PpSourceMode),
1998 PpmHirTree(PpSourceMode),
2004 pub fn needs_ast_map(&self) -> bool {
2006 use PpSourceMode::*;
2008 PpmSource(PpmNormal | PpmIdentified) => false,
2011 PpmExpanded | PpmEveryBodyLoops | PpmExpandedIdentified | PpmExpandedHygiene,
2016 | PpmMirCFG => true,
2017 PpmSource(PpmTyped) => panic!("invalid state"),
2021 pub fn needs_analysis(&self) -> bool {
2024 PpmMir | PpmMirCFG => true,
2030 /// Command-line arguments passed to the compiler have to be incorporated with
2031 /// the dependency tracking system for incremental compilation. This module
2032 /// provides some utilities to make this more convenient.
2034 /// The values of all command-line arguments that are relevant for dependency
2035 /// tracking are hashed into a single value that determines whether the
2036 /// incremental compilation cache can be re-used or not. This hashing is done
2037 /// via the `DepTrackingHash` trait defined below, since the standard `Hash`
2038 /// implementation might not be suitable (e.g., arguments are stored in a `Vec`,
2039 /// the hash of which is order dependent, but we might not want the order of
2040 /// arguments to make a difference for the hash).
2042 /// However, since the value provided by `Hash::hash` often *is* suitable,
2043 /// especially for primitive types, there is the
2044 /// `impl_dep_tracking_hash_via_hash!()` macro that allows to simply reuse the
2045 /// `Hash` implementation for `DepTrackingHash`. It's important though that
2046 /// we have an opt-in scheme here, so one is hopefully forced to think about
2047 /// how the hash should be calculated when adding a new command-line argument.
2048 crate mod dep_tracking {
2050 CFGuard, CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel,
2051 OutputTypes, Passes, SanitizerSet, SourceFileHashAlgorithm, SwitchWithOptPath,
2052 SymbolManglingVersion,
2055 use crate::utils::NativeLibKind;
2056 use rustc_feature::UnstableFeatures;
2057 use rustc_span::edition::Edition;
2058 use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2059 use rustc_target::spec::{RelroLevel, TargetTriple, TlsModel};
2060 use std::collections::hash_map::DefaultHasher;
2061 use std::collections::BTreeMap;
2062 use std::hash::Hash;
2063 use std::path::PathBuf;
2065 pub trait DepTrackingHash {
2066 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
2069 macro_rules! impl_dep_tracking_hash_via_hash {
2071 impl DepTrackingHash for $t {
2072 fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
2073 Hash::hash(self, hasher);
2079 macro_rules! impl_dep_tracking_hash_for_sortable_vec_of {
2081 impl DepTrackingHash for Vec<$t> {
2082 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2083 let mut elems: Vec<&$t> = self.iter().collect();
2085 Hash::hash(&elems.len(), hasher);
2086 for (index, elem) in elems.iter().enumerate() {
2087 Hash::hash(&index, hasher);
2088 DepTrackingHash::hash(*elem, hasher, error_format);
2095 impl_dep_tracking_hash_via_hash!(bool);
2096 impl_dep_tracking_hash_via_hash!(usize);
2097 impl_dep_tracking_hash_via_hash!(u64);
2098 impl_dep_tracking_hash_via_hash!(String);
2099 impl_dep_tracking_hash_via_hash!(PathBuf);
2100 impl_dep_tracking_hash_via_hash!(lint::Level);
2101 impl_dep_tracking_hash_via_hash!(Option<bool>);
2102 impl_dep_tracking_hash_via_hash!(Option<usize>);
2103 impl_dep_tracking_hash_via_hash!(Option<String>);
2104 impl_dep_tracking_hash_via_hash!(Option<(String, u64)>);
2105 impl_dep_tracking_hash_via_hash!(Option<Vec<String>>);
2106 impl_dep_tracking_hash_via_hash!(Option<MergeFunctions>);
2107 impl_dep_tracking_hash_via_hash!(Option<RelocModel>);
2108 impl_dep_tracking_hash_via_hash!(Option<CodeModel>);
2109 impl_dep_tracking_hash_via_hash!(Option<TlsModel>);
2110 impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
2111 impl_dep_tracking_hash_via_hash!(Option<RelroLevel>);
2112 impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
2113 impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
2114 impl_dep_tracking_hash_via_hash!(CrateType);
2115 impl_dep_tracking_hash_via_hash!(MergeFunctions);
2116 impl_dep_tracking_hash_via_hash!(PanicStrategy);
2117 impl_dep_tracking_hash_via_hash!(RelroLevel);
2118 impl_dep_tracking_hash_via_hash!(Passes);
2119 impl_dep_tracking_hash_via_hash!(OptLevel);
2120 impl_dep_tracking_hash_via_hash!(LtoCli);
2121 impl_dep_tracking_hash_via_hash!(DebugInfo);
2122 impl_dep_tracking_hash_via_hash!(UnstableFeatures);
2123 impl_dep_tracking_hash_via_hash!(OutputTypes);
2124 impl_dep_tracking_hash_via_hash!(NativeLibKind);
2125 impl_dep_tracking_hash_via_hash!(SanitizerSet);
2126 impl_dep_tracking_hash_via_hash!(CFGuard);
2127 impl_dep_tracking_hash_via_hash!(TargetTriple);
2128 impl_dep_tracking_hash_via_hash!(Edition);
2129 impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2130 impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
2131 impl_dep_tracking_hash_via_hash!(SymbolManglingVersion);
2132 impl_dep_tracking_hash_via_hash!(Option<SourceFileHashAlgorithm>);
2134 impl_dep_tracking_hash_for_sortable_vec_of!(String);
2135 impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf);
2136 impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
2137 impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
2138 impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>, NativeLibKind));
2139 impl_dep_tracking_hash_for_sortable_vec_of!((String, u64));
2141 impl<T1, T2> DepTrackingHash for (T1, T2)
2143 T1: DepTrackingHash,
2144 T2: DepTrackingHash,
2146 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2147 Hash::hash(&0, hasher);
2148 DepTrackingHash::hash(&self.0, hasher, error_format);
2149 Hash::hash(&1, hasher);
2150 DepTrackingHash::hash(&self.1, hasher, error_format);
2154 impl<T1, T2, T3> DepTrackingHash for (T1, T2, T3)
2156 T1: DepTrackingHash,
2157 T2: DepTrackingHash,
2158 T3: DepTrackingHash,
2160 fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
2161 Hash::hash(&0, hasher);
2162 DepTrackingHash::hash(&self.0, hasher, error_format);
2163 Hash::hash(&1, hasher);
2164 DepTrackingHash::hash(&self.1, hasher, error_format);
2165 Hash::hash(&2, hasher);
2166 DepTrackingHash::hash(&self.2, hasher, error_format);
2170 // This is a stable hash because BTreeMap is a sorted container
2172 sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
2173 hasher: &mut DefaultHasher,
2174 error_format: ErrorOutputType,
2176 for (key, sub_hash) in sub_hashes {
2177 // Using Hash::hash() instead of DepTrackingHash::hash() is fine for
2178 // the keys, as they are just plain strings
2179 Hash::hash(&key.len(), hasher);
2180 Hash::hash(key, hasher);
2181 sub_hash.hash(hasher, error_format);