https://github.com/frederik-h updated https://github.com/llvm/llvm-project/pull/145056
>From 87c03ace23467a7d6cb7e466a02309b5b287a013 Mon Sep 17 00:00:00 2001 From: Frederik Harwath <fharw...@amd.com> Date: Wed, 19 Feb 2025 16:01:56 +0100 Subject: [PATCH 1/7] [Clang] Take libstdc++ into account during GCC detection The Generic_GCC::GCCInstallationDetector class always picks the latest available GCC installation directory. This often breaks C++ compilation on systems on which this directory does not contain a libstdc++ installation. On Ubuntu 22.04 systems, for instance, this can happen if the "gcc-12" package gets installed without the corresponding "g++-12" or "libstdc++-12" package in addition to the default "g++-11" installation. This patch changes the GCC installation selection, if compiling for C++ using libstdc++, to consider only GCC installation directories which also contain libstdc++. This is accomplished by enabling the GCCInstallationDetector to reuse the existing functionality for determinig the libstdc++ include directories which had to be decoupled from its existing uses. --- clang/include/clang/Driver/Options.td | 5 +- clang/include/clang/Driver/ToolChain.h | 27 ++- clang/lib/Driver/ToolChain.cpp | 25 ++- clang/lib/Driver/ToolChains/AVR.cpp | 3 +- clang/lib/Driver/ToolChains/CSKYToolChain.cpp | 2 +- clang/lib/Driver/ToolChains/Gnu.cpp | 191 ++++++++++++------ clang/lib/Driver/ToolChains/Gnu.h | 84 ++++++-- clang/lib/Driver/ToolChains/Haiku.cpp | 2 +- clang/lib/Driver/ToolChains/Hurd.cpp | 2 +- clang/lib/Driver/ToolChains/Linux.cpp | 2 +- clang/lib/Driver/ToolChains/MSP430.cpp | 2 +- .../lib/Driver/ToolChains/RISCVToolchain.cpp | 2 +- clang/lib/Driver/ToolChains/Solaris.cpp | 2 +- .../gcc-11.2.0/include/c++/11.2.0/.keep | 0 .../gcc-12/include/c++/12/.keep | 0 clang/test/Driver/gcc-toolchain.cpp | 5 - 16 files changed, 245 insertions(+), 109 deletions(-) create mode 100644 clang/test/Driver/Inputs/powerpc64le-linux-gnu-tree/gcc-11.2.0/include/c++/11.2.0/.keep create mode 100644 clang/test/Driver/Inputs/powerpc64le-linux-gnu-tree/gcc-12/include/c++/12/.keep diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 6eabd9f76a792..65a63a990d8e3 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -732,8 +732,9 @@ def gcc_install_dir_EQ : Joined<["--"], "gcc-install-dir=">, def gcc_toolchain : Joined<["--"], "gcc-toolchain=">, Flags<[NoXarchOption]>, Visibility<[ClangOption, FlangOption]>, HelpText< - "Specify a directory where Clang can find 'include' and 'lib{,32,64}/gcc{,-cross}/$triple/$version'. " - "Clang will use the GCC installation with the largest version">, + "Specify a directory to search for GCC installations (see --gcc-install-dir). " + "Picks the subdirectory with the largest GCC version, " + "skipping those without libstdc++ if the compile flags require it.">, HelpTextForVariants<[FlangOption], "Specify a directory where Flang can find 'lib{,32,64}/gcc{,-cross}/$triple/$version'. " "Flang will use the GCC installation with the largest version">; diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h index 7d1d8feebf35e..fe4e22caca5f5 100644 --- a/clang/include/clang/Driver/ToolChain.h +++ b/clang/include/clang/Driver/ToolChain.h @@ -226,25 +226,32 @@ class ToolChain { /// \name Utilities for implementing subclasses. ///@{ - static void addSystemInclude(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - const Twine &Path); static void addExternCSystemInclude(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, const Twine &Path); static void - addExternCSystemIncludeIfExists(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - const Twine &Path); - static void addSystemIncludes(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - ArrayRef<StringRef> Paths); - + addExternCSystemIncludeIfExists(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + const Twine &Path); static std::string concat(StringRef Path, const Twine &A, const Twine &B = "", const Twine &C = "", const Twine &D = ""); + + /// Return the CXXStdlibType which has been selected based on the + /// type of ToolChain driver args, triple etc. if it is in use, + /// i.e. we are compiling for C++ and the stdlib has not been + /// disabled. + std::optional<CXXStdlibType> getCXXStdlibTypeInUse(); + ///@} public: + static void addSystemInclude(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + const Twine &Path); + static void addSystemIncludes(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + ArrayRef<StringRef> Paths); + virtual ~ToolChain(); // Accessors diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index ebc982096595e..58f5034ccd19f 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -104,6 +104,15 @@ ToolChain::ToolChain(const Driver &D, const llvm::Triple &T, addIfExists(getFilePaths(), Path); } +std::optional<ToolChain::CXXStdlibType> ToolChain::getCXXStdlibTypeInUse() { + if (!(D.CCCIsCXX() && + !Args.hasArg(options::OPT_nostdinc, options::OPT_nostdincxx, + options::OPT_nostdlibinc))) + return std::nullopt; + + return GetCXXStdlibType(Args); +} + llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> ToolChain::executeToolChainProgram(StringRef Executable) const { llvm::SmallString<64> OutputFile; @@ -1272,14 +1281,6 @@ ToolChain::CXXStdlibType ToolChain::GetCXXStdlibType(const ArgList &Args) const{ return *cxxStdlibType; } -/// Utility function to add a system include directory to CC1 arguments. -/*static*/ void ToolChain::addSystemInclude(const ArgList &DriverArgs, - ArgStringList &CC1Args, - const Twine &Path) { - CC1Args.push_back("-internal-isystem"); - CC1Args.push_back(DriverArgs.MakeArgString(Path)); -} - /// Utility function to add a system include directory with extern "C" /// semantics to CC1 arguments. /// @@ -1302,6 +1303,14 @@ void ToolChain::addExternCSystemIncludeIfExists(const ArgList &DriverArgs, addExternCSystemInclude(DriverArgs, CC1Args, Path); } +/// Utility function to add a system include directory to CC1 arguments. +/*static*/ void ToolChain::addSystemInclude(const ArgList &DriverArgs, + ArgStringList &CC1Args, + const Twine &Path) { + CC1Args.push_back("-internal-isystem"); + CC1Args.push_back(DriverArgs.MakeArgString(Path)); +} + /// Utility function to add a list of system include directories to CC1. /*static*/ void ToolChain::addSystemIncludes(const ArgList &DriverArgs, ArgStringList &CC1Args, diff --git a/clang/lib/Driver/ToolChains/AVR.cpp b/clang/lib/Driver/ToolChains/AVR.cpp index 08e906ac9e806..ef5806c4231b1 100644 --- a/clang/lib/Driver/ToolChains/AVR.cpp +++ b/clang/lib/Driver/ToolChains/AVR.cpp @@ -366,7 +366,8 @@ const StringRef PossibleAVRLibcLocations[] = { AVRToolChain::AVRToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - GCCInstallation.init(Triple, Args); + + GCCInstallation.init(Triple, Args, getCXXStdlibTypeInUse()); if (getCPUName(D, Args, Triple).empty()) D.Diag(diag::warn_drv_avr_mcu_not_specified); diff --git a/clang/lib/Driver/ToolChains/CSKYToolChain.cpp b/clang/lib/Driver/ToolChains/CSKYToolChain.cpp index feb3bc922920f..c3f4dcf3ed342 100644 --- a/clang/lib/Driver/ToolChains/CSKYToolChain.cpp +++ b/clang/lib/Driver/ToolChains/CSKYToolChain.cpp @@ -35,7 +35,7 @@ static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs, CSKYToolChain::CSKYToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - GCCInstallation.init(Triple, Args); + GCCInstallation.init(Triple, Args, getCXXStdlibTypeInUse()); if (GCCInstallation.isValid()) { Multilibs = GCCInstallation.getMultilibs(); SelectedMultilibs.assign({GCCInstallation.getMultilib()}); diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index f56eeda3cb5f6..5fdd690d01316 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -34,6 +34,7 @@ #include "llvm/TargetParser/RISCVISAInfo.h" #include "llvm/TargetParser/TargetParser.h" #include <system_error> +#include <algorithm> using namespace clang::driver; using namespace clang::driver::toolchains; @@ -2171,7 +2172,10 @@ static llvm::StringRef getGCCToolchainDir(const ArgList &Args, /// necessary because the driver doesn't store the final version of the target /// triple. void Generic_GCC::GCCInstallationDetector::init( - const llvm::Triple &TargetTriple, const ArgList &Args) { + const llvm::Triple &TargetTriple, const ArgList &Args, + std::optional<ToolChain::CXXStdlibType> CxxLibType) { + RequireLibStdCxx = CxxLibType && CxxLibType == CXXStdlibType::CST_Libstdcxx; + llvm::Triple BiarchVariantTriple = TargetTriple.isArch32Bit() ? TargetTriple.get64BitArchVariant() : TargetTriple.get32BitArchVariant(); @@ -2213,10 +2217,11 @@ void Generic_GCC::GCCInstallationDetector::init( StringRef TripleText = llvm::sys::path::filename(llvm::sys::path::parent_path(InstallDir)); - Version = GCCVersion::Parse(VersionText); - GCCTriple.setTriple(TripleText); - GCCInstallPath = std::string(InstallDir); - GCCParentLibPath = GCCInstallPath + "/../../.."; + SelectedInstallation.Version = GCCVersion::Parse(VersionText); + SelectedInstallation.GCCTriple.setTriple(TripleText); + SelectedInstallation.GCCInstallPath = std::string(InstallDir); + SelectedInstallation.GCCParentLibPath = + SelectedInstallation.GCCInstallPath + "/../../.."; IsValid = true; } return; @@ -2276,7 +2281,7 @@ void Generic_GCC::GCCInstallationDetector::init( // Loop over the various components which exist and select the best GCC // installation available. GCC installs are ranked by version number. const GCCVersion VersionZero = GCCVersion::Parse("0.0.0"); - Version = VersionZero; + SelectedInstallation.Version = VersionZero; for (const std::string &Prefix : Prefixes) { auto &VFS = D.getVFS(); if (!VFS.exists(Prefix)) @@ -2304,7 +2309,7 @@ void Generic_GCC::GCCInstallationDetector::init( } // Skip other prefixes once a GCC installation is found. - if (Version > VersionZero) + if (SelectedInstallation.Version > VersionZero) break; } } @@ -2313,14 +2318,17 @@ void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const { for (const auto &InstallPath : CandidateGCCInstallPaths) OS << "Found candidate GCC installation: " << InstallPath << "\n"; - if (!GCCInstallPath.empty()) - OS << "Selected GCC installation: " << GCCInstallPath << "\n"; + if (!SelectedInstallation.GCCInstallPath.empty()) + OS << "Selected GCC installation: " << SelectedInstallation.GCCInstallPath + << "\n"; for (const auto &Multilib : Multilibs) OS << "Candidate multilib: " << Multilib << "\n"; - if (Multilibs.size() != 0 || !SelectedMultilib.isDefault()) - OS << "Selected multilib: " << SelectedMultilib << "\n"; + if (Multilibs.size() != 0 || + !SelectedInstallation.SelectedMultilib.isDefault()) + OS << "Selected multilib: " << SelectedInstallation.SelectedMultilib + << "\n"; } bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { @@ -2842,9 +2850,9 @@ bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs( } Multilibs = Detected.Multilibs; - SelectedMultilib = Detected.SelectedMultilibs.empty() - ? Multilib() - : Detected.SelectedMultilibs.back(); + SelectedInstallation.SelectedMultilib = + Detected.SelectedMultilibs.empty() ? Multilib() + : Detected.SelectedMultilibs.back(); BiarchSibling = Detected.BiarchSibling; return true; @@ -2883,6 +2891,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( if (!Suffix.Active) continue; + SmallVector<GCCInstallCandidate, 3> Installations; StringRef LibSuffix = Suffix.LibSuffix; std::error_code EC; for (llvm::vfs::directory_iterator @@ -2896,20 +2905,40 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( continue; // Saw this path before; no need to look at it again. if (CandidateVersion.isOlderThan(4, 1, 1)) continue; - if (CandidateVersion <= Version) + if (CandidateVersion <= SelectedInstallation.Version && IsValid) continue; if (!ScanGCCForMultilibs(TargetTriple, Args, LI->path(), NeedsBiarchSuffix)) continue; - Version = CandidateVersion; - GCCTriple.setTriple(CandidateTriple); + GCCInstallCandidate Installation; + Installation.Version = CandidateVersion; + Installation.GCCTriple.setTriple(CandidateTriple); // FIXME: We hack together the directory name here instead of // using LI to ensure stable path separators across Windows and // Linux. - GCCInstallPath = (LibDir + "/" + LibSuffix + "/" + VersionText).str(); - GCCParentLibPath = (GCCInstallPath + "/../" + Suffix.ReversePath).str(); + Installation.GCCInstallPath = + (LibDir + "/" + LibSuffix + "/" + VersionText).str(); + Installation.GCCParentLibPath = + (Installation.GCCInstallPath + "/../" + Suffix.ReversePath).str(); + Installation.SelectedMultilib = getMultilib(); + + Installations.push_back(Installation); + if (GCCInstallationHasRequiredLibs(Installation, Args)) { + SelectedInstallation = Installation; + IsValid = true; + } + } + + // If no GCC installation has all required libs, pick the latest + // one. Otherwise we would, for instance, break C++ compilation + // for code which does not use anything from the stdlib but + // which gets compiled without "-nostdlib". + if (!IsValid && !Installations.empty()) { + SelectedInstallation = *std::max_element( + Installations.begin(), Installations.end(), + [](auto x, auto y) { return x.Version < y.Version; }); IsValid = true; } } @@ -2990,10 +3019,12 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig( NeedsBiarchSuffix)) continue; - Version = GCCVersion::Parse(ActiveVersion.second); - GCCInstallPath = GentooPath; - GCCParentLibPath = GentooPath + std::string("/../../.."); - GCCTriple.setTriple(ActiveVersion.first); + SelectedInstallation.Version = + GCCVersion::Parse(ActiveVersion.second); + SelectedInstallation.GCCInstallPath = GentooPath; + SelectedInstallation.GCCParentLibPath = + GentooPath + std::string("/../../.."); + SelectedInstallation.GCCTriple.setTriple(ActiveVersion.first); IsValid = true; return true; } @@ -3196,8 +3227,9 @@ void Generic_GCC::AddMultilibIncludeArgs(const ArgList &DriverArgs, // gcc TOOL_INCLUDE_DIR. const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); std::string LibPath(GCCInstallation.getParentLibPath()); - addSystemInclude(DriverArgs, CC1Args, - Twine(LibPath) + "/../" + GCCTriple.str() + "/include"); + ToolChain::addSystemInclude(DriverArgs, CC1Args, + Twine(LibPath) + "/../" + GCCTriple.str() + + "/include"); const auto &Callback = Multilibs.includeDirsCallback(); if (Callback) { @@ -3284,12 +3316,14 @@ Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, return; } -bool Generic_GCC::addLibStdCXXIncludePaths(Twine IncludeDir, StringRef Triple, - Twine IncludeSuffix, - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - bool DetectDebian) const { - if (!getVFS().exists(IncludeDir)) +static bool addLibStdCXXIncludePaths(llvm::vfs::FileSystem &vfs, + Twine IncludeDir, StringRef Triple, + Twine IncludeSuffix, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + bool DetectDebian = false) { + + if (!vfs.exists(IncludeDir)) return false; // Debian native gcc uses g++-multiarch-incdir.diff which uses @@ -3301,39 +3335,48 @@ bool Generic_GCC::addLibStdCXXIncludePaths(Twine IncludeDir, StringRef Triple, std::string Path = (Include + "/" + Triple + Dir.substr(Include.size()) + IncludeSuffix) .str(); - if (DetectDebian && !getVFS().exists(Path)) + if (DetectDebian && !vfs.exists(Path)) return false; // GPLUSPLUS_INCLUDE_DIR - addSystemInclude(DriverArgs, CC1Args, IncludeDir); + ToolChain::addSystemInclude(DriverArgs, CC1Args, IncludeDir); // GPLUSPLUS_TOOL_INCLUDE_DIR. If Triple is not empty, add a target-dependent // include directory. if (DetectDebian) - addSystemInclude(DriverArgs, CC1Args, Path); + ToolChain::addSystemInclude(DriverArgs, CC1Args, Path); else if (!Triple.empty()) - addSystemInclude(DriverArgs, CC1Args, - IncludeDir + "/" + Triple + IncludeSuffix); + ToolChain::addSystemInclude(DriverArgs, CC1Args, + IncludeDir + "/" + Triple + IncludeSuffix); // GPLUSPLUS_BACKWARD_INCLUDE_DIR - addSystemInclude(DriverArgs, CC1Args, IncludeDir + "/backward"); + ToolChain::addSystemInclude(DriverArgs, CC1Args, IncludeDir + "/backward"); return true; } -bool Generic_GCC::addGCCLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, - StringRef DebianMultiarch) const { - assert(GCCInstallation.isValid()); +bool Generic_GCC::addLibStdCXXIncludePaths(Twine IncludeDir, StringRef Triple, + Twine IncludeSuffix, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + bool DetectDebian) const { + return ::addLibStdCXXIncludePaths(getVFS(), IncludeDir, Triple, IncludeSuffix, + DriverArgs, CC1Args, DetectDebian); +} + +bool Generic_GCC::GCCInstallCandidate::addGCCLibStdCxxIncludePaths( + llvm::vfs::FileSystem &vfs, const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, StringRef DebianMultiarch) const { // By default, look for the C++ headers in an include directory adjacent to // the lib directory of the GCC installation. Note that this is expect to be // equivalent to '/usr/include/c++/X.Y' in almost all cases. - StringRef LibDir = GCCInstallation.getParentLibPath(); - StringRef InstallDir = GCCInstallation.getInstallPath(); - StringRef TripleStr = GCCInstallation.getTriple().str(); - const Multilib &Multilib = GCCInstallation.getMultilib(); - const GCCVersion &Version = GCCInstallation.getVersion(); + StringRef LibDir = getParentLibPath(); + StringRef InstallDir = getInstallPath(); + StringRef TripleStr = getTriple().str(); + const Multilib &Multilib = getMultilib(); + const GCCVersion &Version = getVersion(); // Try /../$triple/include/c++/$version (gcc --print-multiarch is not empty). - if (addLibStdCXXIncludePaths( + if (::addLibStdCXXIncludePaths( + vfs, LibDir.str() + "/../" + TripleStr + "/include/c++/" + Version.Text, TripleStr, Multilib.includeSuffix(), DriverArgs, CC1Args)) return true; @@ -3341,22 +3384,24 @@ bool Generic_GCC::addGCCLibStdCxxIncludePaths( // Try /gcc/$triple/$version/include/c++/ (gcc --print-multiarch is not // empty). Like above but for GCC built with // --enable-version-specific-runtime-libs. - if (addLibStdCXXIncludePaths(LibDir.str() + "/gcc/" + TripleStr + "/" + - Version.Text + "/include/c++/", - TripleStr, Multilib.includeSuffix(), DriverArgs, - CC1Args)) + if (::addLibStdCXXIncludePaths(vfs, + LibDir.str() + "/gcc/" + TripleStr + "/" + + Version.Text + "/include/c++/", + TripleStr, Multilib.includeSuffix(), + DriverArgs, CC1Args)) return true; // Detect Debian g++-multiarch-incdir.diff. - if (addLibStdCXXIncludePaths(LibDir.str() + "/../include/c++/" + Version.Text, - DebianMultiarch, Multilib.includeSuffix(), - DriverArgs, CC1Args, /*Debian=*/true)) + if (::addLibStdCXXIncludePaths( + vfs, LibDir.str() + "/../include/c++/" + Version.Text, + DebianMultiarch, Multilib.includeSuffix(), DriverArgs, CC1Args, + /*Debian=*/true)) return true; // Try /../include/c++/$version (gcc --print-multiarch is empty). - if (addLibStdCXXIncludePaths(LibDir.str() + "/../include/c++/" + Version.Text, - TripleStr, Multilib.includeSuffix(), DriverArgs, - CC1Args)) + if (::addLibStdCXXIncludePaths( + vfs, LibDir.str() + "/../include/c++/" + Version.Text, TripleStr, + Multilib.includeSuffix(), DriverArgs, CC1Args)) return true; // Otherwise, fall back on a bunch of options which don't use multiarch @@ -3371,13 +3416,41 @@ bool Generic_GCC::addGCCLibStdCxxIncludePaths( }; for (const auto &IncludePath : LibStdCXXIncludePathCandidates) { - if (addLibStdCXXIncludePaths(IncludePath, TripleStr, - Multilib.includeSuffix(), DriverArgs, CC1Args)) + if (::addLibStdCXXIncludePaths(vfs, IncludePath, TripleStr, + Multilib.includeSuffix(), DriverArgs, + CC1Args)) return true; } return false; } +bool Generic_GCC::GCCInstallationDetector::GCCInstallationHasRequiredLibs( + const GCCInstallCandidate &GCCInstallation, + const llvm::opt::ArgList &DriverArgs) const { + + if (!RequireLibStdCxx) + return true; + + // The following function is meant to add the libstdc++ include + // paths to the CC1 argument list. Here we just want to know if this + // would succeed and hence we do not pass it the real arguments. + llvm::opt::ArgStringList dummyCC1Args; + StringRef TripleStr = GCCInstallation.getTriple().str(); + StringRef DebianMultiarch = + getTriple().getArch() == llvm::Triple::x86 ? "i386-linux-gnu" : TripleStr; + + bool found = GCCInstallation.addGCCLibStdCxxIncludePaths( + D.getVFS(), DriverArgs, dummyCC1Args, DebianMultiarch); + return found; +} + +bool Generic_GCC::addGCCLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, + StringRef DebianMultiarch) const { + return GCCInstallation.getSelectedInstallation().addGCCLibStdCxxIncludePaths( + getVFS(), DriverArgs, CC1Args, DebianMultiarch); +} + void Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { diff --git a/clang/lib/Driver/ToolChains/Gnu.h b/clang/lib/Driver/ToolChains/Gnu.h index 3b8df71bbf9d3..faee6bd9758d6 100644 --- a/clang/lib/Driver/ToolChains/Gnu.h +++ b/clang/lib/Driver/ToolChains/Gnu.h @@ -184,6 +184,38 @@ class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain { bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); } }; + struct GCCInstallCandidate { + std::string GCCInstallPath; + std::string GCCParentLibPath; + + llvm::Triple GCCTriple; + + /// The primary multilib appropriate for the given flags. + Multilib SelectedMultilib; + + GCCVersion Version; + + /// Get the GCC triple for the detected install. + const llvm::Triple &getTriple() const { return GCCTriple; } + + /// Get the detected GCC installation path. + StringRef getInstallPath() const { return GCCInstallPath; } + + /// Get the detected GCC parent lib path. + StringRef getParentLibPath() const { return GCCParentLibPath; } + + /// Get the detected Multilib + const Multilib &getMultilib() const { return SelectedMultilib; } + + /// Get the detected GCC version string. + const GCCVersion &getVersion() const { return Version; } + + bool addGCCLibStdCxxIncludePaths(llvm::vfs::FileSystem &vfs, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + StringRef DebianMultiarch) const; + }; + /// This is a class to find a viable GCC installation for Clang to /// use. /// @@ -192,21 +224,15 @@ class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain { /// Driver, and has logic for fuzzing that where appropriate. class GCCInstallationDetector { bool IsValid; - llvm::Triple GCCTriple; + const Driver &D; - // FIXME: These might be better as path objects. - std::string GCCInstallPath; - std::string GCCParentLibPath; + GCCInstallCandidate SelectedInstallation; - /// The primary multilib appropriate for the given flags. - Multilib SelectedMultilib; /// On Biarch systems, this corresponds to the default multilib when /// targeting the non-default multilib. Otherwise, it is empty. std::optional<Multilib> BiarchSibling; - GCCVersion Version; - // We retain the list of install paths that were considered and rejected in // order to print out detailed information in verbose mode. std::set<std::string> CandidateGCCInstallPaths; @@ -218,23 +244,40 @@ class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain { const std::string GentooConfigDir = "/etc/env.d/gcc"; public: - explicit GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {} - void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args); + bool RequireLibStdCxx; + + explicit GCCInstallationDetector(const Driver &D) + : IsValid(false), D(D), RequireLibStdCxx(false) {} + + void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args, + std::optional<ToolChain::CXXStdlibType> CxxLibType); /// Check whether we detected a valid GCC install. bool isValid() const { return IsValid; } + const GCCInstallCandidate &getSelectedInstallation() const { + return SelectedInstallation; + } + /// Get the GCC triple for the detected install. - const llvm::Triple &getTriple() const { return GCCTriple; } + const llvm::Triple &getTriple() const { + return SelectedInstallation.GCCTriple; + } /// Get the detected GCC installation path. - StringRef getInstallPath() const { return GCCInstallPath; } + StringRef getInstallPath() const { + return SelectedInstallation.GCCInstallPath; + } /// Get the detected GCC parent lib path. - StringRef getParentLibPath() const { return GCCParentLibPath; } + StringRef getParentLibPath() const { + return SelectedInstallation.GCCParentLibPath; + } /// Get the detected Multilib - const Multilib &getMultilib() const { return SelectedMultilib; } + const Multilib &getMultilib() const { + return SelectedInstallation.SelectedMultilib; + } /// Get the whole MultilibSet const MultilibSet &getMultilibs() const { return Multilibs; } @@ -244,7 +287,9 @@ class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain { bool getBiarchSibling(Multilib &M) const; /// Get the detected GCC version string. - const GCCVersion &getVersion() const { return Version; } + const GCCVersion &getVersion() const { + return SelectedInstallation.Version; + } /// Print information about the detected GCC installation. void print(raw_ostream &OS) const; @@ -262,9 +307,14 @@ class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain { SmallVectorImpl<std::string> &Prefixes, StringRef SysRoot); + /// Checks if the \p GCCInstallation has the libs required + /// by the \p DriverArgs. + bool + GCCInstallationHasRequiredLibs(const GCCInstallCandidate &GCCInstallation, + const llvm::opt::ArgList &DriverArgs) const; + bool ScanGCCForMultilibs(const llvm::Triple &TargetTriple, - const llvm::opt::ArgList &Args, - StringRef Path, + const llvm::opt::ArgList &Args, StringRef Path, bool NeedsBiarchSuffix = false); void ScanLibDirForGCCTriple(const llvm::Triple &TargetArch, diff --git a/clang/lib/Driver/ToolChains/Haiku.cpp b/clang/lib/Driver/ToolChains/Haiku.cpp index af74f43e48364..6c55a2f74724f 100644 --- a/clang/lib/Driver/ToolChains/Haiku.cpp +++ b/clang/lib/Driver/ToolChains/Haiku.cpp @@ -166,7 +166,7 @@ void haiku::Linker::ConstructJob(Compilation &C, const JobAction &JA, Haiku::Haiku(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - GCCInstallation.init(Triple, Args); + GCCInstallation.init(Triple, Args, getCXXStdlibTypeInUse()); getFilePaths().push_back(concat(getDriver().SysRoot, "/boot/system/lib")); getFilePaths().push_back(concat(getDriver().SysRoot, "/boot/system/develop/lib")); diff --git a/clang/lib/Driver/ToolChains/Hurd.cpp b/clang/lib/Driver/ToolChains/Hurd.cpp index 0bc114b90ffc0..efddd4b429869 100644 --- a/clang/lib/Driver/ToolChains/Hurd.cpp +++ b/clang/lib/Driver/ToolChains/Hurd.cpp @@ -71,7 +71,7 @@ static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) { Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - GCCInstallation.init(Triple, Args); + GCCInstallation.init(Triple, Args, getCXXStdlibTypeInUse()); Multilibs = GCCInstallation.getMultilibs(); SelectedMultilibs.assign({GCCInstallation.getMultilib()}); std::string SysRoot = computeSysRoot(); diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index 0767fe6c58796..86bf610026226 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -212,7 +212,7 @@ static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) { Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - GCCInstallation.init(Triple, Args); + GCCInstallation.init(Triple, Args, getCXXStdlibTypeInUse()); Multilibs = GCCInstallation.getMultilibs(); SelectedMultilibs.assign({GCCInstallation.getMultilib()}); llvm::Triple::ArchType Arch = Triple.getArch(); diff --git a/clang/lib/Driver/ToolChains/MSP430.cpp b/clang/lib/Driver/ToolChains/MSP430.cpp index 07e875c64960e..ed515f0f1373c 100644 --- a/clang/lib/Driver/ToolChains/MSP430.cpp +++ b/clang/lib/Driver/ToolChains/MSP430.cpp @@ -112,7 +112,7 @@ MSP430ToolChain::MSP430ToolChain(const Driver &D, const llvm::Triple &Triple, StringRef MultilibSuf = ""; - GCCInstallation.init(Triple, Args); + GCCInstallation.init(Triple, Args, getCXXStdlibTypeInUse()); if (GCCInstallation.isValid()) { MultilibSuf = GCCInstallation.getMultilib().gccSuffix(); diff --git a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp index 624099d21ae12..e5d1e550f5453 100644 --- a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp +++ b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp @@ -50,7 +50,7 @@ bool RISCVToolChain::hasGCCToolchain(const Driver &D, RISCVToolChain::RISCVToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - GCCInstallation.init(Triple, Args); + GCCInstallation.init(Triple, Args, getCXXStdlibTypeInUse()); if (GCCInstallation.isValid()) { Multilibs = GCCInstallation.getMultilibs(); SelectedMultilibs.assign({GCCInstallation.getMultilib()}); diff --git a/clang/lib/Driver/ToolChains/Solaris.cpp b/clang/lib/Driver/ToolChains/Solaris.cpp index fd3232b7c1b06..1153c2ac319cb 100644 --- a/clang/lib/Driver/ToolChains/Solaris.cpp +++ b/clang/lib/Driver/ToolChains/Solaris.cpp @@ -310,7 +310,7 @@ Solaris::Solaris(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - GCCInstallation.init(Triple, Args); + GCCInstallation.init(Triple, Args, getCXXStdlibTypeInUse()); StringRef LibSuffix = getSolarisLibSuffix(Triple); path_list &Paths = getFilePaths(); diff --git a/clang/test/Driver/Inputs/powerpc64le-linux-gnu-tree/gcc-11.2.0/include/c++/11.2.0/.keep b/clang/test/Driver/Inputs/powerpc64le-linux-gnu-tree/gcc-11.2.0/include/c++/11.2.0/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/powerpc64le-linux-gnu-tree/gcc-12/include/c++/12/.keep b/clang/test/Driver/Inputs/powerpc64le-linux-gnu-tree/gcc-12/include/c++/12/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/gcc-toolchain.cpp b/clang/test/Driver/gcc-toolchain.cpp index 6d4ad417cfec6..a14e8d00af1ef 100644 --- a/clang/test/Driver/gcc-toolchain.cpp +++ b/clang/test/Driver/gcc-toolchain.cpp @@ -6,11 +6,6 @@ // RUN: --gcc-toolchain=%S/Inputs/ubuntu_14.04_multiarch_tree/usr -stdlib=libstdc++ --rtlib=libgcc --unwindlib=libgcc -no-pie 2>&1 | \ // RUN: FileCheck %s // -// Additionally check that the legacy spelling of the flag works. -// RUN: %clangxx %s -### --target=x86_64-linux-gnu --sysroot= \ -// RUN: --gcc-toolchain=%S/Inputs/ubuntu_14.04_multiarch_tree/usr -stdlib=libstdc++ --rtlib=libgcc --unwindlib=libgcc -no-pie 2>&1 | \ -// RUN: FileCheck %s -// // Test for header search toolchain detection. // CHECK: "-internal-isystem" // CHECK: "[[TOOLCHAIN:[^"]+]]/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../../include/c++/4.8" >From b9ae7143b5bf2d325c38219d684c4afc3ec1104a Mon Sep 17 00:00:00 2001 From: Frederik Harwath <fharw...@amd.com> Date: Tue, 1 Jul 2025 14:22:25 +0200 Subject: [PATCH 2/7] Adjustments suggested in Discourse discussion & Cleanup * Always prefer GCC installations with libstdc++ Previously, GCC installation directories containing libstdc++ include directories were only preferred if the compiler flags indicated that they might be required. This might lead to different GCC installations directories being used for C and C++ compilation. * Revert to old GCC version detection and inform about future behavior Instead of actually preferring GCC installations containing libstdc++, stick to the old logic. Inform about the directory that will be chosen in the future. * Add test for new warnings * Make DebianMultiarch available to GCCInstallationHasLibStdcxxIncludePaths The correct DebianMultiarch to use in the invocation of GCCInstallation.addGCCLibStdCxxIncludePaths in GCCInstallationHasLibStdcxxIncludePaths depends on the subclass of Generic_GCC from which the latter function has been invoked. This information is only available in a different place. Add a function for converting the triple component of the GCC installation directory to the GCCInstallationDetector. This function is then adjusted from the different Generic_GCC subclasses. * Revert some unnecessary changes and fix minor bugs. --- .../clang/Basic/DiagnosticDriverKinds.td | 7 +- clang/include/clang/Driver/Options.td | 5 +- clang/include/clang/Driver/ToolChain.h | 6 - clang/lib/Driver/ToolChain.cpp | 9 -- clang/lib/Driver/ToolChains/AVR.cpp | 2 +- clang/lib/Driver/ToolChains/CSKYToolChain.cpp | 2 +- clang/lib/Driver/ToolChains/Gnu.cpp | 105 +++++++++++------- clang/lib/Driver/ToolChains/Gnu.h | 40 +++++-- clang/lib/Driver/ToolChains/Haiku.cpp | 2 +- clang/lib/Driver/ToolChains/Hurd.cpp | 16 +-- clang/lib/Driver/ToolChains/Linux.cpp | 20 ++-- clang/lib/Driver/ToolChains/MSP430.cpp | 2 +- .../lib/Driver/ToolChains/RISCVToolchain.cpp | 2 +- clang/lib/Driver/ToolChains/Solaris.cpp | 2 +- .../lib/gcc/x86_64-linux-gnu/10/crtbegin.o} | 0 .../usr/lib/gcc/x86_64-linux-gnu/10/crtend.o} | 0 .../lib/gcc/x86_64-linux-gnu/11/crtbegin.o | 0 .../usr/lib/gcc/x86_64-linux-gnu/11/crtend.o | 0 .../lib/gcc/x86_64-linux-gnu/11/include/.keep | 0 .../lib/gcc/x86_64-linux-gnu/12/crtbegin.o | 0 .../usr/lib/gcc/x86_64-linux-gnu/12/crtend.o | 0 .../lib/gcc/x86_64-linux-gnu/12/include/.keep | 0 .../lib/gcc/x86_64-linux-gnu/10/crtbegin.o | 0 .../usr/lib/gcc/x86_64-linux-gnu/10/crtend.o | 0 .../lib/gcc/x86_64-linux-gnu/10/include/.keep | 0 .../lib/gcc/x86_64-linux-gnu/11/crtbegin.o | 0 .../usr/lib/gcc/x86_64-linux-gnu/11/crtend.o | 0 .../lib/gcc/x86_64-linux-gnu/12/crtbegin.o | 0 .../usr/lib/gcc/x86_64-linux-gnu/12/crtend.o | 0 .../lib/gcc/x86_64-linux-gnu/12/include/.keep | 0 .../lib/gcc/x86_64-linux-gnu/10/crtbegin.o | 0 .../usr/lib/gcc/x86_64-linux-gnu/10/crtend.o | 0 .../lib/gcc/x86_64-linux-gnu/10/include/.keep | 0 .../lib/gcc/x86_64-linux-gnu/11/crtbegin.o | 0 .../usr/lib/gcc/x86_64-linux-gnu/11/crtend.o | 0 .../lib/gcc/x86_64-linux-gnu/12/crtbegin.o | 0 .../usr/lib/gcc/x86_64-linux-gnu/12/crtend.o | 0 clang/test/Driver/gcc-toolchain-libstdcxx.cpp | 28 +++++ 38 files changed, 152 insertions(+), 96 deletions(-) rename clang/test/Driver/Inputs/{powerpc64le-linux-gnu-tree/gcc-11.2.0/include/c++/11.2.0/.keep => gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/10/crtbegin.o} (100%) rename clang/test/Driver/Inputs/{powerpc64le-linux-gnu-tree/gcc-12/include/c++/12/.keep => gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/10/crtend.o} (100%) create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/11/crtbegin.o create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/11/crtend.o create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/11/include/.keep create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/12/crtbegin.o create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/12/crtend.o create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/12/include/.keep create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/10/crtbegin.o create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/10/crtend.o create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/10/include/.keep create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/11/crtbegin.o create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/11/crtend.o create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/12/crtbegin.o create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/12/crtend.o create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/12/include/.keep create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/10/crtbegin.o create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/10/crtend.o create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/10/include/.keep create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/11/crtbegin.o create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/11/crtend.o create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/12/crtbegin.o create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/12/crtend.o create mode 100644 clang/test/Driver/gcc-toolchain-libstdcxx.cpp diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 8d599c96eb4fb..fc7f8092ff149 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -841,4 +841,9 @@ def warn_missing_include_dirs : Warning< def err_drv_malformed_warning_suppression_mapping : Error< "failed to process suppression mapping file '%0': %1">; -} + +def warn_drv_gcc_install_dir_libstdcxx : Warning< + "future releases of the clang compiler will prefer GCC installations " + "containing libstdc++ include directories; '%0' would be chosen over '%1'">, + InGroup<DiagGroup<"gcc-install-dir-libstdcxx">>; +} \ No newline at end of file diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 65a63a990d8e3..6eabd9f76a792 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -732,9 +732,8 @@ def gcc_install_dir_EQ : Joined<["--"], "gcc-install-dir=">, def gcc_toolchain : Joined<["--"], "gcc-toolchain=">, Flags<[NoXarchOption]>, Visibility<[ClangOption, FlangOption]>, HelpText< - "Specify a directory to search for GCC installations (see --gcc-install-dir). " - "Picks the subdirectory with the largest GCC version, " - "skipping those without libstdc++ if the compile flags require it.">, + "Specify a directory where Clang can find 'include' and 'lib{,32,64}/gcc{,-cross}/$triple/$version'. " + "Clang will use the GCC installation with the largest version">, HelpTextForVariants<[FlangOption], "Specify a directory where Flang can find 'lib{,32,64}/gcc{,-cross}/$triple/$version'. " "Flang will use the GCC installation with the largest version">; diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h index fe4e22caca5f5..42e525c9d1289 100644 --- a/clang/include/clang/Driver/ToolChain.h +++ b/clang/include/clang/Driver/ToolChain.h @@ -236,12 +236,6 @@ class ToolChain { static std::string concat(StringRef Path, const Twine &A, const Twine &B = "", const Twine &C = "", const Twine &D = ""); - /// Return the CXXStdlibType which has been selected based on the - /// type of ToolChain driver args, triple etc. if it is in use, - /// i.e. we are compiling for C++ and the stdlib has not been - /// disabled. - std::optional<CXXStdlibType> getCXXStdlibTypeInUse(); - ///@} public: diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 58f5034ccd19f..3dcf7087a175d 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -104,15 +104,6 @@ ToolChain::ToolChain(const Driver &D, const llvm::Triple &T, addIfExists(getFilePaths(), Path); } -std::optional<ToolChain::CXXStdlibType> ToolChain::getCXXStdlibTypeInUse() { - if (!(D.CCCIsCXX() && - !Args.hasArg(options::OPT_nostdinc, options::OPT_nostdincxx, - options::OPT_nostdlibinc))) - return std::nullopt; - - return GetCXXStdlibType(Args); -} - llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>> ToolChain::executeToolChainProgram(StringRef Executable) const { llvm::SmallString<64> OutputFile; diff --git a/clang/lib/Driver/ToolChains/AVR.cpp b/clang/lib/Driver/ToolChains/AVR.cpp index ef5806c4231b1..13c42b4b94916 100644 --- a/clang/lib/Driver/ToolChains/AVR.cpp +++ b/clang/lib/Driver/ToolChains/AVR.cpp @@ -367,7 +367,7 @@ AVRToolChain::AVRToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - GCCInstallation.init(Triple, Args, getCXXStdlibTypeInUse()); + GCCInstallation.init(Triple, Args); if (getCPUName(D, Args, Triple).empty()) D.Diag(diag::warn_drv_avr_mcu_not_specified); diff --git a/clang/lib/Driver/ToolChains/CSKYToolChain.cpp b/clang/lib/Driver/ToolChains/CSKYToolChain.cpp index c3f4dcf3ed342..feb3bc922920f 100644 --- a/clang/lib/Driver/ToolChains/CSKYToolChain.cpp +++ b/clang/lib/Driver/ToolChains/CSKYToolChain.cpp @@ -35,7 +35,7 @@ static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs, CSKYToolChain::CSKYToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - GCCInstallation.init(Triple, Args, getCXXStdlibTypeInUse()); + GCCInstallation.init(Triple, Args); if (GCCInstallation.isValid()) { Multilibs = GCCInstallation.getMultilibs(); SelectedMultilibs.assign({GCCInstallation.getMultilib()}); diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index 5fdd690d01316..5032044a40558 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -34,7 +34,6 @@ #include "llvm/TargetParser/RISCVISAInfo.h" #include "llvm/TargetParser/TargetParser.h" #include <system_error> -#include <algorithm> using namespace clang::driver; using namespace clang::driver::toolchains; @@ -2172,10 +2171,7 @@ static llvm::StringRef getGCCToolchainDir(const ArgList &Args, /// necessary because the driver doesn't store the final version of the target /// triple. void Generic_GCC::GCCInstallationDetector::init( - const llvm::Triple &TargetTriple, const ArgList &Args, - std::optional<ToolChain::CXXStdlibType> CxxLibType) { - RequireLibStdCxx = CxxLibType && CxxLibType == CXXStdlibType::CST_Libstdcxx; - + const llvm::Triple &TargetTriple, const ArgList &Args) { llvm::Triple BiarchVariantTriple = TargetTriple.isArch32Bit() ? TargetTriple.get64BitArchVariant() : TargetTriple.get32BitArchVariant(); @@ -2858,6 +2854,41 @@ bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs( return true; } +bool Generic_GCC::GCCInstallationDetector::SelectGCCInstallationDirectory( + const SmallVector<Generic_GCC::GCCInstallCandidate, 3> &Installations, + const ArgList &Args, + Generic_GCC::GCCInstallCandidate &SelectedInstallation) const { + if (Installations.empty()) + return false; + + SelectedInstallation = + *max_element(Installations, [](const auto &Max, const auto &I) { + return I.Version > Max.Version; + }); + + // FIXME Start selecting installation with libstdc++ in clang 22, + // using the current way of selecting the installation as a fallback only. + // For now, warn if install with libstdc++ differs SelectedInstallation. + const GCCInstallCandidate *InstallWithIncludes = nullptr; + for (const auto &I : Installations) { + if ((!InstallWithIncludes || I.Version > InstallWithIncludes->Version) && + GCCInstallationHasLibStdcxxIncludePaths(I, Args)) + InstallWithIncludes = &I; + } + + if (InstallWithIncludes && SelectedInstallation.GCCInstallPath != + InstallWithIncludes->GCCInstallPath) + D.Diag(diag::warn_drv_gcc_install_dir_libstdcxx) + << InstallWithIncludes->GCCInstallPath + << SelectedInstallation.GCCInstallPath; + + // TODO Warn if SelectedInstallation does not contain libstdc++ includes + // although compiler flags indicate that it is required (C++ compilation, + // libstdc++ not explicitly disabled). + + return true; +} + void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( const llvm::Triple &TargetTriple, const ArgList &Args, const std::string &LibDir, StringRef CandidateTriple, @@ -2887,11 +2918,11 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( TargetTriple.getVendor() == llvm::Triple::Freescale || TargetTriple.getVendor() == llvm::Triple::OpenEmbedded}}; + SmallVector<GCCInstallCandidate, 3> Installations; for (auto &Suffix : Suffixes) { if (!Suffix.Active) continue; - SmallVector<GCCInstallCandidate, 3> Installations; StringRef LibSuffix = Suffix.LibSuffix; std::error_code EC; for (llvm::vfs::directory_iterator @@ -2925,23 +2956,11 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( Installation.SelectedMultilib = getMultilib(); Installations.push_back(Installation); - if (GCCInstallationHasRequiredLibs(Installation, Args)) { - SelectedInstallation = Installation; - IsValid = true; - } - } - - // If no GCC installation has all required libs, pick the latest - // one. Otherwise we would, for instance, break C++ compilation - // for code which does not use anything from the stdlib but - // which gets compiled without "-nostdlib". - if (!IsValid && !Installations.empty()) { - SelectedInstallation = *std::max_element( - Installations.begin(), Installations.end(), - [](auto x, auto y) { return x.Version < y.Version; }); - IsValid = true; } } + + IsValid |= + SelectGCCInstallationDirectory(Installations, Args, SelectedInstallation); } bool Generic_GCC::GCCInstallationDetector::ScanGentooConfigs( @@ -3424,29 +3443,30 @@ bool Generic_GCC::GCCInstallCandidate::addGCCLibStdCxxIncludePaths( return false; } -bool Generic_GCC::GCCInstallationDetector::GCCInstallationHasRequiredLibs( - const GCCInstallCandidate &GCCInstallation, - const llvm::opt::ArgList &DriverArgs) const { - - if (!RequireLibStdCxx) - return true; - - // The following function is meant to add the libstdc++ include - // paths to the CC1 argument list. Here we just want to know if this - // would succeed and hence we do not pass it the real arguments. - llvm::opt::ArgStringList dummyCC1Args; - StringRef TripleStr = GCCInstallation.getTriple().str(); +bool Generic_GCC::GCCInstallationDetector:: + GCCInstallationHasLibStdcxxIncludePaths( + const GCCInstallCandidate &GCCInstallation, + const llvm::opt::ArgList &DriverArgs) const { StringRef DebianMultiarch = - getTriple().getArch() == llvm::Triple::x86 ? "i386-linux-gnu" : TripleStr; + TripleToDebianMultiarch(GCCInstallation.getTriple()); - bool found = GCCInstallation.addGCCLibStdCxxIncludePaths( + // The following function checks for libstdc++ include paths and + // adds them to the provided argument list. Here we just need the + // check. + llvm::opt::ArgStringList dummyCC1Args; + return GCCInstallation.addGCCLibStdCxxIncludePaths( D.getVFS(), DriverArgs, dummyCC1Args, DebianMultiarch); - return found; } bool Generic_GCC::addGCCLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, - StringRef DebianMultiarch) const { + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + assert(GCCInstallation.isValid()); + + // Detect Debian g++-multiarch-incdir.diff. + StringRef DebianMultiarch = + GCCInstallation.TripleToDebianMultiarch(GCCInstallation.getTriple()); + return GCCInstallation.getSelectedInstallation().addGCCLibStdCxxIncludePaths( getVFS(), DriverArgs, CC1Args, DebianMultiarch); } @@ -3454,10 +3474,11 @@ bool Generic_GCC::addGCCLibStdCxxIncludePaths( void Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { - if (GCCInstallation.isValid()) { - addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args, - GCCInstallation.getTriple().str()); - } + if (!GCCInstallation.isValid()) + return; + + GCCInstallation.getSelectedInstallation().addGCCLibStdCxxIncludePaths( + getVFS(), DriverArgs, CC1Args, GCCInstallation.getTriple().str()); } llvm::opt::DerivedArgList * diff --git a/clang/lib/Driver/ToolChains/Gnu.h b/clang/lib/Driver/ToolChains/Gnu.h index faee6bd9758d6..099436abf57c1 100644 --- a/clang/lib/Driver/ToolChains/Gnu.h +++ b/clang/lib/Driver/ToolChains/Gnu.h @@ -244,13 +244,23 @@ class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain { const std::string GentooConfigDir = "/etc/env.d/gcc"; public: - bool RequireLibStdCxx; + /// Function for converting a Triple to a Debian multiarch. The + /// toolchains use this to adjust the target specific component of + /// include paths for Debian. + std::function<StringRef(const llvm::Triple &)> TripleToDebianMultiarch = + [](const llvm::Triple &T) { + StringRef S = T.str(); + return S; + }; - explicit GCCInstallationDetector(const Driver &D) - : IsValid(false), D(D), RequireLibStdCxx(false) {} + explicit GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {} - void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args, - std::optional<ToolChain::CXXStdlibType> CxxLibType); + void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args); + + // TODO Replace isValid by changing SelectedInstallation into + // std::optional<SelectedInstallation> + // and move all accessors for fields of GCCInstallCandidate into + // that struct. /// Check whether we detected a valid GCC install. bool isValid() const { return IsValid; } @@ -307,11 +317,18 @@ class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain { SmallVectorImpl<std::string> &Prefixes, StringRef SysRoot); - /// Checks if the \p GCCInstallation has the libs required - /// by the \p DriverArgs. - bool - GCCInstallationHasRequiredLibs(const GCCInstallCandidate &GCCInstallation, - const llvm::opt::ArgList &DriverArgs) const; + /// Checks if the \p GCCInstallation has libstdc++ include + /// directories. + bool GCCInstallationHasLibStdcxxIncludePaths( + const GCCInstallCandidate &GCCInstallation, + const llvm::opt::ArgList &DriverArgs) const; + + /// Select a GCC installation directory from \p Installations. + /// Set \p SelectedInstallation + bool SelectGCCInstallationDirectory( + const SmallVector<GCCInstallCandidate, 3> &Installations, + const llvm::opt::ArgList &Args, + GCCInstallCandidate &SelectedInstallation) const; bool ScanGCCForMultilibs(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args, StringRef Path, @@ -399,8 +416,7 @@ class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain { llvm::opt::ArgStringList &CC1Args) const; bool addGCCLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - StringRef DebianMultiarch) const; + llvm::opt::ArgStringList &CC) const; bool addLibStdCXXIncludePaths(Twine IncludeDir, StringRef Triple, Twine IncludeSuffix, diff --git a/clang/lib/Driver/ToolChains/Haiku.cpp b/clang/lib/Driver/ToolChains/Haiku.cpp index 6c55a2f74724f..af74f43e48364 100644 --- a/clang/lib/Driver/ToolChains/Haiku.cpp +++ b/clang/lib/Driver/ToolChains/Haiku.cpp @@ -166,7 +166,7 @@ void haiku::Linker::ConstructJob(Compilation &C, const JobAction &JA, Haiku::Haiku(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - GCCInstallation.init(Triple, Args, getCXXStdlibTypeInUse()); + GCCInstallation.init(Triple, Args); getFilePaths().push_back(concat(getDriver().SysRoot, "/boot/system/lib")); getFilePaths().push_back(concat(getDriver().SysRoot, "/boot/system/develop/lib")); diff --git a/clang/lib/Driver/ToolChains/Hurd.cpp b/clang/lib/Driver/ToolChains/Hurd.cpp index efddd4b429869..e0f3f239776aa 100644 --- a/clang/lib/Driver/ToolChains/Hurd.cpp +++ b/clang/lib/Driver/ToolChains/Hurd.cpp @@ -71,7 +71,14 @@ static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) { Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - GCCInstallation.init(Triple, Args, getCXXStdlibTypeInUse()); + GCCInstallation.TripleToDebianMultiarch = [](const llvm::Triple &T) { + StringRef TripleStr = T.str(); + StringRef DebianMultiarch = + T.getArch() == llvm::Triple::x86 ? "i386-gnu" : TripleStr; + return DebianMultiarch; + }; + + GCCInstallation.init(Triple, Args); Multilibs = GCCInstallation.getMultilibs(); SelectedMultilibs.assign({GCCInstallation.getMultilib()}); std::string SysRoot = computeSysRoot(); @@ -207,12 +214,7 @@ void Hurd::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, if (!GCCInstallation.isValid()) return; - StringRef TripleStr = GCCInstallation.getTriple().str(); - StringRef DebianMultiarch = - GCCInstallation.getTriple().getArch() == llvm::Triple::x86 ? "i386-gnu" - : TripleStr; - - addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args, DebianMultiarch); + addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args); } void Hurd::addExtraOpts(llvm::opt::ArgStringList &CmdArgs) const { diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index 86bf610026226..65977d56af030 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -212,7 +212,14 @@ static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) { Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - GCCInstallation.init(Triple, Args, getCXXStdlibTypeInUse()); + GCCInstallation.TripleToDebianMultiarch = [](const llvm::Triple &T) { + StringRef TripleStr = T.str(); + StringRef DebianMultiarch = + T.getArch() == llvm::Triple::x86 ? "i386-linux-gnu" : TripleStr; + return DebianMultiarch; + }; + + GCCInstallation.init(Triple, Args); Multilibs = GCCInstallation.getMultilibs(); SelectedMultilibs.assign({GCCInstallation.getMultilib()}); llvm::Triple::ArchType Arch = Triple.getArch(); @@ -701,22 +708,15 @@ void Linux::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, if (!GCCInstallation.isValid()) return; - // Detect Debian g++-multiarch-incdir.diff. - StringRef TripleStr = GCCInstallation.getTriple().str(); - StringRef DebianMultiarch = - GCCInstallation.getTriple().getArch() == llvm::Triple::x86 - ? "i386-linux-gnu" - : TripleStr; - // Try generic GCC detection first. - if (Generic_GCC::addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args, - DebianMultiarch)) + if (Generic_GCC::addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args)) return; StringRef LibDir = GCCInstallation.getParentLibPath(); const Multilib &Multilib = GCCInstallation.getMultilib(); const GCCVersion &Version = GCCInstallation.getVersion(); + StringRef TripleStr = GCCInstallation.getTriple().str(); const std::string LibStdCXXIncludePathCandidates[] = { // Android standalone toolchain has C++ headers in yet another place. LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text, diff --git a/clang/lib/Driver/ToolChains/MSP430.cpp b/clang/lib/Driver/ToolChains/MSP430.cpp index ed515f0f1373c..07e875c64960e 100644 --- a/clang/lib/Driver/ToolChains/MSP430.cpp +++ b/clang/lib/Driver/ToolChains/MSP430.cpp @@ -112,7 +112,7 @@ MSP430ToolChain::MSP430ToolChain(const Driver &D, const llvm::Triple &Triple, StringRef MultilibSuf = ""; - GCCInstallation.init(Triple, Args, getCXXStdlibTypeInUse()); + GCCInstallation.init(Triple, Args); if (GCCInstallation.isValid()) { MultilibSuf = GCCInstallation.getMultilib().gccSuffix(); diff --git a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp index e5d1e550f5453..624099d21ae12 100644 --- a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp +++ b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp @@ -50,7 +50,7 @@ bool RISCVToolChain::hasGCCToolchain(const Driver &D, RISCVToolChain::RISCVToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - GCCInstallation.init(Triple, Args, getCXXStdlibTypeInUse()); + GCCInstallation.init(Triple, Args); if (GCCInstallation.isValid()) { Multilibs = GCCInstallation.getMultilibs(); SelectedMultilibs.assign({GCCInstallation.getMultilib()}); diff --git a/clang/lib/Driver/ToolChains/Solaris.cpp b/clang/lib/Driver/ToolChains/Solaris.cpp index 1153c2ac319cb..fd3232b7c1b06 100644 --- a/clang/lib/Driver/ToolChains/Solaris.cpp +++ b/clang/lib/Driver/ToolChains/Solaris.cpp @@ -310,7 +310,7 @@ Solaris::Solaris(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - GCCInstallation.init(Triple, Args, getCXXStdlibTypeInUse()); + GCCInstallation.init(Triple, Args); StringRef LibSuffix = getSolarisLibSuffix(Triple); path_list &Paths = getFilePaths(); diff --git a/clang/test/Driver/Inputs/powerpc64le-linux-gnu-tree/gcc-11.2.0/include/c++/11.2.0/.keep b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/10/crtbegin.o similarity index 100% rename from clang/test/Driver/Inputs/powerpc64le-linux-gnu-tree/gcc-11.2.0/include/c++/11.2.0/.keep rename to clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/10/crtbegin.o diff --git a/clang/test/Driver/Inputs/powerpc64le-linux-gnu-tree/gcc-12/include/c++/12/.keep b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/10/crtend.o similarity index 100% rename from clang/test/Driver/Inputs/powerpc64le-linux-gnu-tree/gcc-12/include/c++/12/.keep rename to clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/10/crtend.o diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/11/crtbegin.o b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/11/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/11/crtend.o b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/11/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/11/include/.keep b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/11/include/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/12/crtbegin.o b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/12/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/12/crtend.o b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/12/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/12/include/.keep b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/12/include/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/10/crtbegin.o b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/10/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/10/crtend.o b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/10/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/10/include/.keep b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/10/include/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/11/crtbegin.o b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/11/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/11/crtend.o b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/11/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/12/crtbegin.o b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/12/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/12/crtend.o b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/12/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/12/include/.keep b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/12/include/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/10/crtbegin.o b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/10/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/10/crtend.o b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/10/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/10/include/.keep b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/10/include/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/11/crtbegin.o b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/11/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/11/crtend.o b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/11/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/12/crtbegin.o b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/12/crtbegin.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/12/crtend.o b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/12/crtend.o new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/gcc-toolchain-libstdcxx.cpp b/clang/test/Driver/gcc-toolchain-libstdcxx.cpp new file mode 100644 index 0000000000000..6ec1674500022 --- /dev/null +++ b/clang/test/Driver/gcc-toolchain-libstdcxx.cpp @@ -0,0 +1,28 @@ +// UNSUPPORTED: system-windows + +// This file tests that the GCC installation directory detection takes +// the libstdc++ includes into account. In each directory +// Inputs/gcc_toolchain_libstdcxx/gccX, the installation directory for +// gcc X should be picked in the future since it is the directory with +// the largest version number which also contains the libstdc++ +// include directory. + +// RUN: %clang --gcc-toolchain=%S/Inputs/gcc_toolchain_libstdcxx/gcc10/usr -v 2>&1 |& FileCheck %s --check-prefix=GCC10 +// GCC10: clang: warning: future releases of the clang compiler will prefer GCC installations containing libstdc++ include directories; '[[PREFIX:.*gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu]]/10' would be chosen over '[[PREFIX]]/12' [-Wgcc-install-dir-libstdcxx] +// GCC10: Found candidate GCC installation: [[PREFIX]]/10 +// GCC10: Found candidate GCC installation: [[PREFIX]]/11 +// GCC10: Found candidate GCC installation: [[PREFIX]]/12 +// GCC10: Selected GCC installation: [[PREFIX]]/12 + +// RUN: %clang --gcc-toolchain=%S/Inputs/gcc_toolchain_libstdcxx/gcc11/usr -v 2>&1 |& FileCheck %s --check-prefix=ONLY_GCC11 +// ONLY_GCC11: clang: warning: future releases of the clang compiler will prefer GCC installations containing libstdc++ include directories; '[[PREFIX:.*gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu]]/11' would be chosen over '[[PREFIX]]/12' [-Wgcc-install-dir-libstdcxx] +// ONLY_GCC11: Found candidate GCC installation: [[PREFIX]]/10 +// ONLY_GCC11: Found candidate GCC installation: [[PREFIX]]/11 +// ONLY_GCC11: Found candidate GCC installation: [[PREFIX]]/12 +// ONLY_GCC11: Selected GCC installation: [[PREFIX]]/12 + +// RUN: %clang --gcc-toolchain=%S/Inputs/gcc_toolchain_libstdcxx/gcc12/usr -v 2>&1 |& FileCheck %s --check-prefix=GCC12 +// GCC12: Found candidate GCC installation: [[PREFIX:.*gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu]]/10 +// GCC12: Found candidate GCC installation: [[PREFIX]]/11 +// GCC12: Found candidate GCC installation: [[PREFIX]]/12 +// GCC12: Selected GCC installation: [[PREFIX]]/12 >From d1271ef4c8920bd00f69a79407af2ea62c54394f Mon Sep 17 00:00:00 2001 From: Frederik Harwath <fharw...@amd.com> Date: Tue, 8 Jul 2025 17:00:18 +0200 Subject: [PATCH 3/7] Remove some unnecessary code movement --- .../clang/Basic/DiagnosticDriverKinds.td | 2 -- clang/include/clang/Driver/ToolChain.h | 23 ++++++++----------- clang/lib/Driver/ToolChain.cpp | 16 ++++++------- clang/lib/Driver/ToolChains/Managarm.cpp | 4 +--- 4 files changed, 19 insertions(+), 26 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 7f27f1e64cd7f..c91517f9796ff 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -874,11 +874,9 @@ def warn_drv_openacc_without_cir : Warning<"OpenACC directives will result in no runtime behavior; use " "-fclangir to enable runtime effect">, InGroup<SourceUsesOpenACC>; -} def warn_drv_gcc_install_dir_libstdcxx : Warning< "future releases of the clang compiler will prefer GCC installations " "containing libstdc++ include directories; '%0' would be chosen over '%1'">, InGroup<DiagGroup<"gcc-install-dir-libstdcxx">>; } - diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h index a441aa65a87c5..61c70bd4c0288 100644 --- a/clang/include/clang/Driver/ToolChain.h +++ b/clang/include/clang/Driver/ToolChain.h @@ -228,29 +228,26 @@ class ToolChain { static void addSystemFrameworkInclude(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, const Twine &Path); - static void addExternCSystemInclude(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, const Twine &Path); - static std::string concat(StringRef Path, const Twine &A, const Twine &B = "", - const Twine &C = "", const Twine &D = ""); - ///@} - -public: - static void addSystemInclude(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - const Twine &Path); static void - addExternCSystemIncludeIfExists(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - const Twine &Path); + addExternCSystemIncludeIfExists(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + const Twine &Path); static void addSystemFrameworkIncludes(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, ArrayRef<StringRef> Paths); static void addSystemIncludes(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, ArrayRef<StringRef> Paths); - + static std::string concat(StringRef Path, const Twine &A, const Twine &B = "", + const Twine &C = "", const Twine &D = ""); + ///@} +public: + static void addSystemInclude(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + const Twine &Path); virtual ~ToolChain(); // Accessors diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index c9769d818d344..c8b6283e4dad0 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -1370,6 +1370,14 @@ ToolChain::CXXStdlibType ToolChain::GetCXXStdlibType(const ArgList &Args) const{ return *cxxStdlibType; } +/// Utility function to add a system framework directory to CC1 arguments. +void ToolChain::addSystemFrameworkInclude(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + const Twine &Path) { + CC1Args.push_back("-internal-iframework"); + CC1Args.push_back(DriverArgs.MakeArgString(Path)); +} + /// Utility function to add a system include directory with extern "C" /// semantics to CC1 arguments. /// @@ -1400,14 +1408,6 @@ void ToolChain::addExternCSystemIncludeIfExists(const ArgList &DriverArgs, CC1Args.push_back(DriverArgs.MakeArgString(Path)); } -/// Utility function to add a system framework directory to CC1 arguments. -void ToolChain::addSystemFrameworkInclude(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - const Twine &Path) { - CC1Args.push_back("-internal-iframework"); - CC1Args.push_back(DriverArgs.MakeArgString(Path)); -} - /// Utility function to add a list of system framework directories to CC1. void ToolChain::addSystemFrameworkIncludes(const ArgList &DriverArgs, ArgStringList &CC1Args, diff --git a/clang/lib/Driver/ToolChains/Managarm.cpp b/clang/lib/Driver/ToolChains/Managarm.cpp index 0f56f0f6aad77..da4a9072317f4 100644 --- a/clang/lib/Driver/ToolChains/Managarm.cpp +++ b/clang/lib/Driver/ToolChains/Managarm.cpp @@ -193,10 +193,8 @@ void Managarm::addLibStdCxxIncludePaths( if (!GCCInstallation.isValid()) return; - StringRef TripleStr = GCCInstallation.getTriple().str(); - // Try generic GCC detection. - Generic_GCC::addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args, TripleStr); + addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args); } SanitizerMask Managarm::getSupportedSanitizers() const { >From f37db8df9b01883ce75cf95ae0ba33bb282c4c39 Mon Sep 17 00:00:00 2001 From: Frederik Harwath <fharw...@amd.com> Date: Tue, 8 Jul 2025 17:25:51 +0200 Subject: [PATCH 4/7] Correct spelling mistakes --- clang/lib/Driver/ToolChains/Gnu.cpp | 5 +++-- clang/lib/Driver/ToolChains/Gnu.h | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index e52b1cbcbdbc7..21686cc01d180 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -2805,8 +2805,9 @@ bool Generic_GCC::GCCInstallationDetector::SelectGCCInstallationDirectory( }); // FIXME Start selecting installation with libstdc++ in clang 22, - // using the current way of selecting the installation as a fallback only. - // For now, warn if install with libstdc++ differs SelectedInstallation. + // using the current way of selecting the installation as a fallback + // only. For now, warn if the installation with libstdc++ differs + // from SelectedInstallation. const GCCInstallCandidate *InstallWithIncludes = nullptr; for (const auto &I : Installations) { if ((!InstallWithIncludes || I.Version > InstallWithIncludes->Version) && diff --git a/clang/lib/Driver/ToolChains/Gnu.h b/clang/lib/Driver/ToolChains/Gnu.h index 099436abf57c1..ba766ba0f02bb 100644 --- a/clang/lib/Driver/ToolChains/Gnu.h +++ b/clang/lib/Driver/ToolChains/Gnu.h @@ -244,7 +244,7 @@ class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain { const std::string GentooConfigDir = "/etc/env.d/gcc"; public: - /// Function for converting a Triple to a Debian multiarch. The + /// Function for converting a triple to a Debian multiarch. The /// toolchains use this to adjust the target specific component of /// include paths for Debian. std::function<StringRef(const llvm::Triple &)> TripleToDebianMultiarch = >From 07fb1afdad3179b7a00e1b88c301b12ab92aca35 Mon Sep 17 00:00:00 2001 From: Frederik Harwath <fharw...@amd.com> Date: Tue, 8 Jul 2025 17:27:49 +0200 Subject: [PATCH 5/7] Fix comment --- clang/lib/Driver/ToolChains/Gnu.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/Driver/ToolChains/Gnu.h b/clang/lib/Driver/ToolChains/Gnu.h index ba766ba0f02bb..19642336ee2e8 100644 --- a/clang/lib/Driver/ToolChains/Gnu.h +++ b/clang/lib/Driver/ToolChains/Gnu.h @@ -323,8 +323,8 @@ class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain { const GCCInstallCandidate &GCCInstallation, const llvm::opt::ArgList &DriverArgs) const; - /// Select a GCC installation directory from \p Installations. - /// Set \p SelectedInstallation + /// Select a GCC installation directory from \p Installations and + /// set \p SelectedInstallation accordingly. bool SelectGCCInstallationDirectory( const SmallVector<GCCInstallCandidate, 3> &Installations, const llvm::opt::ArgList &Args, >From 90d6164ef1ead89696e0a0d2b4de58f5fae10bbe Mon Sep 17 00:00:00 2001 From: Frederik Harwath <fharw...@amd.com> Date: Tue, 8 Jul 2025 18:31:11 +0200 Subject: [PATCH 6/7] Add .keep files to empty directories --- .../gcc10/usr/lib/gcc/x86_64-linux-gnu/10/include/c++/.keep | 0 .../gcc11/usr/lib/gcc/x86_64-linux-gnu/11/include/c++/.keep | 0 .../gcc12/usr/lib/gcc/x86_64-linux-gnu/11/include/c++/.keep | 0 .../gcc12/usr/lib/gcc/x86_64-linux-gnu/12/include/c++/.keep | 0 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/10/include/c++/.keep create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/11/include/c++/.keep create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/11/include/c++/.keep create mode 100644 clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/12/include/c++/.keep diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/10/include/c++/.keep b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/10/include/c++/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/11/include/c++/.keep b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc11/usr/lib/gcc/x86_64-linux-gnu/11/include/c++/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/11/include/c++/.keep b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/11/include/c++/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/12/include/c++/.keep b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc12/usr/lib/gcc/x86_64-linux-gnu/12/include/c++/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d >From 3d7fc7050a5dbb261489c4a4865fc727e1fba376 Mon Sep 17 00:00:00 2001 From: Frederik Harwath <fharw...@amd.com> Date: Wed, 9 Jul 2025 10:23:18 +0200 Subject: [PATCH 7/7] Remove whitespace changes and reintroduce deleted FIXME --- clang/include/clang/Driver/ToolChain.h | 2 ++ clang/lib/Driver/ToolChains/AVR.cpp | 1 - clang/lib/Driver/ToolChains/Gnu.h | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h index 61c70bd4c0288..b1d1ae2e111c9 100644 --- a/clang/include/clang/Driver/ToolChain.h +++ b/clang/include/clang/Driver/ToolChain.h @@ -241,9 +241,11 @@ class ToolChain { static void addSystemIncludes(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, ArrayRef<StringRef> Paths); + static std::string concat(StringRef Path, const Twine &A, const Twine &B = "", const Twine &C = "", const Twine &D = ""); ///@} + public: static void addSystemInclude(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, diff --git a/clang/lib/Driver/ToolChains/AVR.cpp b/clang/lib/Driver/ToolChains/AVR.cpp index 5b275c1f8be54..731076d9754a9 100644 --- a/clang/lib/Driver/ToolChains/AVR.cpp +++ b/clang/lib/Driver/ToolChains/AVR.cpp @@ -433,7 +433,6 @@ const StringRef PossibleAVRLibcLocations[] = { AVRToolChain::AVRToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - GCCInstallation.init(Triple, Args); if (getCPUName(D, Args, Triple).empty()) diff --git a/clang/lib/Driver/ToolChains/Gnu.h b/clang/lib/Driver/ToolChains/Gnu.h index 19642336ee2e8..1842ef5a548be 100644 --- a/clang/lib/Driver/ToolChains/Gnu.h +++ b/clang/lib/Driver/ToolChains/Gnu.h @@ -185,6 +185,7 @@ class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain { }; struct GCCInstallCandidate { + // FIXME: These might be better as path objects. std::string GCCInstallPath; std::string GCCParentLibPath; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits