Skip to content

Commit d9e56f4

Browse files
authored
Rollup merge of rust-lang#79570 - alexcrichton:split-debuginfo, r=bjorn3
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 rust-lang#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 rust-lang#79361
2 parents c0b64d9 + a124043 commit d9e56f4

File tree

21 files changed

+352
-134
lines changed

21 files changed

+352
-134
lines changed

compiler/rustc_codegen_llvm/src/back/lto.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -732,10 +732,7 @@ pub unsafe fn optimize_thin_module(
732732
let diag_handler = cgcx.create_diag_handler();
733733

734734
let module_name = &thin_module.shared.module_names[thin_module.idx];
735-
let split_dwarf_file = cgcx
736-
.output_filenames
737-
.split_dwarf_filename(cgcx.split_dwarf_kind, Some(module_name.to_str().unwrap()));
738-
let tm_factory_config = TargetMachineFactoryConfig { split_dwarf_file };
735+
let tm_factory_config = TargetMachineFactoryConfig::new(cgcx, module_name.to_str().unwrap());
739736
let tm =
740737
(cgcx.tm_factory)(tm_factory_config).map_err(|e| write::llvm_err(&diag_handler, &e))?;
741738

compiler/rustc_codegen_llvm/src/back/write.rs

+18-11
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,11 @@ use rustc_fs_util::{link_or_copy, path_to_c_string};
2323
use rustc_hir::def_id::LOCAL_CRATE;
2424
use rustc_middle::bug;
2525
use rustc_middle::ty::TyCtxt;
26-
use rustc_session::config::{
27-
self, Lto, OutputType, Passes, SanitizerSet, SplitDwarfKind, SwitchWithOptPath,
28-
};
26+
use rustc_session::config::{self, Lto, OutputType, Passes, SanitizerSet, SwitchWithOptPath};
2927
use rustc_session::Session;
3028
use rustc_span::symbol::sym;
3129
use rustc_span::InnerSpan;
32-
use rustc_target::spec::{CodeModel, RelocModel};
30+
use rustc_target::spec::{CodeModel, RelocModel, SplitDebuginfo};
3331
use tracing::debug;
3432

3533
use libc::{c_char, c_int, c_uint, c_void, size_t};
@@ -93,9 +91,12 @@ pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm:
9391
}
9492

