Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[bootstrap] Distribute split debuginfo if present #138321

Merged
merged 1 commit into from
Mar 24, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 34 additions & 22 deletions src/bootstrap/src/core/build_steps/compile.rs
Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@ use crate::utils::exec::command;
use crate::utils::helpers::{
exe, get_clang_cl_resource_dir, is_debug_info, is_dylib, symlink_dir, t, up_to_date,
};
use crate::{CLang, Compiler, DependencyType, GitRepo, LLVM_TOOLS, Mode, debug, trace};
use crate::{CLang, Compiler, DependencyType, FileType, GitRepo, LLVM_TOOLS, Mode, debug, trace};

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Std {
@@ -321,7 +321,7 @@ fn copy_and_stamp(
dependency_type: DependencyType,
) {
let target = libdir.join(name);
builder.copy_link(&sourcedir.join(name), &target);
builder.copy_link(&sourcedir.join(name), &target, FileType::Regular);

target_deps.push((target, dependency_type));
}
@@ -330,7 +330,7 @@ fn copy_llvm_libunwind(builder: &Builder<'_>, target: TargetSelection, libdir: &
let libunwind_path = builder.ensure(llvm::Libunwind { target });
let libunwind_source = libunwind_path.join("libunwind.a");
let libunwind_target = libdir.join("libunwind.a");
builder.copy_link(&libunwind_source, &libunwind_target);
builder.copy_link(&libunwind_source, &libunwind_target, FileType::NativeLibrary);
libunwind_target
}

@@ -401,7 +401,7 @@ fn copy_self_contained_objects(
for &obj in &["crtbegin.o", "crtbeginS.o", "crtend.o", "crtendS.o"] {
let src = crt_path.join(obj);
let target = libdir_self_contained.join(obj);
builder.copy_link(&src, &target);
builder.copy_link(&src, &target, FileType::NativeLibrary);
target_deps.push((target, DependencyType::TargetSelfContained));
}
} else {
@@ -443,9 +443,9 @@ fn copy_self_contained_objects(
} else if target.is_windows_gnu() {
for obj in ["crt2.o", "dllcrt2.o"].iter() {
let src = compiler_file(builder, &builder.cc(target), target, CLang::C, obj);
let target = libdir_self_contained.join(obj);
builder.copy_link(&src, &target);
target_deps.push((target, DependencyType::TargetSelfContained));
let dst = libdir_self_contained.join(obj);
builder.copy_link(&src, &dst, FileType::NativeLibrary);
target_deps.push((dst, DependencyType::TargetSelfContained));
}
}

@@ -790,8 +790,11 @@ impl Step for StdLink {
let file = t!(file);
let path = file.path();
if path.is_file() {
builder
.copy_link(&path, &sysroot.join("lib").join(path.file_name().unwrap()));
builder.copy_link(
&path,
&sysroot.join("lib").join(path.file_name().unwrap()),
FileType::Regular,
);
}
}
}
@@ -829,7 +832,7 @@ fn copy_sanitizers(

for runtime in &runtimes {
let dst = libdir.join(&runtime.name);
builder.copy_link(&runtime.path, &dst);
builder.copy_link(&runtime.path, &dst, FileType::NativeLibrary);

// The `aarch64-apple-ios-macabi` and `x86_64-apple-ios-macabi` are also supported for
// sanitizers, but they share a sanitizer runtime with `${arch}-apple-darwin`, so we do
@@ -934,9 +937,9 @@ impl Step for StartupObjects {
.run(builder);
}

let target = sysroot_dir.join((*file).to_string() + ".o");
builder.copy_link(dst_file, &target);
target_deps.push((target, DependencyType::Target));
let obj = sysroot_dir.join((*file).to_string() + ".o");
builder.copy_link(dst_file, &obj, FileType::NativeLibrary);
target_deps.push((obj, DependencyType::Target));
}

target_deps
@@ -952,7 +955,7 @@ fn cp_rustc_component_to_ci_sysroot(builder: &Builder<'_>, sysroot: &Path, conte
if src.is_dir() {
t!(fs::create_dir_all(dst));
} else {
builder.copy_link(&src, &dst);
builder.copy_link(&src, &dst, FileType::Regular);
}
}
}
@@ -1707,7 +1710,7 @@ fn copy_codegen_backends_to_sysroot(
let dot = filename.find('.').unwrap();
format!("{}-{}{}", &filename[..dash], builder.rust_release(), &filename[dot..])
};
builder.copy_link(file, &dst.join(target_filename));
builder.copy_link(file, &dst.join(target_filename), FileType::NativeLibrary);
}
}

