Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 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
4 changes: 3 additions & 1 deletion src/bootstrap/src/core/build_steps/dist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2823,7 +2823,9 @@ impl Step for Gcc {
fn run(self, builder: &Builder<'_>) -> Self::Output {
let tarball = Tarball::new(builder, "gcc", &self.target.triple);
let output = builder.ensure(super::gcc::Gcc { target: self.target });
tarball.add_file(&output.libgccjit, "lib", FileType::NativeLibrary);
if let Some(ref path) = output.libgccjit {
tarball.add_file(path, "lib", FileType::NativeLibrary);
}
tarball.generate()
}

Expand Down
87 changes: 66 additions & 21 deletions src/bootstrap/src/core/build_steps/gcc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ pub struct Gcc {

#[derive(Clone)]
pub struct GccOutput {
pub libgccjit: PathBuf,
/// Path to a built or downloaded libgccjit.
/// Is None when setting libgccjit-libs-dir.
/// FIXME: it seems wrong to make this an Option.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Kobzol: What are your thoughts about this?

/// Perhaps it should be a Vec so that we can install all libs from libgccjit-libs-dir?
pub libgccjit: Option<PathBuf>,
}

impl GccOutput {
Expand All @@ -36,23 +40,55 @@ impl GccOutput {
return;
}

// At build time, cg_gcc has to link to libgccjit.so (the unversioned symbol).
// However, at runtime, it will by default look for libgccjit.so.0.
// So when we install the built libgccjit.so file to the target `directory`, we add it there
// with the `.0` suffix.
let mut target_filename = self.libgccjit.file_name().unwrap().to_str().unwrap().to_string();
target_filename.push_str(".0");

// If we build libgccjit ourselves, then `self.libgccjit` can actually be a symlink.
// In that case, we have to resolve it first, otherwise we'd create a symlink to a symlink,
// which wouldn't work.
let actual_libgccjit_path = t!(
self.libgccjit.canonicalize(),
format!("Cannot find libgccjit at {}", self.libgccjit.display())
);
if let Some(ref path) = self.libgccjit {
// At build time, cg_gcc has to link to libgccjit.so (the unversioned symbol).
// However, at runtime, it will by default look for libgccjit.so.0.
// So when we install the built libgccjit.so file to the target `directory`, we add it there
// with the `.0` suffix.
let mut target_filename = path.file_name().unwrap().to_str().unwrap().to_string();
target_filename.push_str(".0");

// If we build libgccjit ourselves, then `self.libgccjit` can actually be a symlink.
// In that case, we have to resolve it first, otherwise we'd create a symlink to a symlink,
// which wouldn't work.
let actual_libgccjit_path = t!(
path.canonicalize(),
format!("Cannot find libgccjit at {}", path.display())
);

let dst = directory.join(&target_filename);
builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary);
}

if let Some(ref path) = builder.config.libgccjit_libs_dir {
let host_target = builder.config.host_target.triple;

let source = path.join(host_target);
let dst = directory;

let targets = builder.config.targets.iter()
.map(|target| target.triple)
.chain(std::iter::once(host_target));

let target_filename = "libgccjit.so.0";
for target in targets {
let source = source.join(target).join(target_filename);
// To support symlinks in libgccjit-libs-dir, we have to resolve it first,
// otherwise we'd create a symlink to a symlink, which wouldn't work.
let actual_libgccjit_path = t!(
source.canonicalize(),
format!("Cannot find libgccjit at {}", source.display())
);
let target_dir = dst.join(target);
t!(
std::fs::create_dir_all(&target_dir),
format!("Cannot create target dir {} for libgccjit", target_dir.display())
);
let dst = target_dir.join(&target_filename);
builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary);
}
}

let dst = directory.join(target_filename);
builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary);
}
}

Expand All @@ -75,7 +111,8 @@ impl Step for Gcc {

// If GCC has already been built, we avoid building it again.
let metadata = match get_gcc_build_status(builder, target) {
GccBuildStatus::AlreadyBuilt(path) => return GccOutput { libgccjit: path },
GccBuildStatus::AlreadyBuilt(path) => return GccOutput { libgccjit: Some(path) },
GccBuildStatus::InLibsDir => return GccOutput { libgccjit: None },
GccBuildStatus::ShouldBuild(m) => m,
};

Expand All @@ -85,14 +122,14 @@ impl Step for Gcc {

let libgccjit_path = libgccjit_built_path(&metadata.install_dir);
if builder.config.dry_run() {
return GccOutput { libgccjit: libgccjit_path };
return GccOutput { libgccjit: Some(libgccjit_path) };
}

build_gcc(&metadata, builder, target);

t!(metadata.stamp.write());

GccOutput { libgccjit: libgccjit_path }
GccOutput { libgccjit: Some(libgccjit_path) }
}
}

