From 3a70a810d5d271f18489a7e5a8cbbd2e6262b1b7 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 23 May 2024 11:53:27 +0300 Subject: [PATCH 1/6] create libcxx-version tool for getting currently used libcxx version Signed-off-by: onur-ozkan --- src/tools/libcxx-version/main.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/tools/libcxx-version/main.cpp diff --git a/src/tools/libcxx-version/main.cpp b/src/tools/libcxx-version/main.cpp new file mode 100644 index 0000000000000..d12078abbb83e --- /dev/null +++ b/src/tools/libcxx-version/main.cpp @@ -0,0 +1,28 @@ +// 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. +// +// ignore-tidy-linelength + +#include + +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; +} From 73ff1d4b25b7f996c159335af0ca5091b9f4554c Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 23 May 2024 11:59:25 +0300 Subject: [PATCH 2/6] check host's libstdc++ version when using ci llvm Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/tool.rs | 54 ++++++++++++++++++++++ src/bootstrap/src/core/sanity.rs | 36 ++++++++++++++- 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 2db3f8f79364e..4f7efcb05d892 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -10,6 +10,7 @@ use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, use crate::core::config::TargetSelection; use crate::utils::channel::GitInfo; use crate::utils::exec::BootstrapCommand; +use crate::utils::helpers::output; use crate::utils::helpers::{add_dylib_path, exe, t}; use crate::Compiler; use crate::Mode; @@ -804,6 +805,59 @@ impl Step for LlvmBitcodeLinker { } } +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct LibcxxVersionTool { + pub target: TargetSelection, +} + +#[derive(Debug, Clone)] +pub enum LibcxxVersion { + Gnu(usize), + #[allow(dead_code)] + 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::().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 { (($sel:ident, $builder:ident), $($name:ident, diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index ead38ebc6d5e7..6595c599eb1c8 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -18,7 +18,8 @@ use std::process::Command; #[cfg(not(feature = "bootstrap-self-test"))] use std::collections::HashSet; -use crate::builder::Kind; +use crate::builder::{Builder, Kind}; +use crate::core::build_steps::tool; use crate::core::config::Target; use crate::utils::helpers::output; use crate::Build; @@ -38,6 +39,10 @@ const STAGE0_MISSING_TARGETS: &[&str] = &[ // 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). +const LIBSTDCXX_MIN_VERSION_THRESHOLD: usize = 8; + impl Finder { pub fn new() -> Self { Self { cache: HashMap::new(), path: env::var_os("PATH").unwrap_or_default() } @@ -102,6 +107,35 @@ pub fn check(build: &mut Build) { cmd_finder.must_have("git"); } + // Ensure that a compatible version of libstdc++ is available on the system when using `llvm.download-ci-llvm`. + 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(_) => { + eprintln!( + "\nYour system is using libc++, which is incompatible with the `llvm.download-ci-llvm` option." + ); + eprintln!("Disable `llvm.download-ci-llvm` or switch to libstdc++."); + crate::exit!(1); + } + } + } + // We need cmake, but only if we're actually building LLVM or sanitizers. let building_llvm = build .hosts From 1a07e58c0997e17cf62150ebc2bbf3af6ea4e807 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 23 May 2024 12:05:24 +0300 Subject: [PATCH 3/6] register libcxx-version in triagebot Signed-off-by: onur-ozkan --- triagebot.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 23e5c0a27f3aa..55f63ef2567c1 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -330,6 +330,7 @@ trigger_files = [ "src/tools/compiletest", "src/tools/tidy", "src/tools/rustdoc-gui-test", + "src/tools/libcxx-version", ] [autolabel."T-infra"] @@ -1117,6 +1118,7 @@ project-exploit-mitigations = [ "/src/tools/tidy" = ["bootstrap"] "/src/tools/x" = ["bootstrap"] "/src/tools/rustdoc-gui-test" = ["bootstrap", "@onur-ozkan"] +"/src/tools/libcxx-version" = ["@onur-ozkan"] # Enable tracking of PR review assignment # Documentation at: https://forge.rust-lang.org/triagebot/pr-assignment-tracking.html From a2407e84481fbbadd6d8d8e80726fa599533c465 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 23 May 2024 12:59:58 +0300 Subject: [PATCH 4/6] skip `src/tools/libcxx-version` from tidy Signed-off-by: onur-ozkan --- src/tools/libcxx-version/main.cpp | 2 -- src/tools/tidy/src/walk.rs | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tools/libcxx-version/main.cpp b/src/tools/libcxx-version/main.cpp index d12078abbb83e..79df7ef457c4f 100644 --- a/src/tools/libcxx-version/main.cpp +++ b/src/tools/libcxx-version/main.cpp @@ -4,8 +4,6 @@ // // It's nothing more than specifying the name of the standard library implementation (either libstdc++ or libc++) // and its major version. -// -// ignore-tidy-linelength #include diff --git a/src/tools/tidy/src/walk.rs b/src/tools/tidy/src/walk.rs index f68b7675c769f..63a0383416652 100644 --- a/src/tools/tidy/src/walk.rs +++ b/src/tools/tidy/src/walk.rs @@ -16,6 +16,7 @@ pub fn filter_dirs(path: &Path) -> bool { "library/stdarch", "src/tools/cargo", "src/tools/clippy", + "src/tools/libcxx-version", "src/tools/miri", "src/tools/rust-analyzer", "src/tools/rustc-perf", From 6bfdb040d95739e09b3067e5d09543030726aeb3 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Tue, 28 May 2024 08:18:35 +0300 Subject: [PATCH 5/6] add FIXME on libcxx check Signed-off-by: onur-ozkan --- src/bootstrap/src/core/sanity.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 6595c599eb1c8..ff0c36f114416 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -127,11 +127,7 @@ pub fn check(build: &mut Build) { } } tool::LibcxxVersion::Llvm(_) => { - eprintln!( - "\nYour system is using libc++, which is incompatible with the `llvm.download-ci-llvm` option." - ); - eprintln!("Disable `llvm.download-ci-llvm` or switch to libstdc++."); - crate::exit!(1); + // FIXME: Handle libc++ version check. } } } From dd9902118c0cbbcfc35c246673b381072ac5b3a8 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 6 Jun 2024 07:06:51 +0300 Subject: [PATCH 6/6] use `bootstrap-self-test` feature on libstd check Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/tool.rs | 2 +- src/bootstrap/src/core/sanity.rs | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 4f7efcb05d892..05b19c0a6e332 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -810,10 +810,10 @@ pub struct LibcxxVersionTool { pub target: TargetSelection, } +#[allow(dead_code)] #[derive(Debug, Clone)] pub enum LibcxxVersion { Gnu(usize), - #[allow(dead_code)] Llvm(usize), } diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index ff0c36f114416..e3556cb16b053 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -15,11 +15,14 @@ use std::fs; use std::path::PathBuf; 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"))] use std::collections::HashSet; -use crate::builder::{Builder, Kind}; -use crate::core::build_steps::tool; +use crate::builder::Kind; use crate::core::config::Target; use crate::utils::helpers::output; use crate::Build; @@ -41,6 +44,7 @@ const STAGE0_MISSING_TARGETS: &[&str] = &[ /// 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 { @@ -108,6 +112,7 @@ pub fn check(build: &mut Build) { } // 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 });