Add libgccjit dist generation
This commit is contained in:
parent
9028177115
commit
30feef626f
@ -2273,6 +2273,7 @@ fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
|
|||||||
tarball.permit_symlinks(true);
|
tarball.permit_symlinks(true);
|
||||||
|
|
||||||
builder.ensure(crate::core::build_steps::llvm::Llvm { target });
|
builder.ensure(crate::core::build_steps::llvm::Llvm { target });
|
||||||
|
builder.ensure(crate::core::build_steps::gcc::Gcc { target });
|
||||||
|
|
||||||
let src_bindir = builder.llvm_out(target).join("bin");
|
let src_bindir = builder.llvm_out(target).join("bin");
|
||||||
// If updating this, you likely want to change
|
// If updating this, you likely want to change
|
||||||
@ -2308,6 +2309,15 @@ fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
|
|||||||
// just broadly useful to be able to link against the bundled LLVM.
|
// just broadly useful to be able to link against the bundled LLVM.
|
||||||
tarball.add_dir(builder.llvm_out(target).join("include"), "include");
|
tarball.add_dir(builder.llvm_out(target).join("include"), "include");
|
||||||
|
|
||||||
|
let libgccjit_path = builder.gcc_out(target).join("install/lib/libgccjit.so");
|
||||||
|
if libgccjit_path.exists() {
|
||||||
|
tarball.add_dir(libgccjit_path, "libgccjit.so");
|
||||||
|
tarball.add_dir(
|
||||||
|
builder.gcc_out(target).join("install/lib/libgccjit.so.0"),
|
||||||
|
"libgccjit.so.0",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Copy libLLVM.so to the target lib dir as well, so the RPATH like
|
// Copy libLLVM.so to the target lib dir as well, so the RPATH like
|
||||||
// `$ORIGIN/../lib` can find it. It may also be used as a dependency
|
// `$ORIGIN/../lib` can find it. It may also be used as a dependency
|
||||||
// of `rustc-dev` to support the inherited `-lLLVM` when using the
|
// of `rustc-dev` to support the inherited `-lLLVM` when using the
|
||||||
|
226
src/bootstrap/src/core/build_steps/gcc.rs
Normal file
226
src/bootstrap/src/core/build_steps/gcc.rs
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
//! Compilation of native dependencies like LLVM.
|
||||||
|
//!
|
||||||
|
//! Native projects like LLVM unfortunately aren't suited just yet for
|
||||||
|
//! compilation in build scripts that Cargo has. This is because the
|
||||||
|
//! compilation takes a *very* long time but also because we don't want to
|
||||||
|
//! compile LLVM 3 times as part of a normal bootstrap (we want it cached).
|
||||||
|
//!
|
||||||
|
//! LLVM and compiler-rt are essentially just wired up to everything else to
|
||||||
|
//! ensure that they're always in place if needed.
|
||||||
|
|
||||||
|
use std::fs;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
|
use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
|
||||||
|
use crate::core::config::TargetSelection;
|
||||||
|
use crate::utils::exec::command;
|
||||||
|
use crate::utils::helpers::{self, t};
|
||||||
|
use crate::{generate_smart_stamp_hash, Kind};
|
||||||
|
|
||||||
|
use super::llvm::HashStamp;
|
||||||
|
|
||||||
|
pub struct Meta {
|
||||||
|
stamp: HashStamp,
|
||||||
|
out_dir: PathBuf,
|
||||||
|
install_dir: PathBuf,
|
||||||
|
root: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum GccBuildStatus {
|
||||||
|
AlreadyBuilt,
|
||||||
|
ShouldBuild(Meta),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This returns whether we've already previously built GCC.
|
||||||
|
///
|
||||||
|
/// 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 prebuilt_gcc_config(builder: &Builder<'_>, target: TargetSelection) -> GccBuildStatus {
|
||||||
|
// If we have gcc submodule initialized already, sync it.
|
||||||
|
builder.update_existing_submodule(&Path::new("src").join("gcc"));
|
||||||
|
|
||||||
|
// FIXME (GuillaumeGomez): To be done once gccjit has been built in the CI.
|
||||||
|
// builder.config.maybe_download_ci_gcc();
|
||||||
|
|
||||||
|
// Initialize the llvm submodule if not initialized already.
|
||||||
|
builder.update_submodule(&Path::new("src").join("gcc"));
|
||||||
|
|
||||||
|
let root = "src/gcc";
|
||||||
|
let out_dir = builder.gcc_out(target).join("build");
|
||||||
|
let install_dir = builder.gcc_out(target).join("install");
|
||||||
|
|
||||||
|
static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new();
|
||||||
|
let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| {
|
||||||
|
generate_smart_stamp_hash(
|
||||||
|
&builder.config.src.join("src/llvm-project"),
|
||||||
|
builder.in_tree_llvm_info.sha().unwrap_or_default(),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let stamp = out_dir.join("gcc-finished-building");
|
||||||
|
let stamp = HashStamp::new(stamp, Some(smart_stamp_hash));
|
||||||
|
|
||||||
|
if stamp.is_done() {
|
||||||
|
if stamp.hash.is_none() {
|
||||||
|
builder.info(
|
||||||
|
"Could not determine the GCC submodule commit hash. \
|
||||||
|
Assuming that an GCC rebuild is not necessary.",
|
||||||
|
);
|
||||||
|
builder.info(&format!(
|
||||||
|
"To force GCC to rebuild, remove the file `{}`",
|
||||||
|
stamp.path.display()
|
||||||
|
));
|
||||||
|
}
|
||||||
|
return GccBuildStatus::AlreadyBuilt;
|
||||||
|
}
|
||||||
|
|
||||||
|
GccBuildStatus::ShouldBuild(Meta { stamp, out_dir, install_dir, root: root.into() })
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME (GuillaumeGomez): When gcc-ci-download option is added, uncomment this code.
|
||||||
|
// /// This retrieves the GCC sha we *want* to use, according to git history.
|
||||||
|
// pub(crate) fn detect_gcc_sha(config: &Config, is_git: bool) -> String {
|
||||||
|
// let gcc_sha = if is_git {
|
||||||
|
// // We proceed in 2 steps. First we get the closest commit that is actually upstream. Then we
|
||||||
|
// // walk back further to the last bors merge commit that actually changed GCC. The first
|
||||||
|
// // step will fail on CI because only the `auto` branch exists; we just fall back to `HEAD`
|
||||||
|
// // in that case.
|
||||||
|
// let closest_upstream = get_git_merge_base(&config.git_config(), Some(&config.src))
|
||||||
|
// .unwrap_or_else(|_| "HEAD".into());
|
||||||
|
// let mut rev_list = config.git();
|
||||||
|
// rev_list.args(&[
|
||||||
|
// PathBuf::from("rev-list"),
|
||||||
|
// format!("--author={}", config.stage0_metadata.config.git_merge_commit_email).into(),
|
||||||
|
// "-n1".into(),
|
||||||
|
// "--first-parent".into(),
|
||||||
|
// closest_upstream.into(),
|
||||||
|
// "--".into(),
|
||||||
|
// config.src.join("src/gcc"),
|
||||||
|
// config.src.join("src/bootstrap/download-ci-gcc-stamp"),
|
||||||
|
// // the GCC shared object file is named `gcc-12-rust-{version}-nightly`
|
||||||
|
// config.src.join("src/version"),
|
||||||
|
// ]);
|
||||||
|
// output(&mut rev_list).trim().to_owned()
|
||||||
|
// } else if let Some(info) = channel::read_commit_info_file(&config.src) {
|
||||||
|
// info.sha.trim().to_owned()
|
||||||
|
// } else {
|
||||||
|
// "".to_owned()
|
||||||
|
// };
|
||||||
|
|
||||||
|
// if gcc_sha.is_empty() {
|
||||||
|
// eprintln!("error: could not find commit hash for downloading LLVM");
|
||||||
|
// eprintln!("HELP: maybe your repository history is too shallow?");
|
||||||
|
// eprintln!("HELP: consider disabling `download-ci-gcc`");
|
||||||
|
// eprintln!("HELP: or fetch enough history to include one upstream commit");
|
||||||
|
// panic!();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// gcc_sha
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /// Returns whether the CI-found GCC is currently usable.
|
||||||
|
// ///
|
||||||
|
// /// This checks both the build triple platform to confirm we're usable at all,
|
||||||
|
// /// and then verifies if the current HEAD matches the detected GCC SHA head,
|
||||||
|
// /// in which case GCC is indicated as not available.
|
||||||
|
// pub(crate) fn is_ci_gcc_available(config: &Config, asserts: bool) -> bool {
|
||||||
|
// // This is currently all tier 1 targets and tier 2 targets with host tools
|
||||||
|
// // (since others may not have CI artifacts)
|
||||||
|
// // https://doc.rust-lang.org/rustc/platform-support.html#tier-1
|
||||||
|
// let supported_platforms = [
|
||||||
|
// // tier 1
|
||||||
|
// ("x86_64-unknown-linux-gnu", true),
|
||||||
|
// ];
|
||||||
|
|
||||||
|
// if !supported_platforms.contains(&(&*config.build.triple, asserts))
|
||||||
|
// && (asserts || !supported_platforms.contains(&(&*config.build.triple, true)))
|
||||||
|
// {
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if is_ci_gcc_modified(config) {
|
||||||
|
// eprintln!("Detected GCC as non-available: running in CI and modified GCC in this change");
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// true
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /// Returns true if we're running in CI with modified GCC (and thus can't download it)
|
||||||
|
// pub(crate) fn is_ci_gcc_modified(config: &Config) -> bool {
|
||||||
|
// CiEnv::is_ci() && config.rust_info.is_managed_git_subrepository() && {
|
||||||
|
// // We assume we have access to git, so it's okay to unconditionally pass
|
||||||
|
// // `true` here.
|
||||||
|
// let gcc_sha = detect_gcc_sha(config, true);
|
||||||
|
// let head_sha = output(config.git().arg("rev-parse").arg("HEAD"));
|
||||||
|
// let head_sha = head_sha.trim();
|
||||||
|
// gcc_sha == head_sha
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||||
|
pub struct Gcc {
|
||||||
|
pub target: TargetSelection,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Step for Gcc {
|
||||||
|
type Output = bool;
|
||||||
|
|
||||||
|
const ONLY_HOSTS: bool = true;
|
||||||
|
|
||||||
|
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||||
|
run.path("src/gcc")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_run(run: RunConfig<'_>) {
|
||||||
|
run.builder.ensure(Gcc { target: run.target });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compile GCC for `target`.
|
||||||
|
fn run(self, builder: &Builder<'_>) -> bool {
|
||||||
|
let target = self.target;
|
||||||
|
if !target.contains("linux") || !target.contains("x86_64") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If GCC has already been built or been downloaded through download-ci-gcc, we avoid
|
||||||
|
// building it again.
|
||||||
|
let Meta { stamp, out_dir, install_dir, root } = match prebuilt_gcc_config(builder, target)
|
||||||
|
{
|
||||||
|
GccBuildStatus::AlreadyBuilt => return true,
|
||||||
|
GccBuildStatus::ShouldBuild(m) => m,
|
||||||
|
};
|
||||||
|
|
||||||
|
let _guard = builder.msg_unstaged(Kind::Build, "GCC", target);
|
||||||
|
t!(stamp.remove());
|
||||||
|
let _time = helpers::timeit(builder);
|
||||||
|
t!(fs::create_dir_all(&out_dir));
|
||||||
|
|
||||||
|
if builder.config.dry_run() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.run(
|
||||||
|
command(root.join("configure"))
|
||||||
|
.current_dir(&out_dir)
|
||||||
|
.arg("--enable-host-shared")
|
||||||
|
.arg("--enable-languages=jit")
|
||||||
|
.arg("--enable-checking=release")
|
||||||
|
.arg("--disable-bootstrap")
|
||||||
|
.arg("--disable-multilib")
|
||||||
|
.arg(format!("--prefix={}", install_dir.display())),
|
||||||
|
);
|
||||||
|
builder.run(command("make").current_dir(&out_dir).arg(format!("-j{}", builder.jobs())));
|
||||||
|
builder.run(command("make").current_dir(&out_dir).arg("install"));
|
||||||
|
|
||||||
|
t!(builder.symlink_file(
|
||||||
|
install_dir.join("lib/libgccjit.so"),
|
||||||
|
install_dir.join("lib/libgccjit.so.0")
|
||||||
|
));
|
||||||
|
|
||||||
|
t!(stamp.write());
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
@ -1242,17 +1242,17 @@ fn supported_sanitizers(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct HashStamp {
|
pub(super) struct HashStamp {
|
||||||
path: PathBuf,
|
pub(super) path: PathBuf,
|
||||||
hash: Option<Vec<u8>>,
|
pub(super) hash: Option<Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HashStamp {
|
impl HashStamp {
|
||||||
fn new(path: PathBuf, hash: Option<&str>) -> Self {
|
pub(super) fn new(path: PathBuf, hash: Option<&str>) -> Self {
|
||||||
HashStamp { path, hash: hash.map(|s| s.as_bytes().to_owned()) }
|
HashStamp { path, hash: hash.map(|s| s.as_bytes().to_owned()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_done(&self) -> bool {
|
pub(super) fn is_done(&self) -> bool {
|
||||||
match fs::read(&self.path) {
|
match fs::read(&self.path) {
|
||||||
Ok(h) => self.hash.as_deref().unwrap_or(b"") == h.as_slice(),
|
Ok(h) => self.hash.as_deref().unwrap_or(b"") == h.as_slice(),
|
||||||
Err(e) if e.kind() == io::ErrorKind::NotFound => false,
|
Err(e) if e.kind() == io::ErrorKind::NotFound => false,
|
||||||
@ -1262,7 +1262,7 @@ fn is_done(&self) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove(&self) -> io::Result<()> {
|
pub(super) fn remove(&self) -> io::Result<()> {
|
||||||
match fs::remove_file(&self.path) {
|
match fs::remove_file(&self.path) {
|
||||||
Ok(()) => Ok(()),
|
Ok(()) => Ok(()),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -1275,7 +1275,7 @@ fn remove(&self) -> io::Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&self) -> io::Result<()> {
|
pub(super) fn write(&self) -> io::Result<()> {
|
||||||
fs::write(&self.path, self.hash.as_deref().unwrap_or(b""))
|
fs::write(&self.path, self.hash.as_deref().unwrap_or(b""))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
pub(crate) mod dist;
|
pub(crate) mod dist;
|
||||||
pub(crate) mod doc;
|
pub(crate) mod doc;
|
||||||
pub(crate) mod format;
|
pub(crate) mod format;
|
||||||
|
pub(crate) mod gcc;
|
||||||
pub(crate) mod install;
|
pub(crate) mod install;
|
||||||
pub(crate) mod llvm;
|
pub(crate) mod llvm;
|
||||||
pub(crate) mod perf;
|
pub(crate) mod perf;
|
||||||
|
@ -765,6 +765,10 @@ fn enzyme_out(&self, target: TargetSelection) -> PathBuf {
|
|||||||
self.out.join(&*target.triple).join("enzyme")
|
self.out.join(&*target.triple).join("enzyme")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn gcc_out(&self, target: TargetSelection) -> PathBuf {
|
||||||
|
self.out.join(&*target.triple).join("gcc")
|
||||||
|
}
|
||||||
|
|
||||||
fn lld_out(&self, target: TargetSelection) -> PathBuf {
|
fn lld_out(&self, target: TargetSelection) -> PathBuf {
|
||||||
self.out.join(target).join("lld")
|
self.out.join(target).join("lld")
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user