9593
pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut llvm::TargetMachine {
96-
let split_dwarf_file = tcx
97-
.output_filenames(LOCAL_CRATE)
98-
.split_dwarf_filename(tcx.sess.opts.debugging_opts.split_dwarf, Some(mod_name));
94+
let split_dwarf_file = if tcx.sess.target_can_use_split_dwarf() {
95+
tcx.output_filenames(LOCAL_CRATE)
96+
.split_dwarf_filename(tcx.sess.split_debuginfo(), Some(mod_name))
97+
} else {
98+
None
99+
};
99100
let config = TargetMachineFactoryConfig { split_dwarf_file };
100101
target_machine_factory(&tcx.sess, tcx.backend_optimization_level(LOCAL_CRATE))(config)
101102
.unwrap_or_else(|err| llvm_err(tcx.sess.diagnostic(), &err).raise())
@@ -838,11 +839,17 @@ pub(crate) unsafe fn codegen(
838839
.generic_activity_with_arg("LLVM_module_codegen_emit_obj", &module.name[..]);
839840

840841
let dwo_out = cgcx.output_filenames.temp_path_dwo(module_name);
841-
let dwo_out = match cgcx.split_dwarf_kind {
842+
let dwo_out = match cgcx.split_debuginfo {
842843
// Don't change how DWARF is emitted in single mode (or when disabled).
843-
SplitDwarfKind::None | SplitDwarfKind::Single => None,
844+
SplitDebuginfo::Off | SplitDebuginfo::Packed => None,
844845
// Emit (a subset of the) DWARF into a separate file in split mode.
845-
SplitDwarfKind::Split => Some(dwo_out.as_path()),
846+
SplitDebuginfo::Unpacked => {
847+
if cgcx.target_can_use_split_dwarf {
848+
Some(dwo_out.as_path())
849+
} else {
850+
None
851+
}
852+
}
846853
};
847854

848855
with_codegen(tm, llmod, config.no_builtins, |cpm| {
@@ -880,7 +887,7 @@ pub(crate) unsafe fn codegen(
880887

881888
Ok(module.into_compiled_module(
882889
config.emit_obj != EmitObj::None,
883-
cgcx.split_dwarf_kind == SplitDwarfKind::Split,
890+
cgcx.target_can_use_split_dwarf && cgcx.split_debuginfo == SplitDebuginfo::Unpacked,
884891
config.emit_bc,
885892
&cgcx.output_filenames,
886893
))

compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -995,10 +995,13 @@ pub fn compile_unit_metadata(
995995
let flags = "\0";
996996

997997
let out_dir = &tcx.output_filenames(LOCAL_CRATE).out_directory;
998-
let split_name = tcx
999-
.output_filenames(LOCAL_CRATE)
1000-
.split_dwarf_filename(tcx.sess.opts.debugging_opts.split_dwarf, Some(codegen_unit_name))
1001-
.unwrap_or_default();
998+
let split_name = if tcx.sess.target_can_use_split_dwarf() {
999+
tcx.output_filenames(LOCAL_CRATE)
1000+
.split_dwarf_filename(tcx.sess.split_debuginfo(), Some(codegen_unit_name))
1001+
} else {
1002+
None
1003+
}
1004+
.unwrap_or_default();
10021005
let out_dir = out_dir.to_str().unwrap();
10031006
let split_name = split_name.to_str().unwrap();
10041007

compiler/rustc_codegen_llvm/src/lib.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -351,12 +351,7 @@ impl ModuleLlvm {
351351
unsafe {
352352
let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
353353
let llmod_raw = back::lto::parse_module(llcx, name, buffer, handler)?;
354-
355-
let split_dwarf_file = cgcx
356-
.output_filenames
357-
.split_dwarf_filename(cgcx.split_dwarf_kind, Some(name.to_str().unwrap()));
358-
let tm_factory_config = TargetMachineFactoryConfig { split_dwarf_file };
359-
354+
let tm_factory_config = TargetMachineFactoryConfig::new(&cgcx, name.to_str().unwrap());
360355
let tm = match (cgcx.tm_factory)(tm_factory_config) {
361356
Ok(m) => m,
362357
Err(e) => {

compiler/rustc_codegen_ssa/src/back/link.rs

+38-46
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use rustc_session::utils::NativeLibKind;
1414
use rustc_session::{filesearch, Session};
1515
use rustc_span::symbol::Symbol;
1616
use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
17-
use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor};
17+
use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor, SplitDebuginfo};
1818
use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, Target};
1919

2020
use super::archive::ArchiveBuilder;
@@ -99,9 +99,6 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
9999
path.as_ref(),
100100
target_cpu,
101101
);
102-
if sess.opts.debugging_opts.split_dwarf == config::SplitDwarfKind::Split {
103-
link_dwarf_object(sess, &out_filename);
104-
}
105102
}
106103
}
107104
if sess.opts.json_artifact_notifications {
@@ -828,29 +825,43 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
828825
}
829826
}
830827

831-
// On macOS, debuggers need this utility to get run to do some munging of
832-
// the symbols. Note, though, that if the object files are being preserved
833-
// for their debug information there's no need for us to run dsymutil.
834-
if sess.target.is_like_osx
835-
&& sess.opts.debuginfo != DebugInfo::None
836-
&& !preserve_objects_for_their_debuginfo(sess)
837-
{
838-
let prog = Command::new("dsymutil").arg(out_filename).output();
839-
match prog {
840-
Ok(prog) => {
841-
if !prog.status.success() {
842-
let mut output = prog.stderr.clone();
843-
output.extend_from_slice(&prog.stdout);
844-
sess.struct_warn(&format!(
845-
"processing debug info with `dsymutil` failed: {}",
846-
prog.status
847-
))
848-
.note(&escape_string(&output))
849-
.emit();
828+
match sess.split_debuginfo() {
829+
// If split debug information is disabled or located in individual files
830+
// there's nothing to do here.
831+
SplitDebuginfo::Off | SplitDebuginfo::Unpacked => {}
832+
833+
// If packed split-debuginfo is requested, but the final compilation
834+
// doesn't actually have any debug information, then we skip this step.
835+
SplitDebuginfo::Packed if sess.opts.debuginfo == DebugInfo::None => {}
836+
837+
// On macOS the external `dsymutil` tool is used to create the packed
838+
// debug information. Note that this will read debug information from
839+
// the objects on the filesystem which we'll clean up later.
840+
SplitDebuginfo::Packed if sess.target.is_like_osx => {
841+
let prog = Command::new("dsymutil").arg(out_filename).output();
842+
match prog {
843+
Ok(prog) => {
844+
if !prog.status.success() {
845+
let mut output = prog.stderr.clone();
846+
output.extend_from_slice(&prog.stdout);
847+
sess.struct_warn(&format!(
848+
"processing debug info with `dsymutil` failed: {}",
849+
prog.status
850+
))
851+
.note(&escape_string(&output))
852+
.emit();
853+
}
850854
}
855+
Err(e) => sess.fatal(&format!("unable to run `dsymutil`: {}", e)),
851856
}
852-
Err(e) => sess.fatal(&format!("unable to run `dsymutil`: {}", e)),
853857
}
858+
859+
// On MSVC packed debug information is produced by the linker itself so
860+
// there's no need to do anything else here.
861+
SplitDebuginfo::Packed if sess.target.is_like_msvc => {}
862+
863+
// ... and otherwise we're processing a `*.dwp` packed dwarf file.
864+
SplitDebuginfo::Packed => link_dwarf_object(sess, &out_filename),
854865
}
855866
}
856867

@@ -1050,28 +1061,9 @@ fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool {
10501061
return false;
10511062
}
10521063

1053-
// Single mode keeps debuginfo in the same object file, but in such a way that it it skipped
1054-
// by the linker - so it's expected that when codegen units are linked together that this
1055-
// debuginfo would be lost without keeping around the temps.
1056-
if sess.opts.debugging_opts.split_dwarf == config::SplitDwarfKind::Single {
1057-
return true;
1058-
}
1059-
1060-
// If we're on OSX then the equivalent of split dwarf is turned on by
1061-
// default. The final executable won't actually have any debug information
1062-
// except it'll have pointers to elsewhere. Historically we've always run
1063-
// `dsymutil` to "link all the dwarf together" but this is actually sort of
1064-
// a bummer for incremental compilation! (the whole point of split dwarf is
1065-
// that you don't do this sort of dwarf link).
1066-
//
1067-
// Basically as a result this just means that if we're on OSX and we're
1068-
// *not* running dsymutil then the object files are the only source of truth
1069-
// for debug information, so we must preserve them.
1070-
if sess.target.is_like_osx {
1071-
return !sess.opts.debugging_opts.run_dsymutil;
1072-
}
1073-
1074-
false
1064+
// "unpacked" split debuginfo means that we leave object files as the
1065+
// debuginfo is found in the original object files themselves
1066+
sess.split_debuginfo() == SplitDebuginfo::Unpacked
10751067
}
10761068

10771069
pub fn archive_search_paths(sess: &Session) -> Vec<PathBuf> {

compiler/rustc_codegen_ssa/src/back/write.rs

+18-2
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,20 @@ pub struct TargetMachineFactoryConfig {
282282
pub split_dwarf_file: Option<PathBuf>,
283283
}
284284

285+
impl TargetMachineFactoryConfig {
286+
pub fn new(
287+
cgcx: &CodegenContext<impl WriteBackendMethods>,
288+
module_name: &str,
289+
) -> TargetMachineFactoryConfig {
290+
let split_dwarf_file = if cgcx.target_can_use_split_dwarf {
291+
cgcx.output_filenames.split_dwarf_filename(cgcx.split_debuginfo, Some(module_name))
292+
} else {
293+
None
294+
};
295+
TargetMachineFactoryConfig { split_dwarf_file }
296+
}
297+
}
298+
285299
pub type TargetMachineFactoryFn<B> = Arc<
286300
dyn Fn(TargetMachineFactoryConfig) -> Result<<B as WriteBackendMethods>::TargetMachine, String>
287301
+ Send
@@ -311,10 +325,11 @@ pub struct CodegenContext<B: WriteBackendMethods> {
311325
pub tm_factory: TargetMachineFactoryFn<B>,
312326
pub msvc_imps_needed: bool,
313327
pub is_pe_coff: bool,
328+
pub target_can_use_split_dwarf: bool,
314329
pub target_pointer_width: u32,
315330
pub target_arch: String,
316331
pub debuginfo: config::DebugInfo,
317-
pub split_dwarf_kind: config::SplitDwarfKind,
332+
pub split_debuginfo: rustc_target::spec::SplitDebuginfo,
318333

319334
// Number of cgus excluding the allocator/metadata modules
320335
pub total_cgus: usize,
@@ -1035,10 +1050,11 @@ fn start_executing_work<B: ExtraBackendMethods>(
10351050
total_cgus,
10361051
msvc_imps_needed: msvc_imps_needed(tcx),
10371052
is_pe_coff: tcx.sess.target.is_like_windows,
1053+
target_can_use_split_dwarf: tcx.sess.target_can_use_split_dwarf(),
10381054
target_pointer_width: tcx.sess.target.pointer_width,
10391055
target_arch: tcx.sess.target.arch.clone(),
10401056
debuginfo: tcx.sess.opts.debuginfo,
1041-
split_dwarf_kind: tcx.sess.opts.debugging_opts.split_dwarf,
1057+
split_debuginfo: tcx.sess.split_debuginfo(),
10421058
};
10431059

10441060
// This is the "main loop" of parallel work happening for parallel codegen.

compiler/rustc_interface/src/tests.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_span::edition::{Edition, DEFAULT_EDITION};
1717
use rustc_span::symbol::sym;
1818
use rustc_span::SourceFileHashAlgorithm;
1919
use rustc_target::spec::{CodeModel, LinkerFlavor, MergeFunctions, PanicStrategy};
20-
use rustc_target::spec::{RelocModel, RelroLevel, TlsModel};
20+
use rustc_target::spec::{RelocModel, RelroLevel, SplitDebuginfo, TlsModel};
2121
use std::collections::{BTreeMap, BTreeSet};
2222
use std::iter::FromIterator;
2323
use std::path::PathBuf;
@@ -446,6 +446,7 @@ fn test_codegen_options_tracking_hash() {
446446
tracked!(profile_use, Some(PathBuf::from("abc")));
447447
tracked!(relocation_model, Some(RelocModel::Pic));
448448
tracked!(soft_float, true);
449+
tracked!(split_debuginfo, Some(SplitDebuginfo::Packed));
449450
tracked!(target_cpu, Some(String::from("abc")));
450451
tracked!(target_feature, String::from("all the features, all of them"));
451452
}
@@ -579,7 +580,6 @@ fn test_debugging_options_tracking_hash() {
579580
tracked!(relax_elf_relocations, Some(true));
580581
tracked!(relro_level, Some(RelroLevel::Full));
581582
tracked!(report_delayed_bugs, true);
582-
tracked!(run_dsymutil, false);
583583
tracked!(sanitizer, SanitizerSet::ADDRESS);
584584
tracked!(sanitizer_memory_track_origins, 2);
585585
tracked!(sanitizer_recover, SanitizerSet::ADDRESS);

compiler/rustc_session/src/config.rs

+19-26
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use rustc_data_structures::impl_stable_hash_via_hash;
1313
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
1414

1515
use rustc_target::abi::{Align, TargetDataLayout};
16-
use rustc_target::spec::{Target, TargetTriple};
16+
use rustc_target::spec::{SplitDebuginfo, Target, TargetTriple};
1717

1818
use crate::parse::CrateConfig;
1919
use rustc_feature::UnstableFeatures;
@@ -221,23 +221,6 @@ pub enum DebugInfo {
221221
Full,
222222
}
223223

224-
/// Some debuginfo requires link-time relocation and some does not. LLVM can partition the debuginfo
225-
/// into sections depending on whether or not it requires link-time relocation. Split DWARF
226-
/// provides a mechanism which allows the linker to skip the sections which don't require link-time
227-
/// relocation - either by putting those sections into DWARF object files, or keeping them in the
228-
/// object file in such a way that the linker will skip them.
229-
#[derive(Clone, Copy, Debug, PartialEq, Hash)]
230-
pub enum SplitDwarfKind {
231-
/// Disabled.
232-
None,
233-
/// Sections which do not require relocation are written into the object file but ignored
234-
/// by the linker.
235-
Single,
236-
/// Sections which do not require relocation are written into a DWARF object (`.dwo`) file,
237-
/// which is skipped by the linker by virtue of being a different file.
238-
Split,
239-
}
240-
241224
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord)]
242225
#[derive(Encodable, Decodable)]
243226
pub enum OutputType {
@@ -635,30 +618,30 @@ impl OutputFilenames {
635618
/// mode is being used, which is the logic that this function is intended to encapsulate.
636619
pub fn split_dwarf_filename(
637620
&self,
638-
split_dwarf_kind: SplitDwarfKind,
621+
split_debuginfo_kind: SplitDebuginfo,
639622
cgu_name: Option<&str>,
640623
) -> Option<PathBuf> {
641-
self.split_dwarf_path(split_dwarf_kind, cgu_name)
624+
self.split_dwarf_path(split_debuginfo_kind, cgu_name)
642625
.map(|path| path.strip_prefix(&self.out_directory).unwrap_or(&path).to_path_buf())
643626
}
644627

645628
/// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
646629
/// mode is being used, which is the logic that this function is intended to encapsulate.
647630
pub fn split_dwarf_path(
648631
&self,
649-
split_dwarf_kind: SplitDwarfKind,
632+
split_debuginfo_kind: SplitDebuginfo,
650633
cgu_name: Option<&str>,
651634
) -> Option<PathBuf> {
652635
let obj_out = self.temp_path(OutputType::Object, cgu_name);
653636
let dwo_out = self.temp_path_dwo(cgu_name);
654-
match split_dwarf_kind {
655-
SplitDwarfKind::None => None,
637+
match split_debuginfo_kind {
638+
SplitDebuginfo::Off => None,
656639
// Single mode doesn't change how DWARF is emitted, but does add Split DWARF attributes
657640
// (pointing at the path which is being determined here). Use the path to the current
658641
// object file.
659-
SplitDwarfKind::Single => Some(obj_out),
642+
SplitDebuginfo::Packed => Some(obj_out),
660643
// Split mode emits the DWARF into a different file, use that path.
661-
SplitDwarfKind::Split => Some(dwo_out),
644+
SplitDebuginfo::Unpacked => Some(dwo_out),
662645
}
663646
}
664647
}
@@ -1910,6 +1893,15 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
19101893

19111894
let pretty = parse_pretty(matches, &debugging_opts, error_format);
19121895

1896+
if !debugging_opts.unstable_options
1897+
&& !target_triple.triple().contains("apple")
1898+
&& cg.split_debuginfo.is_some()
1899+
{
1900+
{
1901+
early_error(error_format, "`-Csplit-debuginfo` is unstable on this platform");
1902+
}
1903+
}
1904+
19131905
Options {
19141906
crate_types,
19151907
optimize: opt_level,
@@ -2191,7 +2183,7 @@ crate mod dep_tracking {
21912183
use rustc_feature::UnstableFeatures;
21922184
use rustc_span::edition::Edition;
21932185
use rustc_target::spec::{CodeModel, MergeFunctions, PanicStrategy, RelocModel};
2194-
use rustc_target::spec::{RelroLevel, TargetTriple, TlsModel};
2186+
use rustc_target::spec::{RelroLevel, SplitDebuginfo, TargetTriple, TlsModel};
21952187
use std::collections::hash_map::DefaultHasher;
21962188
use std::collections::BTreeMap;
21972189
use std::hash::Hash;
@@ -2263,6 +2255,7 @@ crate mod dep_tracking {
22632255
impl_dep_tracking_hash_via_hash!(TargetTriple);
22642256
impl_dep_tracking_hash_via_hash!(Edition);
22652257
impl_dep_tracking_hash_via_hash!(LinkerPluginLto);
2258+
impl_dep_tracking_hash_via_hash!(Option<SplitDebuginfo>);
22662259
impl_dep_tracking_hash_via_hash!(SwitchWithOptPath);
22672260
impl_dep_tracking_hash_via_hash!(Option<SymbolManglingVersion>);
22682261
impl_dep_tracking_hash_via_hash!(Option<SourceFileHashAlgorithm>);

0 commit comments

Comments
 (0)