1
Fork 0

cg_llvm: implement split dwarf support

This commit implements Split DWARF support, wiring up the flag (added in
earlier commits) to the modified FFI wrapper (also from earlier
commits).

Signed-off-by: David Wood <david@davidtw.co>
This commit is contained in:
David Wood 2020-09-23 17:33:54 +01:00
parent 241160de72
commit e3fdae9d81
No known key found for this signature in database
GPG key ID: 2592E76C87381FD9
8 changed files with 228 additions and 46 deletions

View file

@ -6,7 +6,9 @@ use crate::llvm::{self, build_string, False, True};
use crate::{LlvmCodegenBackend, ModuleLlvm}; use crate::{LlvmCodegenBackend, ModuleLlvm};
use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared}; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared};
use rustc_codegen_ssa::back::symbol_export; use rustc_codegen_ssa::back::symbol_export;
use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig}; use rustc_codegen_ssa::back::write::{
CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryConfig,
};
use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind}; use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
@ -728,7 +730,14 @@ pub unsafe fn optimize_thin_module(
cgcx: &CodegenContext<LlvmCodegenBackend>, cgcx: &CodegenContext<LlvmCodegenBackend>,
) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> { ) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> {
let diag_handler = cgcx.create_diag_handler(); let diag_handler = cgcx.create_diag_handler();
let tm = (cgcx.tm_factory)().map_err(|e| write::llvm_err(&diag_handler, &e))?;
let module_name = &thin_module.shared.module_names[thin_module.idx];
let split_dwarf_file = cgcx
.output_filenames
.split_dwarf_file(cgcx.split_dwarf_kind, Some(module_name.to_str().unwrap()));
let tm_factory_config = TargetMachineFactoryConfig { split_dwarf_file };
let tm =
(cgcx.tm_factory)(tm_factory_config).map_err(|e| write::llvm_err(&diag_handler, &e))?;
// Right now the implementation we've got only works over serialized // Right now the implementation we've got only works over serialized
// modules, so we create a fresh new LLVM context and parse the module // modules, so we create a fresh new LLVM context and parse the module
@ -736,12 +745,8 @@ pub unsafe fn optimize_thin_module(
// crates but for locally codegened modules we may be able to reuse // crates but for locally codegened modules we may be able to reuse
// that LLVM Context and Module. // that LLVM Context and Module.
let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
let llmod_raw = parse_module( let llmod_raw =
llcx, parse_module(llcx, &module_name, thin_module.data(), &diag_handler)? as *const _;
&thin_module.shared.module_names[thin_module.idx],
thin_module.data(),
&diag_handler,
)? as *const _;
let module = ModuleCodegen { let module = ModuleCodegen {
module_llvm: ModuleLlvm { llmod_raw, llcx, tm }, module_llvm: ModuleLlvm { llmod_raw, llcx, tm },
name: thin_module.name().to_string(), name: thin_module.name().to_string(),

View file

@ -12,7 +12,8 @@ use crate::type_::Type;
use crate::LlvmCodegenBackend; use crate::LlvmCodegenBackend;
use crate::ModuleLlvm; use crate::ModuleLlvm;
use rustc_codegen_ssa::back::write::{ use rustc_codegen_ssa::back::write::{
BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryFn, BitcodeSection, CodegenContext, EmitObj, ModuleConfig, TargetMachineFactoryConfig,
TargetMachineFactoryFn,
}; };
use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
@ -22,7 +23,9 @@ use rustc_fs_util::{link_or_copy, path_to_c_string};
use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::bug; use rustc_middle::bug;
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
use rustc_session::config::{self, Lto, OutputType, Passes, SanitizerSet, SwitchWithOptPath}; use rustc_session::config::{
self, Lto, OutputType, Passes, SanitizerSet, SplitDwarfKind, SwitchWithOptPath,
};
use rustc_session::Session; use rustc_session::Session;
use rustc_span::symbol::sym; use rustc_span::symbol::sym;
use rustc_span::InnerSpan; use rustc_span::InnerSpan;
@ -51,18 +54,31 @@ pub fn write_output_file(
pm: &llvm::PassManager<'ll>, pm: &llvm::PassManager<'ll>,
m: &'ll llvm::Module, m: &'ll llvm::Module,
output: &Path, output: &Path,
dwo_output: Option<&Path>,
file_type: llvm::FileType, file_type: llvm::FileType,
) -> Result<(), FatalError> { ) -> Result<(), FatalError> {
unsafe { unsafe {
let output_c = path_to_c_string(output); let output_c = path_to_c_string(output);
let result = llvm::LLVMRustWriteOutputFile( let result = if let Some(dwo_output) = dwo_output {
target, let dwo_output_c = path_to_c_string(dwo_output);
pm, llvm::LLVMRustWriteOutputFile(
m, target,
output_c.as_ptr(), pm,
std::ptr::null(), m,
file_type, output_c.as_ptr(),
); dwo_output_c.as_ptr(),
file_type,
)
} else {
llvm::LLVMRustWriteOutputFile(
target,
pm,
m,
output_c.as_ptr(),
std::ptr::null(),
file_type,
)
};
result.into_result().map_err(|()| { result.into_result().map_err(|()| {
let msg = format!("could not write output to {}", output.display()); let msg = format!("could not write output to {}", output.display());
llvm_err(handler, &msg) llvm_err(handler, &msg)
@ -71,12 +87,17 @@ pub fn write_output_file(
} }
pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm::TargetMachine { pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm::TargetMachine {
target_machine_factory(sess, config::OptLevel::No)() let config = TargetMachineFactoryConfig { split_dwarf_file: None };
target_machine_factory(sess, config::OptLevel::No)(config)
.unwrap_or_else(|err| llvm_err(sess.diagnostic(), &err).raise()) .unwrap_or_else(|err| llvm_err(sess.diagnostic(), &err).raise())
} }
pub fn create_target_machine(tcx: TyCtxt<'_>) -> &'static mut llvm::TargetMachine { pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> &'static mut llvm::TargetMachine {
target_machine_factory(&tcx.sess, tcx.backend_optimization_level(LOCAL_CRATE))() let split_dwarf_file = tcx
.output_filenames(LOCAL_CRATE)
.split_dwarf_file(tcx.sess.opts.debugging_opts.split_dwarf, Some(mod_name));
let config = TargetMachineFactoryConfig { split_dwarf_file };
target_machine_factory(&tcx.sess, tcx.backend_optimization_level(LOCAL_CRATE))(config)
.unwrap_or_else(|err| llvm_err(tcx.sess.diagnostic(), &err).raise()) .unwrap_or_else(|err| llvm_err(tcx.sess.diagnostic(), &err).raise())
} }
@ -172,8 +193,10 @@ pub fn target_machine_factory(
let use_init_array = let use_init_array =
!sess.opts.debugging_opts.use_ctors_section.unwrap_or(sess.target.use_ctors_section); !sess.opts.debugging_opts.use_ctors_section.unwrap_or(sess.target.use_ctors_section);
Arc::new(move || { Arc::new(move |config: TargetMachineFactoryConfig| {
let split_dwarf_file = std::ptr::null(); let split_dwarf_file = config.split_dwarf_file.unwrap_or_default();
let split_dwarf_file = CString::new(split_dwarf_file.to_str().unwrap()).unwrap();
let tm = unsafe { let tm = unsafe {
llvm::LLVMRustCreateTargetMachine( llvm::LLVMRustCreateTargetMachine(
triple.as_ptr(), triple.as_ptr(),
@ -192,7 +215,7 @@ pub fn target_machine_factory(
emit_stack_size_section, emit_stack_size_section,
relax_elf_relocations, relax_elf_relocations,
use_init_array, use_init_array,
split_dwarf_file, split_dwarf_file.as_ptr(),
) )
}; };
@ -796,7 +819,15 @@ pub(crate) unsafe fn codegen(
llmod llmod
}; };
with_codegen(tm, llmod, config.no_builtins, |cpm| { with_codegen(tm, llmod, config.no_builtins, |cpm| {
write_output_file(diag_handler, tm, cpm, llmod, &path, llvm::FileType::AssemblyFile) write_output_file(
diag_handler,
tm,
cpm,
llmod,
&path,
None,
llvm::FileType::AssemblyFile,
)
})?; })?;
} }
@ -805,6 +836,15 @@ pub(crate) unsafe fn codegen(
let _timer = cgcx let _timer = cgcx
.prof .prof
.generic_activity_with_arg("LLVM_module_codegen_emit_obj", &module.name[..]); .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &module.name[..]);
let dwo_out = cgcx.output_filenames.temp_path_dwo(module_name);
let dwo_out = match cgcx.split_dwarf_kind {
// Don't change how DWARF is emitted in single mode (or when disabled).
SplitDwarfKind::None | SplitDwarfKind::Single => None,
// Emit (a subset of the) DWARF into a separate file in split mode.
SplitDwarfKind::Split => Some(dwo_out.as_path()),
};
with_codegen(tm, llmod, config.no_builtins, |cpm| { with_codegen(tm, llmod, config.no_builtins, |cpm| {
write_output_file( write_output_file(
diag_handler, diag_handler,
@ -812,6 +852,7 @@ pub(crate) unsafe fn codegen(
cpm, cpm,
llmod, llmod,
&obj_out, &obj_out,
dwo_out,
llvm::FileType::ObjectFile, llvm::FileType::ObjectFile,
) )
})?; })?;
@ -839,6 +880,7 @@ pub(crate) unsafe fn codegen(
Ok(module.into_compiled_module( Ok(module.into_compiled_module(
config.emit_obj != EmitObj::None, config.emit_obj != EmitObj::None,
cgcx.split_dwarf_kind == SplitDwarfKind::Split,
config.emit_bc, config.emit_bc,
&cgcx.output_filenames, &cgcx.output_filenames,
)) ))

View file

@ -995,7 +995,11 @@ pub fn compile_unit_metadata(
let name_in_debuginfo = name_in_debuginfo.to_string_lossy(); let name_in_debuginfo = name_in_debuginfo.to_string_lossy();
let work_dir = tcx.sess.working_dir.0.to_string_lossy(); let work_dir = tcx.sess.working_dir.0.to_string_lossy();
let flags = "\0"; let flags = "\0";
let split_name = ""; let split_name = tcx
.output_filenames(LOCAL_CRATE)
.split_dwarf_file(tcx.sess.opts.debugging_opts.split_dwarf, Some(codegen_unit_name))
.unwrap_or_default();
let split_name = split_name.to_str().unwrap();
// FIXME(#60020): // FIXME(#60020):
// //
@ -1040,7 +1044,7 @@ pub fn compile_unit_metadata(
split_name.len(), split_name.len(),
kind, kind,
0, 0,
true, tcx.sess.opts.debugging_opts.split_dwarf_inlining,
); );
if tcx.sess.opts.debugging_opts.profile { if tcx.sess.opts.debugging_opts.profile {

View file

@ -20,7 +20,7 @@ pub use llvm_util::target_features;
use rustc_ast::expand::allocator::AllocatorKind; use rustc_ast::expand::allocator::AllocatorKind;
use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule}; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
use rustc_codegen_ssa::back::write::{ use rustc_codegen_ssa::back::write::{
CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryFn, CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryConfig, TargetMachineFactoryFn,
}; };
use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_ssa::ModuleCodegen;
@ -332,7 +332,7 @@ impl ModuleLlvm {
unsafe { unsafe {
let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names()); let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names());
let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _; let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _;
ModuleLlvm { llmod_raw, llcx, tm: create_target_machine(tcx) } ModuleLlvm { llmod_raw, llcx, tm: create_target_machine(tcx, mod_name) }
} }
} }
@ -353,7 +353,13 @@ impl ModuleLlvm {
unsafe { unsafe {
let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
let llmod_raw = back::lto::parse_module(llcx, name, buffer, handler)?; let llmod_raw = back::lto::parse_module(llcx, name, buffer, handler)?;
let tm = match (cgcx.tm_factory)() {
let split_dwarf_file = cgcx
.output_filenames
.split_dwarf_file(cgcx.split_dwarf_kind, Some(name.to_str().unwrap()));
let tm_factory_config = TargetMachineFactoryConfig { split_dwarf_file };
let tm = match (cgcx.tm_factory)(tm_factory_config) {
Ok(m) => m, Ok(m) => m,
Err(e) => { Err(e) => {
handler.struct_err(&e).emit(); handler.struct_err(&e).emit();

View file

@ -21,7 +21,9 @@ use super::archive::ArchiveBuilder;
use super::command::Command; use super::command::Command;
use super::linker::{self, Linker}; use super::linker::{self, Linker};
use super::rpath::{self, RPathConfig}; use super::rpath::{self, RPathConfig};
use crate::{looks_like_rust_object_file, CodegenResults, CrateInfo, METADATA_FILENAME}; use crate::{
looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, METADATA_FILENAME,
};
use cc::windows_registry; use cc::windows_registry;
use tempfile::Builder as TempFileBuilder; use tempfile::Builder as TempFileBuilder;
@ -96,6 +98,9 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
path.as_ref(), path.as_ref(),
target_cpu, target_cpu,
); );
if sess.opts.debugging_opts.split_dwarf == config::SplitDwarfKind::Split {
link_dwarf_object(sess, &out_filename);
}
} }
} }
if sess.opts.json_artifact_notifications { if sess.opts.json_artifact_notifications {
@ -107,22 +112,30 @@ pub fn link_binary<'a, B: ArchiveBuilder<'a>>(
// Remove the temporary object file and metadata if we aren't saving temps // Remove the temporary object file and metadata if we aren't saving temps
sess.time("link_binary_remove_temps", || { sess.time("link_binary_remove_temps", || {
if !sess.opts.cg.save_temps { if !sess.opts.cg.save_temps {
let remove_temps_from_module = |module: &CompiledModule| {
if let Some(ref obj) = module.object {
remove(sess, obj);
}
if let Some(ref obj) = module.dwarf_object {
remove(sess, obj);
}
};
if sess.opts.output_types.should_codegen() if sess.opts.output_types.should_codegen()
&& !preserve_objects_for_their_debuginfo(sess) && !preserve_objects_for_their_debuginfo(sess)
{ {
for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { for module in &codegen_results.modules {
remove(sess, obj); remove_temps_from_module(module);
} }
} }
if let Some(ref metadata_module) = codegen_results.metadata_module { if let Some(ref metadata_module) = codegen_results.metadata_module {
if let Some(ref obj) = metadata_module.object { remove_temps_from_module(metadata_module);
remove(sess, obj);
}
} }
if let Some(ref allocator_module) = codegen_results.allocator_module { if let Some(ref allocator_module) = codegen_results.allocator_module {
if let Some(ref obj) = allocator_module.object { remove_temps_from_module(allocator_module);
remove(sess, obj);
}
} }
} }
}); });
@ -446,6 +459,69 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>(
} }
} }
fn escape_stdout_stderr_string(s: &[u8]) -> String {
str::from_utf8(s).map(|s| s.to_owned()).unwrap_or_else(|_| {
let mut x = "Non-UTF-8 output: ".to_string();
x.extend(s.iter().flat_map(|&b| ascii::escape_default(b)).map(char::from));
x
})
}
const LLVM_DWP_EXECUTABLE: &'static str = "rust-llvm-dwp";
/// Invoke `llvm-dwp` (shipped alongside rustc) to link `dwo` files from Split DWARF into a `dwp`
/// file.
fn link_dwarf_object<'a>(sess: &'a Session, executable_out_filename: &Path) {
info!("preparing dwp to {}.dwp", executable_out_filename.to_str().unwrap());
let dwp_out_filename = executable_out_filename.with_extension("dwp");
let mut cmd = Command::new(LLVM_DWP_EXECUTABLE);
cmd.arg("-e");
cmd.arg(executable_out_filename);
cmd.arg("-o");
cmd.arg(&dwp_out_filename);
let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths(false);
if let Some(path) = env::var_os("PATH") {
new_path.extend(env::split_paths(&path));
}
let new_path = env::join_paths(new_path).unwrap();
cmd.env("PATH", new_path);
info!("{:?}", &cmd);
match sess.time("run_dwp", || cmd.output()) {
Ok(prog) if !prog.status.success() => {
sess.struct_err(&format!(
"linking dwarf objects with `{}` failed: {}",
LLVM_DWP_EXECUTABLE, prog.status
))
.note(&format!("{:?}", &cmd))
.note(&escape_stdout_stderr_string(&prog.stdout))
.note(&escape_stdout_stderr_string(&prog.stderr))
.emit();
info!("linker stderr:\n{}", escape_stdout_stderr_string(&prog.stderr));
info!("linker stdout:\n{}", escape_stdout_stderr_string(&prog.stdout));
}
Ok(_) => {}
Err(e) => {
let dwp_not_found = e.kind() == io::ErrorKind::NotFound;
let mut err = if dwp_not_found {
sess.struct_err(&format!("linker `{}` not found", LLVM_DWP_EXECUTABLE))
} else {
sess.struct_err(&format!("could not exec the linker `{}`", LLVM_DWP_EXECUTABLE))
};
err.note(&e.to_string());
if !dwp_not_found {
err.note(&format!("{:?}", &cmd));
}
err.emit();
}
}
}
/// Create a dynamic library or executable. /// Create a dynamic library or executable.
/// ///
/// This will invoke the system linker/cc to create the resulting file. This links to all upstream /// This will invoke the system linker/cc to create the resulting file. This links to all upstream
@ -661,7 +737,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
prog.status prog.status
)) ))
.note(&format!("{:?}", &cmd)) .note(&format!("{:?}", &cmd))
.note(&escape_string(&output)) .note(&escape_stdout_stderr_string(&output))
.emit(); .emit();
// If MSVC's `link.exe` was expected but the return code // If MSVC's `link.exe` was expected but the return code
@ -714,8 +790,8 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
sess.abort_if_errors(); sess.abort_if_errors();
} }
info!("linker stderr:\n{}", escape_string(&prog.stderr)); info!("linker stderr:\n{}", escape_stdout_stderr_string(&prog.stderr));
info!("linker stdout:\n{}", escape_string(&prog.stdout)); info!("linker stdout:\n{}", escape_stdout_stderr_string(&prog.stdout));
} }
Err(e) => { Err(e) => {
let linker_not_found = e.kind() == io::ErrorKind::NotFound; let linker_not_found = e.kind() == io::ErrorKind::NotFound;

View file

@ -274,8 +274,19 @@ impl ModuleConfig {
} }
} }
pub type TargetMachineFactoryFn<B> = /// Configuration passed to the function returned by the `target_machine_factory`.
Arc<dyn Fn() -> Result<<B as WriteBackendMethods>::TargetMachine, String> + Send + Sync>; pub struct TargetMachineFactoryConfig {
/// Split DWARF is enabled in LLVM by checking that `TM.MCOptions.SplitDwarfFile` isn't empty,
/// so the path to the dwarf object has to be provided when we create the target machine.
/// This can be ignored by backends which do not need it for their Split DWARF support.
pub split_dwarf_file: Option<PathBuf>,
}
pub type TargetMachineFactoryFn<B> = Arc<
dyn Fn(TargetMachineFactoryConfig) -> Result<<B as WriteBackendMethods>::TargetMachine, String>
+ Send
+ Sync,
>;
pub type ExportedSymbols = FxHashMap<CrateNum, Arc<Vec<(String, SymbolExportLevel)>>>; pub type ExportedSymbols = FxHashMap<CrateNum, Arc<Vec<(String, SymbolExportLevel)>>>;
@ -303,6 +314,7 @@ pub struct CodegenContext<B: WriteBackendMethods> {
pub target_pointer_width: u32, pub target_pointer_width: u32,
pub target_arch: String, pub target_arch: String,
pub debuginfo: config::DebugInfo, pub debuginfo: config::DebugInfo,
pub split_dwarf_kind: config::SplitDwarfKind,
// Number of cgus excluding the allocator/metadata modules // Number of cgus excluding the allocator/metadata modules
pub total_cgus: usize, pub total_cgus: usize,
@ -619,6 +631,12 @@ fn produce_final_output_artifacts(
} }
} }
if let Some(ref path) = module.dwarf_object {
if !keep_numbered_objects {
remove(sess, path);
}
}
if let Some(ref path) = module.bytecode { if let Some(ref path) = module.bytecode {
if !keep_numbered_bitcode { if !keep_numbered_bitcode {
remove(sess, path); remove(sess, path);
@ -841,6 +859,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
name: module.name, name: module.name,
kind: ModuleKind::Regular, kind: ModuleKind::Regular,
object, object,
dwarf_object: None,
bytecode: None, bytecode: None,
})) }))
} }
@ -1019,6 +1038,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
target_pointer_width: tcx.sess.target.pointer_width, target_pointer_width: tcx.sess.target.pointer_width,
target_arch: tcx.sess.target.arch.clone(), target_arch: tcx.sess.target.arch.clone(),
debuginfo: tcx.sess.opts.debuginfo, debuginfo: tcx.sess.opts.debuginfo,
split_dwarf_kind: tcx.sess.opts.debugging_opts.split_dwarf,
}; };
// This is the "main loop" of parallel work happening for parallel codegen. // This is the "main loop" of parallel work happening for parallel codegen.

