Auto merge of #125411 - onur-ozkan:sanity-check-libstdc++, r=Mark-Simulacrum
check host's libstdc++ version when using ci llvm If the host's libstdc++ version is too old using ci-llvm may result in an ABI mismatch between the local libstdc++ and libLLVM.so. This PR adds a sanity check to immediately fail at the beginning of the bootstrap before starting the actual build. I am not sure if '8' is the best threshold, but it should be a good start and we can increase it anytime if needed. Fixes #123037
This commit is contained in:
commit
50297bb417
@ -10,6 +10,7 @@
|
|||||||
use crate::core::config::TargetSelection;
|
use crate::core::config::TargetSelection;
|
||||||
use crate::utils::channel::GitInfo;
|
use crate::utils::channel::GitInfo;
|
||||||
use crate::utils::exec::BootstrapCommand;
|
use crate::utils::exec::BootstrapCommand;
|
||||||
|
use crate::utils::helpers::output;
|
||||||
use crate::utils::helpers::{add_dylib_path, exe, t};
|
use crate::utils::helpers::{add_dylib_path, exe, t};
|
||||||
use crate::Compiler;
|
use crate::Compiler;
|
||||||
use crate::Mode;
|
use crate::Mode;
|
||||||
@ -804,6 +805,59 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||||
|
pub struct LibcxxVersionTool {
|
||||||
|
pub target: TargetSelection,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum LibcxxVersion {
|
||||||
|
Gnu(usize),
|
||||||
|
Llvm(usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Step for LibcxxVersionTool {
|
||||||
|
type Output = LibcxxVersion;
|
||||||
|
const DEFAULT: bool = false;
|
||||||
|
const ONLY_HOSTS: bool = true;
|
||||||
|
|
||||||
|
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||||
|
run.never()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(self, builder: &Builder<'_>) -> LibcxxVersion {
|
||||||
|
let out_dir = builder.out.join(self.target.to_string()).join("libcxx-version");
|
||||||
|
let _ = fs::remove_dir_all(&out_dir);
|
||||||
|
t!(fs::create_dir_all(&out_dir));
|
||||||
|
|
||||||
|
let compiler = builder.cxx(self.target).unwrap();
|
||||||
|
let mut cmd = Command::new(compiler);
|
||||||
|
|
||||||
|
let executable = out_dir.join("libcxx-version");
|
||||||
|
cmd.arg("-o").arg(&executable).arg(builder.src.join("src/tools/libcxx-version/main.cpp"));
|
||||||
|
|
||||||
|
builder.run_cmd(&mut cmd);
|
||||||
|
|
||||||
|
if !executable.exists() {
|
||||||
|
panic!("Something went wrong. {} is not present", executable.display());
|
||||||
|
}
|
||||||
|
|
||||||
|
let version_output = output(&mut Command::new(executable));
|
||||||
|
|
||||||
|
let version_str = version_output.split_once("version:").unwrap().1;
|
||||||
|
let version = version_str.trim().parse::<usize>().unwrap();
|
||||||
|
|
||||||
|
if version_output.starts_with("libstdc++") {
|
||||||
|
LibcxxVersion::Gnu(version)
|
||||||
|
} else if version_output.starts_with("libc++") {
|
||||||
|
LibcxxVersion::Llvm(version)
|
||||||
|
} else {
|
||||||
|
panic!("Coudln't recognize the standard library version.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! tool_extended {
|
macro_rules! tool_extended {
|
||||||
(($sel:ident, $builder:ident),
|
(($sel:ident, $builder:ident),
|
||||||
$($name:ident,
|
$($name:ident,
|
||||||
|
@ -15,6 +15,10 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "bootstrap-self-test"))]
|
||||||
|
use crate::builder::Builder;
|
||||||
|
#[cfg(not(feature = "bootstrap-self-test"))]
|
||||||
|
use crate::core::build_steps::tool;
|
||||||
#[cfg(not(feature = "bootstrap-self-test"))]
|
#[cfg(not(feature = "bootstrap-self-test"))]
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
@ -38,6 +42,11 @@ pub struct Finder {
|
|||||||
// just a dummy comment so the list doesn't get onelined
|
// just a dummy comment so the list doesn't get onelined
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/// Minimum version threshold for libstdc++ required when using prebuilt LLVM
|
||||||
|
/// from CI (with`llvm.download-ci-llvm` option).
|
||||||
|
#[cfg(not(feature = "bootstrap-self-test"))]
|
||||||
|
const LIBSTDCXX_MIN_VERSION_THRESHOLD: usize = 8;
|
||||||
|
|
||||||
impl Finder {
|
impl Finder {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { cache: HashMap::new(), path: env::var_os("PATH").unwrap_or_default() }
|
Self { cache: HashMap::new(), path: env::var_os("PATH").unwrap_or_default() }
|
||||||
@ -102,6 +111,32 @@ pub fn check(build: &mut Build) {
|
|||||||
cmd_finder.must_have("git");
|
cmd_finder.must_have("git");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure that a compatible version of libstdc++ is available on the system when using `llvm.download-ci-llvm`.
|
||||||
|
#[cfg(not(feature = "bootstrap-self-test"))]
|
||||||
|
if !build.config.dry_run() && !build.build.is_msvc() && build.config.llvm_from_ci {
|
||||||
|
let builder = Builder::new(build);
|
||||||
|
let libcxx_version = builder.ensure(tool::LibcxxVersionTool { target: build.build });
|
||||||
|
|
||||||
|
match libcxx_version {
|
||||||
|
tool::LibcxxVersion::Gnu(version) => {
|
||||||
|
if LIBSTDCXX_MIN_VERSION_THRESHOLD > version {
|
||||||
|
eprintln!(
|
||||||
|
"\nYour system's libstdc++ version is too old for the `llvm.download-ci-llvm` option."
|
||||||
|
);
|
||||||
|
eprintln!("Current version detected: '{}'", version);
|
||||||
|
eprintln!("Minimum required version: '{}'", LIBSTDCXX_MIN_VERSION_THRESHOLD);
|
||||||
|
eprintln!(
|
||||||
|
"Consider upgrading libstdc++ or disabling the `llvm.download-ci-llvm` option."
|
||||||
|
);
|
||||||
|
crate::exit!(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tool::LibcxxVersion::Llvm(_) => {
|
||||||
|
// FIXME: Handle libc++ version check.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// We need cmake, but only if we're actually building LLVM or sanitizers.
|
// We need cmake, but only if we're actually building LLVM or sanitizers.
|
||||||
let building_llvm = build
|
let building_llvm = build
|
||||||
.hosts
|
.hosts
|
||||||
|
26
src/tools/libcxx-version/main.cpp
Normal file
26
src/tools/libcxx-version/main.cpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Detecting the standard library version manually using a bunch of shell commands is very
|
||||||
|
// complicated and fragile across different platforms. This program provides the major version
|
||||||
|
// of the standard library on any target platform without requiring any messy work.
|
||||||
|
//
|
||||||
|
// It's nothing more than specifying the name of the standard library implementation (either libstdc++ or libc++)
|
||||||
|
// and its major version.
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
#ifdef _GLIBCXX_RELEASE
|
||||||
|
std::cout << "libstdc++ version: " << _GLIBCXX_RELEASE << std::endl;
|
||||||
|
#elif defined(_LIBCPP_VERSION)
|
||||||
|
// _LIBCPP_VERSION follows "XXYYZZ" format (e.g., 170001 for 17.0.1).
|
||||||
|
// ref: https://github.com/llvm/llvm-project/blob/f64732195c1030ee2627ff4e4142038e01df1d26/libcxx/include/__config#L51-L54
|
||||||
|
//
|
||||||
|
// Since we use the major version from _GLIBCXX_RELEASE, we need to extract only the first 2 characters of _LIBCPP_VERSION
|
||||||
|
// to provide the major version for consistency.
|
||||||
|
std::cout << "libc++ version: " << std::to_string(_LIBCPP_VERSION).substr(0, 2) << std::endl;
|
||||||
|
#else
|
||||||
|
std::cerr << "Coudln't recognize the standard library version." << std::endl;
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
@ -16,6 +16,7 @@ pub fn filter_dirs(path: &Path) -> bool {
|
|||||||
"library/stdarch",
|
"library/stdarch",
|
||||||
"src/tools/cargo",
|
"src/tools/cargo",
|
||||||
"src/tools/clippy",
|
"src/tools/clippy",
|
||||||
|
"src/tools/libcxx-version",
|
||||||
"src/tools/miri",
|
"src/tools/miri",
|
||||||
"src/tools/rust-analyzer",
|
"src/tools/rust-analyzer",
|
||||||
"src/tools/rustc-perf",
|
"src/tools/rustc-perf",
|
||||||
|
@ -330,6 +330,7 @@ trigger_files = [
|
|||||||
"src/tools/compiletest",
|
"src/tools/compiletest",
|
||||||
"src/tools/tidy",
|
"src/tools/tidy",
|
||||||
"src/tools/rustdoc-gui-test",
|
"src/tools/rustdoc-gui-test",
|
||||||
|
"src/tools/libcxx-version",
|
||||||
]
|
]
|
||||||
|
|
||||||
[autolabel."T-infra"]
|
[autolabel."T-infra"]
|
||||||
@ -1117,6 +1118,7 @@ project-exploit-mitigations = [
|
|||||||
"/src/tools/tidy" = ["bootstrap"]
|
"/src/tools/tidy" = ["bootstrap"]
|
||||||
"/src/tools/x" = ["bootstrap"]
|
"/src/tools/x" = ["bootstrap"]
|
||||||
"/src/tools/rustdoc-gui-test" = ["bootstrap", "@onur-ozkan"]
|
"/src/tools/rustdoc-gui-test" = ["bootstrap", "@onur-ozkan"]
|
||||||
|
"/src/tools/libcxx-version" = ["@onur-ozkan"]
|
||||||
|
|
||||||
# Enable tracking of PR review assignment
|
# Enable tracking of PR review assignment
|
||||||
# Documentation at: https://forge.rust-lang.org/triagebot/pr-assignment-tracking.html
|
# Documentation at: https://forge.rust-lang.org/triagebot/pr-assignment-tracking.html
|
||||||
|
Loading…
Reference in New Issue
Block a user