Change:
Spawned off of I'm not 100% sure what would be involved in such a check here, but it seems like a good thing to investigate, because the nature of the resulting bootstrap failures is super frustrating. (I'll admit, I don't know if the right thing would be to hard error out of all uses of download-ci-llvm for potentially-incompatible libstdc++, or only to hard error out for defaulting uses... but a warning seems warranted in any such cases.
I guess the problem here is that we're compiling the locally and linking that against the downloaded toolchain. A check like suggested here makes sense to me in the meantime, but I suppose long-term the "right" fix here is to get rid of any C++ code we need to separately compile by upstreaming C bindings into LLVM proper, and then we can just call those on the Rust side without any ABI issues. (FWIW, I was initially confused since we explicitly statically link in the stdcpp in the distributed I guess maybe we could also fix this by skipping linking to a local stdcpp while compiling the Rust wrapper code? Not sure if that works out.)
This is the particular line which leads to failure with download-ci-llvm when there is an ABI mismatch. In my experiment removing it resulted in linking errors on rustcdriver. I agree, this solves the problem completely without applying hacks (in my opinion, there is no simple or clean way of comparing ABI or libstd versions) on bootstrap. Maybe, for now, we should just print a warning when downloading ci llvm?
You mean always print a warning? I don't think that's a good idea, it's noisy and we generally expect that people are happy using download CI LLVM. I don't think a warning is helpful here if we can't scope it down to where it matters (in which case it can probably be an error).
Not always, only once while downloading it.
I think that falls in the same "not particularly helpful" case. Most users will miss the message, and even if they don't it's not clear how they should respond. I at least don't know how to check whether my machine has everything setup right. If we could check then we could limit the warning, in which case I'm broadly in favor of making it perhaps even a hard error.

Discussion:
use crate::core::config::TargetSelection; use crate::utils::channel::GitInfo; use crate::utils::exec::BootstrapCommand; <ins> use crate::utils::helpers::output; </ins> use crate::utils::helpers::{add_dylib_path, exe, t}; use crate::Compiler; use crate::Mode;

} } <ins> #[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."); } } } </ins> macro_rules! tool_extended { (($sel:ident, $builder:ident), $($name:ident,

use std::process::Command; #[cfg(not(feature = "bootstrap-self-test"))] <ins> use crate::builder::Builder; #[cfg(not(feature = "bootstrap-self-test"))] use crate::core::build_steps::tool; #[cfg(not(feature = "bootstrap-self-test"))] </ins> use std::collections::HashSet; use crate::builder::Kind;

// just a dummy comment so the list doesn't get onelined ]; <ins> /// 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; </ins> impl Finder { pub fn new() -> Self { Self { cache: HashMap::new(), path: env::var_os("PATH").unwrap_or_default() }

cmd_finder.must_have("git"); } <ins> // 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. } } } </ins> // We need cmake, but only if we're actually building LLVM or sanitizers. let building_llvm = build .hosts

<ins> // 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; } </ins>

"library/stdarch", "src/tools/cargo", "src/tools/clippy", <ins> "src/tools/libcxx-version", </ins> "src/tools/miri", "src/tools/rust-analyzer", "src/tools/rustc-perf",

"src/tools/compiletest", "src/tools/tidy", "src/tools/rustdoc-gui-test", <ins> "src/tools/libcxx-version", </ins> ] [autolabel."T-infra"]

"/src/tools/tidy" =                                      ["bootstrap"] "/src/tools/x" =                                         ["bootstrap"] "/src/tools/rustdoc-gui-test" =                          ["bootstrap", "@onur-ozkan"] <ins> "/src/tools/libcxx-version" =                            ["@onur-ozkan"] </ins> # Enable tracking of PR review assignment # Documentation at: https://forge.rust-lang.org/triagebot/pr-assignment-tracking.html