rustc: Stabilize -Zrun-dsymutil as -Csplit-debuginfo

This commit adds a new stable codegen option to rustc,
`-Csplit-debuginfo`. The old `-Zrun-dsymutil` flag is deleted and now
subsumed by this stable flag. Additionally `-Zsplit-dwarf` is also
subsumed by this flag but still requires `-Zunstable-options` to
actually activate. The `-Csplit-debuginfo` flag takes one of
three values:

* `off` - This indicates that split-debuginfo from the final artifact is
  not desired. This is not supported on Windows and is the default on
  Unix platforms except macOS. On macOS this means that `dsymutil` is
  not executed.

* `packed` - This means that debuginfo is desired in one location
  separate from the main executable. This is the default on Windows
  (`*.pdb`) and macOS (`*.dSYM`). On other Unix platforms this subsumes
  `-Zsplit-dwarf=single` and produces a `*.dwp` file.

* `unpacked` - This means that debuginfo will be roughly equivalent to
  object files, meaning that it's throughout the build directory
  rather than in one location (often the fastest for local development).
  This is not the default on any platform and is not supported on Windows.

Each target can indicate its own default preference for how debuginfo is
handled. Almost all platforms default to `off` except for Windows and
macOS which default to `packed` for historical reasons.

Some equivalencies for previous unstable flags with the new flags are:

* `-Zrun-dsymutil=yes` -> `-Csplit-debuginfo=packed`
* `-Zrun-dsymutil=no` -> `-Csplit-debuginfo=unpacked`
* `-Zsplit-dwarf=single` -> `-Csplit-debuginfo=packed`
* `-Zsplit-dwarf=split` -> `-Csplit-debuginfo=unpacked`

Note that `-Csplit-debuginfo` still requires `-Zunstable-options` for
non-macOS platforms since split-dwarf support was *just* implemented in
rustc.

There's some more rationale listed on #79361, but the main gist of the
motivation for this commit is that `dsymutil` can take quite a long time
to execute in debug builds and provides little benefit. This means that
incremental compile times appear that much worse on macOS because the
compiler is constantly running `dsymutil` over every single binary it
produces during `cargo build` (even build scripts!). Ideally rustc would
switch to not running `dsymutil` by default, but that's a problem left
to get tackled another day.

Closes #79361
This commit is contained in:
Alex Crichton 2020-11-30 08:39:08 -08:00
parent 7fba12bb1d
commit a124043fb0
21 changed files with 352 additions and 134 deletions

View file

