Skip to content
Merged
Show file tree
Hide file tree
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
29 changes: 19 additions & 10 deletions src/bootstrap/src/core/build_steps/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1612,26 +1612,35 @@ impl GccDylibSet {
"Trying to install libgccjit ({target_pair}) to a compiler with a different host ({})",
compiler.host
);
let libgccjit = libgccjit.libgccjit();
let target_filename = libgccjit.file_name().unwrap().to_str().unwrap();
let libgccjit_path = libgccjit.libgccjit();

// If we build libgccjit ourselves, then `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!(
libgccjit.canonicalize(),
format!("Cannot find libgccjit at {}", libgccjit.display())
let libgccjit_path = t!(
libgccjit_path.canonicalize(),
format!("Cannot find libgccjit at {}", libgccjit_path.display())
);

// <cg-sysroot>/lib/<target>/libgccjit.so
let dest_dir = cg_sysroot.join("lib").join(target_pair.target());
t!(fs::create_dir_all(&dest_dir));
let dst = dest_dir.join(target_filename);
builder.copy_link(&actual_libgccjit_path, &dst, FileType::NativeLibrary);
let dst = cg_sysroot.join(libgccjit_path_relative_to_cg_dir(target_pair, libgccjit));
t!(std::fs::create_dir_all(dst.parent().unwrap()));
builder.copy_link(&libgccjit_path, &dst, FileType::NativeLibrary);
}
}
}

/// Returns a path where libgccjit.so should be stored, **relative** to the
/// **codegen backend directory**.
pub fn libgccjit_path_relative_to_cg_dir(
target_pair: &GccTargetPair,
libgccjit: &GccOutput,
) -> PathBuf {
let target_filename = libgccjit.libgccjit().file_name().unwrap().to_str().unwrap();

// <cg-dir>/lib/<target>/libgccjit.so
Path::new("lib").join(target_pair.target()).join(target_filename)
}

/// Output of the `compile::GccCodegenBackend` step.
///
/// It contains a build stamp with the path to the built cg_gcc dylib.
Expand Down
84 changes: 83 additions & 1 deletion src/bootstrap/src/core/build_steps/dist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ use object::read::archive::ArchiveFile;
#[cfg(feature = "tracing")]
use tracing::instrument;

use crate::core::build_steps::compile::{get_codegen_backend_file, normalize_codegen_backend_name};
use crate::core::build_steps::compile::{
get_codegen_backend_file, libgccjit_path_relative_to_cg_dir, normalize_codegen_backend_name,
};
use crate::core::build_steps::doc::DocumentationFormat;
use crate::core::build_steps::gcc::GccTargetPair;
use crate::core::build_steps::tool::{
Expand Down Expand Up @@ -2992,3 +2994,83 @@ impl Step for GccDev {
Some(StepMetadata::dist("gcc-dev", self.target))
}
}

/// Tarball containing a libgccjit dylib,
/// needed as a dependency for the GCC codegen backend (similarly to the LLVM
/// backend needing a prebuilt libLLVM).
///
/// This component is used for distribution through rustup.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Gcc {
host: TargetSelection,
target: TargetSelection,
}

impl Step for Gcc {
type Output = Option<GeneratedTarball>;

fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
run.alias("gcc")
}

fn make_run(run: RunConfig<'_>) {
// GCC is always built for a target pair, (host, target).
// We do not yet support cross-compilation here, so the host target is always inferred to
// be the bootstrap host target.
run.builder.ensure(Gcc { host: run.builder.host_target, target: run.target });
}

fn run(self, builder: &Builder<'_>) -> Self::Output {
// This prevents gcc from being built for "dist"
// or "install" on the stable/beta channels. It is not yet stable and
// should not be included.
if !builder.build.unstable_features() {
return None;
}

let host = self.host;
let target = self.target;
if host != "x86_64-unknown-linux-gnu" {
builder.info(&format!("host target `{host}` not supported by gcc. skipping"));
return None;
}

// We need the GCC sources to build GCC and also to add its license and README
// files to the tarball
builder.require_submodule(
"src/gcc",
Some("The src/gcc submodule is required for disting libgccjit"),
);

let target_pair = GccTargetPair::for_target_pair(host, target);
let libgccjit = builder.ensure(super::gcc::Gcc { target_pair });

// We have to include the target name in the component name, so that rustup can somehow
// distinguish that there are multiple gcc components on a given host target.
// So the tarball includes the target name.
let mut tarball = Tarball::new(builder, &format!("gcc-{target}"), &host.triple);
tarball.set_overlay(OverlayKind::Gcc);
tarball.is_preview(true);
tarball.add_legal_and_readme_to("share/doc/gcc");

// The path where to put libgccjit is determined by GccDylibSet.
// However, it requires a Compiler to figure out the path to the codegen backend sysroot.
// We don't really have any compiler here, because we just build libgccjit.
// So we duplicate the logic for determining the CG sysroot here.
let cg_dir = PathBuf::from(format!("lib/rustlib/{host}/codegen-backends"));

// This returns the path to the actual file, but here we need its parent
let rel_libgccjit_path = libgccjit_path_relative_to_cg_dir(&target_pair, &libgccjit);
let path = cg_dir.join(rel_libgccjit_path.parent().unwrap());

tarball.add_file(libgccjit.libgccjit(), path, FileType::NativeLibrary);
Some(tarball.generate())
}

fn metadata(&self) -> Option<StepMetadata> {
Some(StepMetadata::dist(
"gcc",
TargetSelection::from_user(&format!("({}, {})", self.host, self.target)),
))
}
}
3 changes: 2 additions & 1 deletion src/bootstrap/src/core/builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -990,7 +990,8 @@ impl<'a> Builder<'a> {
dist::PlainSourceTarballGpl,
dist::BuildManifest,
dist::ReproducibleArtifacts,
dist::GccDev
dist::GccDev,
dist::Gcc
),
Kind::Install => describe!(
install::Docs,
Expand Down
10 changes: 10 additions & 0 deletions src/bootstrap/src/utils/tarball.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub(crate) enum OverlayKind {
RustAnalyzer,
RustcCodegenCranelift,
RustcCodegenGcc,
Gcc,
LlvmBitcodeLinker,
}

Expand Down Expand Up @@ -78,6 +79,14 @@ impl OverlayKind {
"LICENSE-MIT",
"src/tools/llvm-bitcode-linker/README.md",
],
OverlayKind::Gcc => &[
"src/gcc/README",
"src/gcc/COPYING",
"src/gcc/COPYING.LIB",
"src/gcc/COPYING.RUNTIME",
"src/gcc/COPYING3",
"src/gcc/COPYING3.LIB",
],
}
}

Expand All @@ -101,6 +110,7 @@ impl OverlayKind {
OverlayKind::RustcCodegenCranelift => builder.rust_version(),
OverlayKind::RustcCodegenGcc => builder.rust_version(),
OverlayKind::LlvmBitcodeLinker => builder.rust_version(),
OverlayKind::Gcc => builder.rust_version(),
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@ python3 ../x.py build --set rust.debug=true opt-dist
# Use GCC for building GCC components, as it seems to behave badly when built with Clang
# Only build GCC on full builds, not try builds
if [ "${DIST_TRY_BUILD:-0}" == "0" ]; then
CC=/rustroot/bin/cc CXX=/rustroot/bin/c++ python3 ../x.py dist gcc-dev
CC=/rustroot/bin/cc CXX=/rustroot/bin/c++ python3 ../x.py dist \
gcc-dev \
gcc
fi
Loading