@@ -2011,7 +2014,11 @@ impl Step for Assemble {
extra_features: vec![],
});
let tool_exe = exe("llvm-bitcode-linker", target_compiler.host);
builder.copy_link(&llvm_bitcode_linker.tool_path, &libdir_bin.join(tool_exe));
builder.copy_link(
&llvm_bitcode_linker.tool_path,
&libdir_bin.join(tool_exe),
FileType::Executable,
);
}
};

@@ -2072,8 +2079,8 @@ impl Step for Assemble {
builder.sysroot_target_libdir(target_compiler, target_compiler.host);
let dst_lib = libdir.join(&libenzyme).with_extension(lib_ext);
let target_dst_lib = target_libdir.join(&libenzyme).with_extension(lib_ext);
builder.copy_link(&src_lib, &dst_lib);
builder.copy_link(&src_lib, &target_dst_lib);
builder.copy_link(&src_lib, &dst_lib, FileType::NativeLibrary);
builder.copy_link(&src_lib, &target_dst_lib, FileType::NativeLibrary);
}

// Build the libraries for this compiler to link to (i.e., the libraries
@@ -2168,7 +2175,7 @@ impl Step for Assemble {
};

if is_dylib_or_debug && can_be_rustc_dynamic_dep && !is_proc_macro {
builder.copy_link(&f.path(), &rustc_libdir.join(&filename));
builder.copy_link(&f.path(), &rustc_libdir.join(&filename), FileType::Regular);
}
}

@@ -2196,7 +2203,11 @@ impl Step for Assemble {
// See <https://github.com/rust-lang/rust/issues/132719>.
let src_exe = exe("llvm-objcopy", target_compiler.host);
let dst_exe = exe("rust-objcopy", target_compiler.host);
builder.copy_link(&libdir_bin.join(src_exe), &libdir_bin.join(dst_exe));
builder.copy_link(
&libdir_bin.join(src_exe),
&libdir_bin.join(dst_exe),
FileType::Executable,
);
}

// In addition to `rust-lld` also install `wasm-component-ld` when
@@ -2212,6 +2223,7 @@ impl Step for Assemble {
builder.copy_link(
&wasm_component.tool_path,
&libdir_bin.join(wasm_component.tool_path.file_name().unwrap()),
FileType::Executable,
);
}

@@ -2234,7 +2246,7 @@ impl Step for Assemble {
t!(fs::create_dir_all(bindir));
let compiler = builder.rustc(target_compiler);
debug!(src = ?rustc, dst = ?compiler, "linking compiler binary itself");
builder.copy_link(&rustc, &compiler);
builder.copy_link(&rustc, &compiler, FileType::Executable);

target_compiler
}
@@ -2260,7 +2272,7 @@ pub fn add_to_sysroot(
DependencyType::Target => sysroot_dst,
DependencyType::TargetSelfContained => self_contained_dst,
};
builder.copy_link(&path, &dst.join(path.file_name().unwrap()));
builder.copy_link(&path, &dst.join(path.file_name().unwrap()), FileType::Regular);
}
}

155 changes: 103 additions & 52 deletions src/bootstrap/src/core/build_steps/dist.rs

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion src/bootstrap/src/core/build_steps/doc.rs
Original file line number Diff line number Diff line change
@@ -11,14 +11,14 @@ use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::{env, fs, mem};

use crate::Mode;
use crate::core::build_steps::compile;
use crate::core::build_steps::tool::{self, SourceType, Tool, prepare_tool_cargo};
use crate::core::builder::{
self, Alias, Builder, Compiler, Kind, RunConfig, ShouldRun, Step, crate_description,
};
use crate::core::config::{Config, TargetSelection};
use crate::helpers::{submodule_path_of, symlink_dir, t, up_to_date};
use crate::{FileType, Mode};