View file

@ -64,13 +64,15 @@ impl<M> ModuleCodegen<M> {
pub fn into_compiled_module( pub fn into_compiled_module(
self, self,
emit_obj: bool, emit_obj: bool,
emit_dwarf_obj: bool,
emit_bc: bool, emit_bc: bool,
outputs: &OutputFilenames, outputs: &OutputFilenames,
) -> CompiledModule { ) -> CompiledModule {
let object = emit_obj.then(|| outputs.temp_path(OutputType::Object, Some(&self.name))); let object = emit_obj.then(|| outputs.temp_path(OutputType::Object, Some(&self.name)));
let dwarf_object = emit_dwarf_obj.then(|| outputs.temp_path_dwo(Some(&self.name)));
let bytecode = emit_bc.then(|| outputs.temp_path(OutputType::Bitcode, Some(&self.name))); let bytecode = emit_bc.then(|| outputs.temp_path(OutputType::Bitcode, Some(&self.name)));
CompiledModule { name: self.name.clone(), kind: self.kind, object, bytecode } CompiledModule { name: self.name.clone(), kind: self.kind, object, dwarf_object, bytecode }
} }
} }
@ -79,6 +81,7 @@ pub struct CompiledModule {
pub name: String, pub name: String,
pub kind: ModuleKind, pub kind: ModuleKind,
pub object: Option<PathBuf>, pub object: Option<PathBuf>,
pub dwarf_object: Option<PathBuf>,
pub bytecode: Option<PathBuf>, pub bytecode: Option<PathBuf>,
} }