@ -13,7 +13,7 @@ use rustc_data_structures::impl_stable_hash_via_hash;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_target::abi::{Align, TargetDataLayout};
use rustc_target::spec::{Target, TargetTriple};
use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple};
use crate::parse::CrateConfig;
use rustc_feature::UnstableFeatures;
@ -221,23 +221,6 @@ pub enum DebugInfo {
Full,
}
/// Some debuginfo requires link-time relocation and some does not. LLVM can partition the debuginfo
/// into sections depending on whether or not it requires link-time relocation. Split DWARF
/// provides a mechanism which allows the linker to skip the sections which don't require link-time
/// relocation - either by putting those sections into DWARF object files, or keeping them in the
/// object file in such a way that the linker will skip them.
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
pub enum SplitDwarfKind {
/// Disabled.
None,
/// Sections which do not require relocation are written into the object file but ignored
/// by the linker.
Single,
/// Sections which do not require relocation are written into a DWARF object (`.dwo`) file,
/// which is skipped by the linker by virtue of being a different file.
Split,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
#[derive(Encodable, Decodable)]
pub enum OutputType {
@ -635,10 +618,10 @@ impl OutputFilenames {
/// mode is being used, which is the logic that this function is intended to encapsulate.
pub fn split_dwarf_filename(
&self,
split_dwarf_kind: SplitDwarfKind,
split_debuginfo_kind: SplitDebuginfo,
cgu_name: Option<&str>,
) -> Option<PathBuf> {
self.split_dwarf_path(split_dwarf_kind, cgu_name)
self.split_dwarf_path(split_debuginfo_kind, cgu_name)
.map(|path| path.strip_prefix(&self.out_directory).unwrap_or(&path).to_path_buf())
}
@ -646,19 +629,19 @@ impl OutputFilenames {
/// mode is being used, which is the logic that this function is intended to encapsulate.
pub fn split_dwarf_path(
&self,
split_dwarf_kind: SplitDwarfKind,
split_debuginfo_kind: SplitDebuginfo,
cgu_name: Option<&str>,
) -> Option<PathBuf> {
let obj_out = self.temp_path(OutputType::Object, cgu_name);
let dwo_out = self.temp_path_dwo(cgu_name);
match split_dwarf_kind {
SplitDwarfKind::None => None,
match split_debuginfo_kind {
SplitDebuginfo::Off => None,
// Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
// (pointing at the path which is being determined here). Use the path to the current
// object file.
SplitDwarfKind::Single => Some(obj_out),
SplitDebuginfo::Packed => Some(obj_out),
// Split mode emits the DWARF into a different file, use that path.
SplitDwarfKind::Split => Some(dwo_out),
SplitDebuginfo::Unpacked => Some(dwo_out),
}
}
}
@ -1910,6 +1893,15 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
let pretty = parse_pretty(matches, &debugging_opts, error_format);
if !debugging_opts.unstable_options
&& !target_triple.triple().contains("apple")
&& cg.split_debuginfo.is_some()
{
{
early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
}
}
Options {
crate_types,
optimize: opt_level,
@ -2191,7 +2183,7 @@ crate mod dep_tracking {
use rustc_feature::UnstableFeatures;
use rustc_span::edition::Edition;
use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
use rustc_target::spec::{RelroLevel, TargetTriple, TlsModel};
use rustc_target::spec::{RelroLevel, SplitDebuginfo, TargetTriple, TlsModel};
use std::collections::hash_map::DefaultHasher;
use std::collections::BTreeMap;
use std::hash::Hash;
@ -2263,6 +2255,7 @@ crate mod dep_tracking {
impl_dep_tracking_hash_via_hash!(TargetTriple);
impl_dep_tracking_hash_via_hash!(Edition);
impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
impl_dep_tracking_hash_via_hash!(Option<SplitDebuginfo>);
impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
impl_dep_tracking_hash_via_hash!(Option<SymbolManglingVersion>);
impl_dep_tracking_hash_via_hash!(Option<SourceFileHashAlgorithm>);

View file

@ -6,7 +6,7 @@ use crate::search_paths::SearchPath;
use crate::utils::NativeLibKind;
use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy};
use rustc_target::spec::{RelocModel, RelroLevel, TargetTriple, TlsModel};
use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TargetTriple, TlsModel};
use rustc_feature::UnstableFeatures;
use rustc_span::edition::Edition;
@ -269,7 +269,6 @@ macro_rules! options {
pub const parse_switch_with_opt_path: &str =
"an optional path to the profiling data output directory";
pub const parse_merge_functions: &str = "one of: `disabled`, `trampolines`, or `aliases`";
pub const parse_split_dwarf_kind: &str = "one of: `none`, `single` or `split`";
pub const parse_symbol_mangling_version: &str = "either `legacy` or `v0` (RFC 2603)";
pub const parse_src_file_hash: &str = "either `md5` or `sha1`";
pub const parse_relocation_model: &str =
@ -280,6 +279,8 @@ macro_rules! options {
"one of supported TLS models (`rustc --print tls-models`)";
pub const parse_target_feature: &str = parse_string;
pub const parse_wasi_exec_model: &str = "either `command` or `reactor`";
pub const parse_split_debuginfo: &str =
"one of supported split-debuginfo modes (`off` or `dsymutil`)";
}
#[allow(dead_code)]
@ -678,19 +679,6 @@ macro_rules! options {
true
}
fn parse_split_dwarf_kind(
slot: &mut SplitDwarfKind,
v: Option<&str>,
) -> bool {
*slot = match v {
Some("none") => SplitDwarfKind::None,
Some("split") => SplitDwarfKind::Split,
Some("single") => SplitDwarfKind::Single,
_ => return false,
};
true
}
fn parse_symbol_mangling_version(
slot: &mut Option<SymbolManglingVersion>,
v: Option<&str>,
@ -732,6 +720,14 @@ macro_rules! options {
}
true
}
fn parse_split_debuginfo(slot: &mut Option<SplitDebuginfo>, v: Option<&str>) -> bool {
match v.and_then(|s| SplitDebuginfo::from_str(s).ok()) {
Some(e) => *slot = Some(e),
_ => return false,
}
true
}
}
) }
@ -830,6 +826,8 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
"save all temporary output files during compilation (default: no)"),
soft_float: bool = (false, parse_bool, [TRACKED],
"use soft float ABI (*eabihf targets only) (default: no)"),
split_debuginfo: Option<SplitDebuginfo> = (None, parse_split_debuginfo, [TRACKED],
"how to handle split-debuginfo, a platform-specific option"),
target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
"select target processor (`rustc --print target-cpus` for details)"),
target_feature: String = (String::new(), parse_target_feature, [TRACKED],
@ -1073,11 +1071,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"choose which RELRO level to use"),
report_delayed_bugs: bool = (false, parse_bool, [TRACKED],
"immediately print bugs registered with `delay_span_bug` (default: no)"),
// The default historical behavior was to always run dsymutil, so we're
// preserving that temporarily, but we're likely to switch the default
// soon.
run_dsymutil: bool = (true, parse_bool, [TRACKED],
"if on Mac, run `dsymutil` and delete intermediate object files (default: yes)"),
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
"use a sanitizer"),
sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
@ -1112,8 +1105,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
"hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"),
strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
"tell the linker which information to strip (`none` (default), `debuginfo` or `symbols`)"),
split_dwarf: SplitDwarfKind = (SplitDwarfKind::None, parse_split_dwarf_kind, [UNTRACKED],
"enable generation of split dwarf"),
split_dwarf_inlining: bool = (true, parse_bool, [UNTRACKED],
"provide minimal debug info in the object/executable to facilitate online \
symbolication/stack traces in the absence of .dwo/.dwp files when using Split DWARF"),

View file

@ -28,7 +28,7 @@ use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, S
use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
use rustc_target::asm::InlineAsmArch;
use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
use rustc_target::spec::{Target, TargetTriple, TlsModel};
use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple, TlsModel};
use std::cell::{self, RefCell};
use std::env;
@ -804,6 +804,14 @@ impl Session {
)
}
pub fn split_debuginfo(&self) -> SplitDebuginfo {
self.opts.cg.split_debuginfo.unwrap_or(self.target.split_debuginfo)
}
pub fn target_can_use_split_dwarf(&self) -> bool {
!self.target.is_like_windows && !self.target.is_like_osx
}
pub fn must_not_eliminate_frame_pointers(&self) -> bool {
// "mcount" function relies on stack pointer.
// See <https://sourceware.org/binutils/docs/gprof/Implementation.html>.