diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index a8dc5352fcbb..8f80b4cd49bd 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -37,6 +37,22 @@ latest release, please see the `Clang Web Site `_ or the Potentially Breaking Changes ============================ +- Clang will now emit a warning if the auto-detected GCC installation + directory (i.e. the one with the largest version number) does not + contain libstdc++ include directories although a "complete" GCC + installation directory containing the include directories is + available. It is planned to change the auto-detection to prefer the + "complete" directory in the future. The warning will disappear if + the libstdc++ include directories are either installed or removed + for all GCC installation directories considered by the + auto-detection; see the output of ``clang -v`` for a list of those + directories. If the GCC installations cannot be modified and + maintaining the current choice of the auto-detection is desired, the + GCC installation directory can be selected explicitly using the + ``--gcc-install-dir`` command line argument. This will silence the + warning. It can also be disabled using the + ``-Wno-gcc-install-dir-libstdcxx`` command line flag. + C/C++ Language Potentially Breaking Changes ------------------------------------------- diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 6df8f9932f30..b8c7c6e8d690 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -885,4 +885,9 @@ def warn_drv_openacc_without_cir : Warning<"OpenACC directives will result in no runtime behavior; use " "-fclangir to enable runtime effect">, InGroup; + +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>; } diff --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h index 243056360370..1425714d3411 100644 --- a/clang/include/clang/Driver/ToolChain.h +++ b/clang/include/clang/Driver/ToolChain.h @@ -224,9 +224,6 @@ protected: static void addSystemFrameworkInclude(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, const Twine &Path); - 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); @@ -246,6 +243,9 @@ protected: ///@} 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 7667dbddb0ca..65b36217a940 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -1409,13 +1409,6 @@ void ToolChain::addSystemFrameworkInclude(const llvm::opt::ArgList &DriverArgs, CC1Args.push_back(DriverArgs.MakeArgString(Path)); } -/// Utility function to add a system include directory to CC1 arguments. -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. /// @@ -1438,6 +1431,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 framework directories to CC1. void ToolChain::addSystemFrameworkIncludes(const ArgList &DriverArgs, ArgStringList &CC1Args, diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index 01b146db24f3..3dade2bdf227 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -2123,10 +2123,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; @@ -2186,7 +2187,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)) @@ -2214,7 +2215,7 @@ void Generic_GCC::GCCInstallationDetector::init( } // Skip other prefixes once a GCC installation is found. - if (Version > VersionZero) + if (SelectedInstallation.Version > VersionZero) break; } } @@ -2223,14 +2224,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 { @@ -2768,14 +2772,50 @@ 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; } +bool Generic_GCC::GCCInstallationDetector::SelectGCCInstallationDirectory( + const SmallVector &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 the installation with libstdc++ differs + // from 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, @@ -2805,6 +2845,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( TargetTriple.getVendor() == llvm::Triple::Freescale || TargetTriple.getVendor() == llvm::Triple::OpenEmbedded}}; + SmallVector Installations; for (auto &Suffix : Suffixes) { if (!Suffix.Active) continue; @@ -2822,23 +2863,31 @@ 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(); - IsValid = true; + Installation.GCCInstallPath = + (LibDir + "/" + LibSuffix + "/" + VersionText).str(); + Installation.GCCParentLibPath = + (Installation.GCCInstallPath + "/../" + Suffix.ReversePath).str(); + Installation.SelectedMultilib = getMultilib(); + + Installations.push_back(Installation); } } + + IsValid |= + SelectGCCInstallationDirectory(Installations, Args, SelectedInstallation); } bool Generic_GCC::GCCInstallationDetector::ScanGentooConfigs( @@ -2916,10 +2965,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; } @@ -3122,8 +3173,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) { @@ -3210,12 +3262,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 @@ -3227,39 +3281,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; @@ -3267,22 +3330,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 @@ -3297,20 +3362,50 @@ 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:: + GCCInstallationHasLibStdcxxIncludePaths( + const GCCInstallCandidate &GCCInstallation, + const llvm::opt::ArgList &DriverArgs) const { + StringRef DebianMultiarch = + TripleToDebianMultiarch(GCCInstallation.getTriple()); + + // 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); +} + +bool Generic_GCC::addGCCLibStdCxxIncludePaths( + 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); +} + 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 4c42a5e535d5..5fe143b4aa03 100644 --- a/clang/lib/Driver/ToolChains/Gnu.h +++ b/clang/lib/Driver/ToolChains/Gnu.h @@ -184,46 +184,18 @@ public: bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); } }; - /// This is a class to find a viable GCC installation for Clang to - /// use. - /// - /// This class tries to find a GCC installation on the system, and report - /// information about it. It starts from the host information provided to the - /// Driver, and has logic for fuzzing that where appropriate. - class GCCInstallationDetector { - bool IsValid; - llvm::Triple GCCTriple; - const Driver &D; - + struct GCCInstallCandidate { // FIXME: These might be better as path objects. std::string GCCInstallPath; std::string GCCParentLibPath; + llvm::Triple GCCTriple; + /// 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 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 CandidateGCCInstallPaths; - - /// The set of multilibs that the detected installation supports. - MultilibSet Multilibs; - - // Gentoo-specific toolchain configurations are stored here. - 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); - - /// Check whether we detected a valid GCC install. - bool isValid() const { return IsValid; } - /// Get the GCC triple for the detected install. const llvm::Triple &getTriple() const { return GCCTriple; } @@ -236,6 +208,88 @@ public: /// 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. + /// + /// This class tries to find a GCC installation on the system, and report + /// information about it. It starts from the host information provided to the + /// Driver, and has logic for fuzzing that where appropriate. + class GCCInstallationDetector { + bool IsValid; + + const Driver &D; + + GCCInstallCandidate SelectedInstallation; + + /// On Biarch systems, this corresponds to the default multilib when + /// targeting the non-default multilib. Otherwise, it is empty. + std::optional BiarchSibling; + + // We retain the list of install paths that were considered and rejected in + // order to print out detailed information in verbose mode. + std::set CandidateGCCInstallPaths; + + /// The set of multilibs that the detected installation supports. + MultilibSet Multilibs; + + // Gentoo-specific toolchain configurations are stored here. + const std::string GentooConfigDir = "/etc/env.d/gcc"; + + public: + /// 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 TripleToDebianMultiarch = + [](const llvm::Triple &T) { + StringRef S = T.str(); + return S; + }; + + explicit GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {} + + void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args); + + // TODO Replace isValid by changing SelectedInstallation into + // std::optional + // and move all accessors for fields of GCCInstallCandidate into + // that struct. + + /// 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 SelectedInstallation.GCCTriple; + } + + /// Get the detected GCC installation path. + StringRef getInstallPath() const { + return SelectedInstallation.GCCInstallPath; + } + + /// Get the detected GCC parent lib path. + StringRef getParentLibPath() const { + return SelectedInstallation.GCCParentLibPath; + } + + /// Get the detected Multilib + const Multilib &getMultilib() const { + return SelectedInstallation.SelectedMultilib; + } + /// Get the whole MultilibSet const MultilibSet &getMultilibs() const { return Multilibs; } @@ -244,7 +298,9 @@ public: 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 +318,21 @@ public: SmallVectorImpl &Prefixes, StringRef SysRoot); + /// 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 and + /// set \p SelectedInstallation accordingly. + bool SelectGCCInstallationDirectory( + const SmallVector &Installations, + const llvm::opt::ArgList &Args, + GCCInstallCandidate &SelectedInstallation) 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, @@ -349,8 +417,7 @@ protected: 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/Hurd.cpp b/clang/lib/Driver/ToolChains/Hurd.cpp index a22a8face179..8bcc7e6d9759 100644 --- a/clang/lib/Driver/ToolChains/Hurd.cpp +++ b/clang/lib/Driver/ToolChains/Hurd.cpp @@ -71,6 +71,13 @@ 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.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()}); @@ -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 8ac8d4eb9181..16e35b08cfbd 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -211,6 +211,13 @@ 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.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()}); @@ -693,22 +700,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/Managarm.cpp b/clang/lib/Driver/ToolChains/Managarm.cpp index 0f56f0f6aad7..da4a9072317f 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 { diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/10/crtbegin.o b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/10/crtbegin.o new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/10/crtend.o b/clang/test/Driver/Inputs/gcc_toolchain_libstdcxx/gcc10/usr/lib/gcc/x86_64-linux-gnu/10/crtend.o new file mode 100644 index 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 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 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/gcc-toolchain-libstdcxx.cpp b/clang/test/Driver/gcc-toolchain-libstdcxx.cpp new file mode 100644 index 000000000000..6ec167450002 --- /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