View file

@ -550,6 +550,7 @@ impl_stable_hash_via_hash!(OutputFilenames);
pub const RLINK_EXT: &str = "rlink"; pub const RLINK_EXT: &str = "rlink";
pub const RUST_CGU_EXT: &str = "rcgu"; pub const RUST_CGU_EXT: &str = "rcgu";
pub const DWARF_OBJECT_EXT: &str = "dwo";
impl OutputFilenames { impl OutputFilenames {
pub fn new( pub fn new(
@ -583,7 +584,12 @@ impl OutputFilenames {
self.temp_path_ext(extension, codegen_unit_name) self.temp_path_ext(extension, codegen_unit_name)
} }
/// Like temp_path, but also supports things where there is no corresponding /// Like `temp_path`, but specifically for dwarf objects.
pub fn temp_path_dwo(&self, codegen_unit_name: Option<&str>) -> PathBuf {
self.temp_path_ext(DWARF_OBJECT_EXT, codegen_unit_name)
}
/// Like `temp_path`, but also supports things where there is no corresponding
/// OutputType, like noopt-bitcode or lto-bitcode. /// OutputType, like noopt-bitcode or lto-bitcode.
pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf { pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathBuf {
let mut extension = String::new(); let mut extension = String::new();
@ -610,6 +616,26 @@ impl OutputFilenames {
path.set_extension(extension); path.set_extension(extension);
path path
} }
/// Returns the path for the Split DWARF file - this can differ depending on which Split DWARF
/// mode is being used, which is the logic that this function is intended to encapsulate.
pub fn split_dwarf_file(
&self,
split_dwarf_kind: SplitDwarfKind,
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,
// 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),
// Split mode emits the DWARF into a different file, use that path.
SplitDwarfKind::Split => Some(dwo_out),
}
}
} }
pub fn host_triple() -> &'static str { pub fn host_triple() -> &'static str {