Expand All @@ -106,6 +143,7 @@ pub struct Meta {
pub enum GccBuildStatus {
/// libgccjit is already built at this path
AlreadyBuilt(PathBuf),
InLibsDir,
ShouldBuild(Meta),
}

Expand Down Expand Up @@ -170,6 +208,11 @@ fn try_download_gcc(_builder: &Builder<'_>, _target: TargetSelection) -> Option<
/// It's used to avoid busting caches during x.py check -- if we've already built
/// GCC, it's fine for us to not try to avoid doing so.
pub fn get_gcc_build_status(builder: &Builder<'_>, target: TargetSelection) -> GccBuildStatus {
if matches!(builder.config.gcc_ci_mode, crate::core::config::GccCiMode::CopyFromLibsDir) {
// TODO: check if this is OK.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to myself: don't forget this.

return GccBuildStatus::InLibsDir;
}

if let Some(path) = try_download_gcc(builder, target) {
return GccBuildStatus::AlreadyBuilt(path);
}
Expand Down Expand Up @@ -293,7 +336,9 @@ fn build_gcc(metadata: &Meta, builder: &Builder<'_>, target: TargetSelection) {
/// Configures a Cargo invocation so that it can build the GCC codegen backend.
pub fn add_cg_gcc_cargo_flags(cargo: &mut Cargo, gcc: &GccOutput) {
// Add the path to libgccjit.so to the linker search paths.
cargo.rustflag(&format!("-L{}", gcc.libgccjit.parent().unwrap().to_str().unwrap()));
if let Some(ref path) = gcc.libgccjit {
cargo.rustflag(&format!("-L{}", path.parent().unwrap().to_str().unwrap()));
}
}

/// The absolute path to the downloaded GCC artifacts.
Expand Down
8 changes: 6 additions & 2 deletions src/bootstrap/src/core/build_steps/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3870,13 +3870,17 @@ impl Step for CodegenGCC {
.arg("test")
.arg("--use-backend")
.arg("gcc")
.arg("--gcc-path")
.arg(gcc.libgccjit.parent().unwrap())
.arg("--out-dir")
.arg(builder.stage_out(compilers.build_compiler(), Mode::Codegen).join("cg_gcc"))
.arg("--release")
.arg("--mini-tests")
.arg("--std-tests");

if let Some(ref path) = gcc.libgccjit {
cargo
.arg("--gcc-path")
.arg(path.parent().unwrap());
}
cargo.args(builder.config.test_args());

cargo.into_cmd().run(builder);
Expand Down
11 changes: 7 additions & 4 deletions src/bootstrap/src/core/config/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ pub struct Config {

// gcc codegen options
pub gcc_ci_mode: GccCiMode,
pub libgccjit_libs_dir: Option<PathBuf>,

// rust codegen options
pub rust_optimize: RustOptimize,
Expand Down Expand Up @@ -620,7 +621,7 @@ impl Config {
vendor: dist_vendor,
} = toml.dist.unwrap_or_default();

let Gcc { download_ci_gcc: gcc_download_ci_gcc } = toml.gcc.unwrap_or_default();
let Gcc { download_ci_gcc: gcc_download_ci_gcc, libgccjit_libs_dir } = toml.gcc.unwrap_or_default();

if rust_bootstrap_override_lld.is_some() && rust_bootstrap_override_lld_legacy.is_some() {
panic!(
Expand Down Expand Up @@ -1218,12 +1219,13 @@ impl Config {
Warnings::Default => rust_deny_warnings.unwrap_or(true),
};

let gcc_ci_mode = match gcc_download_ci_gcc {
Some(value) => match value {
let gcc_ci_mode = match (&libgccjit_libs_dir, gcc_download_ci_gcc) {
(Some(_), _) => GccCiMode::CopyFromLibsDir,
(None, Some(value)) => match value {
true => GccCiMode::DownloadFromCi,
false => GccCiMode::BuildLocally,
},
None => GccCiMode::default(),
(None, None) => GccCiMode::default(),
};

let targets = flags_target
Expand Down Expand Up @@ -1327,6 +1329,7 @@ impl Config {
free_args: flags_free_args,
full_bootstrap: build_full_bootstrap.unwrap_or(false),
gcc_ci_mode,
libgccjit_libs_dir,
gdb: build_gdb.map(PathBuf::from),
host_target,
hosts,
Expand Down
1 change: 1 addition & 0 deletions src/bootstrap/src/core/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,7 @@ pub enum GccCiMode {
/// If it is not available on CI, it will be built locally instead.
#[default]
DownloadFromCi,
CopyFromLibsDir,
}

pub fn threads_from_config(v: u32) -> u32 {
Expand Down
1 change: 1 addition & 0 deletions src/bootstrap/src/core/config/toml/gcc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ define_config! {
#[derive(Default)]
struct Gcc {
download_ci_gcc: Option<bool> = "download-ci-gcc",
libgccjit_libs_dir: Option<PathBuf> = "libgccjit-libs-dir",
}
}
Loading