macro_rules! book {
($($name:ident, $path:expr, $book_name:expr, $lang:expr ;)+) => {
@@ -546,6 +546,7 @@ impl Step for SharedAssets {
builder.copy_link(
&builder.src.join("src").join("doc").join("rust.css"),
&out.join("rust.css"),
FileType::Regular,
);

SharedAssetsPaths { version_info }
32 changes: 21 additions & 11 deletions src/bootstrap/src/core/build_steps/tool.rs
Original file line number Diff line number Diff line change
@@ -26,7 +26,7 @@ use crate::core::config::{DebuginfoLevel, RustcLto, TargetSelection};
use crate::utils::channel::GitInfo;
use crate::utils::exec::{BootstrapCommand, command};
use crate::utils::helpers::{add_dylib_path, exe, t};
use crate::{Compiler, Kind, Mode, gha};
use crate::{Compiler, FileType, Kind, Mode, gha};

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum SourceType {
@@ -353,7 +353,7 @@ fn copy_link_tool_bin(
) -> PathBuf {
let cargo_out = builder.cargo_out(compiler, mode, target).join(exe(name, target));
let bin = builder.tools_dir(compiler).join(exe(name, target));
builder.copy_link(&cargo_out, &bin);
builder.copy_link(&cargo_out, &bin, FileType::Executable);
bin
}

@@ -696,7 +696,7 @@ impl Step for Rustdoc {
.join(exe("rustdoc", target_compiler.host));

let bin_rustdoc = bin_rustdoc();
builder.copy_link(&precompiled_rustdoc, &bin_rustdoc);
builder.copy_link(&precompiled_rustdoc, &bin_rustdoc, FileType::Executable);

return ToolBuildResult {
tool_path: bin_rustdoc,
@@ -743,7 +743,7 @@ impl Step for Rustdoc {
compile::strip_debug(builder, target, &tool_path);
}
let bin_rustdoc = bin_rustdoc();
builder.copy_link(&tool_path, &bin_rustdoc);
builder.copy_link(&tool_path, &bin_rustdoc, FileType::Executable);
ToolBuildResult { tool_path: bin_rustdoc, build_compiler, target_compiler }
} else {
ToolBuildResult { tool_path, build_compiler, target_compiler }
@@ -846,13 +846,20 @@ impl Step for LldWrapper {
let src_exe = exe("lld", target);
let dst_exe = exe("rust-lld", target);

builder.copy_link(&lld_install.join("bin").join(src_exe), &libdir_bin.join(dst_exe));
builder.copy_link(
&lld_install.join("bin").join(src_exe),
&libdir_bin.join(dst_exe),
FileType::Executable,
);
let self_contained_lld_dir = libdir_bin.join("gcc-ld");
t!(fs::create_dir_all(&self_contained_lld_dir));

for name in crate::LLD_FILE_NAMES {
builder
.copy_link(&tool_result.tool_path, &self_contained_lld_dir.join(exe(name, target)));
builder.copy_link(
&tool_result.tool_path,
&self_contained_lld_dir.join(exe(name, target)),
FileType::Executable,
);
}

tool_result
@@ -949,8 +956,11 @@ impl Step for RustAnalyzerProcMacroSrv {
// so that r-a can use it.
let libexec_path = builder.sysroot(self.compiler).join("libexec");
t!(fs::create_dir_all(&libexec_path));
builder
.copy_link(&tool_result.tool_path, &libexec_path.join("rust-analyzer-proc-macro-srv"));
builder.copy_link(
&tool_result.tool_path,
&libexec_path.join("rust-analyzer-proc-macro-srv"),
FileType::Executable,
);

Some(tool_result)
}
@@ -1007,7 +1017,7 @@ impl Step for LlvmBitcodeLinker {
t!(fs::create_dir_all(&bindir_self_contained));
let bin_destination = bindir_self_contained
.join(exe("llvm-bitcode-linker", tool_result.target_compiler.host));
builder.copy_link(&tool_result.tool_path, &bin_destination);
builder.copy_link(&tool_result.tool_path, &bin_destination, FileType::Executable);
ToolBuildResult {
tool_path: bin_destination,
build_compiler: tool_result.build_compiler,
@@ -1189,7 +1199,7 @@ fn run_tool_build_step(

for add_bin in add_bins_to_sysroot {
let bin_destination = bindir.join(exe(add_bin, target_compiler.host));
builder.copy_link(&tool_path, &bin_destination);
builder.copy_link(&tool_path, &bin_destination, FileType::Executable);
}

// Return a path into the bin dir.
63 changes: 56 additions & 7 deletions src/bootstrap/src/lib.rs
Original file line number Diff line number Diff line change
@@ -36,7 +36,9 @@ use crate::core::builder;
use crate::core::builder::Kind;
use crate::core::config::{DryRun, LldMode, LlvmLibunwind, Target, TargetSelection, flags};
use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, CommandOutput, OutputMode, command};
use crate::utils::helpers::{self, dir_is_empty, exe, libdir, output, set_file_times, symlink_dir};
use crate::utils::helpers::{
self, dir_is_empty, exe, libdir, output, set_file_times, split_debuginfo, symlink_dir,
};

mod core;
mod utils;
@@ -274,6 +276,35 @@ pub enum CLang {
Cxx,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FileType {
/// An executable binary file (like a `.exe`).
Executable,
/// A native, binary library file (like a `.so`, `.dll`, `.a`, `.lib` or `.o`).
NativeLibrary,
/// An executable (non-binary) script file (like a `.py` or `.sh`).
Script,
/// Any other regular file that is non-executable.
Regular,
}

impl FileType {
/// Get Unix permissions appropriate for this file type.
pub fn perms(self) -> u32 {
match self {
FileType::Executable | FileType::Script => 0o755,
FileType::Regular | FileType::NativeLibrary => 0o644,
}
}

pub fn could_have_split_debuginfo(self) -> bool {
match self {
FileType::Executable | FileType::NativeLibrary => true,
FileType::Script | FileType::Regular => false,
}
}
}

macro_rules! forward {
( $( $fn:ident( $($param:ident: $ty:ty),* ) $( -> $ret:ty)? ),+ $(,)? ) => {
impl Build {
@@ -1744,8 +1775,18 @@ Executed at: {executed_at}"#,
/// Attempts to use hard links if possible, falling back to copying.
/// You can neither rely on this being a copy nor it being a link,
/// so do not write to dst.
pub fn copy_link(&self, src: &Path, dst: &Path) {
pub fn copy_link(&self, src: &Path, dst: &Path, file_type: FileType) {
self.copy_link_internal(src, dst, false);

if file_type.could_have_split_debuginfo() {
if let Some(dbg_file) = split_debuginfo(src) {
self.copy_link_internal(
&dbg_file,
&dst.with_extension(dbg_file.extension().unwrap()),
false,
);
}
}
}

fn copy_link_internal(&self, src: &Path, dst: &Path, dereference_symlinks: bool) {
@@ -1808,7 +1849,7 @@ Executed at: {executed_at}"#,
t!(fs::create_dir_all(&dst));
self.cp_link_r(&path, &dst);
} else {
self.copy_link(&path, &dst);
self.copy_link(&path, &dst, FileType::Regular);
}
}
}
@@ -1844,7 +1885,7 @@ Executed at: {executed_at}"#,
self.cp_link_filtered_recurse(&path, &dst, &relative, filter);
} else {
let _ = fs::remove_file(&dst);
self.copy_link(&path, &dst);
self.copy_link(&path, &dst, FileType::Regular);
}
}
}
@@ -1853,10 +1894,10 @@ Executed at: {executed_at}"#,
fn copy_link_to_folder(&self, src: &Path, dest_folder: &Path) {
let file_name = src.file_name().unwrap();
let dest = dest_folder.join(file_name);
self.copy_link(src, &dest);
self.copy_link(src, &dest, FileType::Regular);
}

fn install(&self, src: &Path, dstdir: &Path, perms: u32) {
fn install(&self, src: &Path, dstdir: &Path, file_type: FileType) {
if self.config.dry_run() {
return;
}
@@ -1866,8 +1907,16 @@ Executed at: {executed_at}"#,
if !src.exists() {
panic!("ERROR: File \"{}\" not found!", src.display());
}

self.copy_link_internal(src, &dst, true);
chmod(&dst, perms);
chmod(&dst, file_type.perms());

// If this file can have debuginfo, look for split debuginfo and install it too.
if file_type.could_have_split_debuginfo() {
if let Some(dbg_file) = split_debuginfo(src) {
self.install(&dbg_file, dstdir, FileType::Regular);
}
}
}

fn read(&self, path: &Path) -> String {
17 changes: 17 additions & 0 deletions src/bootstrap/src/utils/helpers.rs
Original file line number Diff line number Diff line change
@@ -52,6 +52,23 @@ pub fn exe(name: &str, target: TargetSelection) -> String {
crate::utils::shared_helpers::exe(name, &target.triple)
}

/// Returns the path to the split debug info for the specified file if it exists.
pub fn split_debuginfo(name: impl Into<PathBuf>) -> Option<PathBuf> {
// FIXME: only msvc is currently supported

let path = name.into();
let pdb = path.with_extension("pdb");
if pdb.exists() {
return Some(pdb);
}

// pdbs get named with '-' replaced by '_'
let file_name = pdb.file_name()?.to_str()?.replace("-", "_");

let pdb: PathBuf = [path.parent()?, Path::new(&file_name)].into_iter().collect();
pdb.exists().then_some(pdb)
}

/// Returns `true` if the file name given looks like a dynamic library.
pub fn is_dylib(path: &Path) -> bool {
path.extension().and_then(|ext| ext.to_str()).is_some_and(|ext| {
28 changes: 22 additions & 6 deletions src/bootstrap/src/utils/tarball.rs
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@
use std::path::{Path, PathBuf};

use crate::FileType;
use crate::core::build_steps::dist::distdir;
use crate::core::builder::{Builder, Kind};
use crate::core::config::BUILDER_CONFIG_FILENAME;
@@ -182,7 +183,12 @@ impl<'a> Tarball<'a> {
&self.image_dir
}

pub(crate) fn add_file(&self, src: impl AsRef<Path>, destdir: impl AsRef<Path>, perms: u32) {
pub(crate) fn add_file(
&self,
src: impl AsRef<Path>,
destdir: impl AsRef<Path>,
file_type: FileType,
) {
// create_dir_all fails to create `foo/bar/.`, so when the destination is "." this simply
// uses the base directory as the destination directory.
let destdir = if destdir.as_ref() == Path::new(".") {
@@ -192,23 +198,24 @@ impl<'a> Tarball<'a> {
};

t!(std::fs::create_dir_all(&destdir));
self.builder.install(src.as_ref(), &destdir, perms);
self.builder.install(src.as_ref(), &destdir, file_type);
}

pub(crate) fn add_renamed_file(
&self,
src: impl AsRef<Path>,
destdir: impl AsRef<Path>,
new_name: &str,
file_type: FileType,
) {
let destdir = self.image_dir.join(destdir.as_ref());
t!(std::fs::create_dir_all(&destdir));
self.builder.copy_link(src.as_ref(), &destdir.join(new_name));
self.builder.copy_link(src.as_ref(), &destdir.join(new_name), file_type);
}

pub(crate) fn add_legal_and_readme_to(&self, destdir: impl AsRef<Path>) {
for file in self.overlay.legal_and_readme() {
self.add_file(self.builder.src.join(file), destdir.as_ref(), 0o644);
self.add_file(self.builder.src.join(file), destdir.as_ref(), FileType::Regular);
}
}

@@ -318,11 +325,20 @@ impl<'a> Tarball<'a> {

// Add config file if present.
if let Some(config) = &self.builder.config.config {
self.add_renamed_file(config, &self.overlay_dir, BUILDER_CONFIG_FILENAME);
self.add_renamed_file(
config,
&self.overlay_dir,
BUILDER_CONFIG_FILENAME,
FileType::Regular,
);
}

for file in self.overlay.legal_and_readme() {
self.builder.install(&self.builder.src.join(file), &self.overlay_dir, 0o644);
self.builder.install(
&self.builder.src.join(file),
&self.overlay_dir,
FileType::Regular,
);
}

let mut cmd = self.builder.tool_cmd(crate::core::build_steps::tool::Tool::RustInstaller);
Loading