[clang] [Clang] Take libstdc++ into account during GCC detection (PR #145056)
Frederik Harwath via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 20 08:45:30 PDT 2025
https://github.com/frederik-h created https://github.com/llvm/llvm-project/pull/145056
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.
>From 87c03ace23467a7d6cb7e466a02309b5b287a013 Mon Sep 17 00:00:00 2001
From: Frederik Harwath <fharwath at amd.com>
Date: Wed, 19 Feb 2025 16:01:56 +0100
Subject: [PATCH] [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"
More information about the cfe-commits
mailing list