diff --git a/clang/lib/Driver/ToolChains/Gnu.h b/clang/lib/Driver/ToolChains/Gnu.h --- a/clang/lib/Driver/ToolChains/Gnu.h +++ b/clang/lib/Driver/ToolChains/Gnu.h @@ -300,6 +300,11 @@ Tool *buildAssembler() const override; Tool *buildLinker() const override; + virtual std::string getMultiarchTriple(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef SysRoot) const + { return TargetTriple.str(); } + /// \name ToolChain Implementation Helper Functions /// @{ @@ -322,6 +327,10 @@ addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const; + bool + addGCCLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix, StringRef GCCTriple, StringRef GCCMultiarchTriple, StringRef TargetMultiarchTriple, diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -2686,19 +2686,49 @@ } } -void -Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - // FIXME: The Linux behavior would probaby be a better approach here. - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/include/c++/v1"); +static std::string DetectLibcxxIncludePath(llvm::vfs::FileSystem &vfs, + StringRef base) { + std::error_code EC; + int MaxVersion = 0; + std::string MaxVersionString; + for (llvm::vfs::directory_iterator LI = vfs.dir_begin(base, EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->path()); + int Version; + if (VersionText[0] == 'v' && + !VersionText.slice(1, StringRef::npos).getAsInteger(10, Version)) { + if (Version > MaxVersion) { + MaxVersion = Version; + MaxVersionString = VersionText; + } + } + } + return MaxVersion ? (base + "/" + MaxVersionString).str() : ""; } void -Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - // By default, we don't assume we know where libstdc++ might be installed. - // FIXME: If we have a valid GCCInstallation, use it. +Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + const std::string& SysRoot = getDriver().SysRoot; + auto AddIncludePath = [&](std::string Path) { + std::string IncludePath = DetectLibcxxIncludePath(getVFS(), Path); + if (IncludePath.empty() || !getVFS().exists(IncludePath)) + return false; + addSystemInclude(DriverArgs, CC1Args, IncludePath); + return true; + }; + // Android never uses the libc++ headers installed alongside the toolchain, + // which are generally incompatible with the NDK libraries anyway. + if (!getTriple().isAndroid()) + if (AddIncludePath(getDriver().Dir + "/../include/c++")) + return; + // If this is a development, non-installed, clang, libcxx will + // not be found at ../include/c++ but it likely to be found at + // one of the following two locations: + if (AddIncludePath(SysRoot + "/usr/local/include/c++")) + return; + if (AddIncludePath(SysRoot + "/usr/include/c++")) + return; } /// Helper to add the variant paths of a libstdc++ installation. @@ -2734,6 +2764,60 @@ return true; } +bool +Generic_GCC::addGCCLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + // Use GCCInstallation to know where libstdc++ headers are installed. + if (!GCCInstallation.isValid()) + return false; + + // 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 std::string GCCMultiarchTriple = getMultiarchTriple( + getDriver(), GCCInstallation.getTriple(), getDriver().SysRoot); + const std::string TargetMultiarchTriple = + getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot); + const GCCVersion &Version = GCCInstallation.getVersion(); + + // The primary search for libstdc++ supports multiarch variants. + if (addLibStdCXXIncludePaths(LibDir.str() + "/../include", + "/c++/" + Version.Text, TripleStr, + GCCMultiarchTriple, TargetMultiarchTriple, + Multilib.includeSuffix(), DriverArgs, CC1Args)) + return true; + + // Otherwise, fall back on a bunch of options which don't use multiarch + // layouts for simplicity. + const std::string LibStdCXXIncludePathCandidates[] = { + // Gentoo is weird and places its headers inside the GCC install, + // so if the first attempt to find the headers fails, try these patterns. + InstallDir.str() + "/include/g++-v" + Version.Text, + InstallDir.str() + "/include/g++-v" + Version.MajorStr + "." + + Version.MinorStr, + InstallDir.str() + "/include/g++-v" + Version.MajorStr, + }; + + for (const auto &IncludePath : LibStdCXXIncludePathCandidates) { + if (addLibStdCXXIncludePaths(IncludePath, /*Suffix*/ "", TripleStr, + /*GCCMultiarchTriple*/ "", + /*TargetMultiarchTriple*/ "", + Multilib.includeSuffix(), DriverArgs, CC1Args)) + return true; + } + return false; +} + +void +Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args); +} + llvm::opt::DerivedArgList * Generic_GCC::TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef, Action::OffloadKind DeviceOffloadKind) const { diff --git a/clang/lib/Driver/ToolChains/Hurd.h b/clang/lib/Driver/ToolChains/Hurd.h --- a/clang/lib/Driver/ToolChains/Hurd.h +++ b/clang/lib/Driver/ToolChains/Hurd.h @@ -36,6 +36,10 @@ protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; + + std::string getMultiarchTriple(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef SysRoot) const override; }; } // end namespace toolchains diff --git a/clang/lib/Driver/ToolChains/Hurd.cpp b/clang/lib/Driver/ToolChains/Hurd.cpp --- a/clang/lib/Driver/ToolChains/Hurd.cpp +++ b/clang/lib/Driver/ToolChains/Hurd.cpp @@ -27,9 +27,9 @@ /// a target-triple directory in the library and header search paths. /// Unfortunately, this triple does not align with the vanilla target triple, /// so we provide a rough mapping here. -static std::string getMultiarchTriple(const Driver &D, - const llvm::Triple &TargetTriple, - StringRef SysRoot) { +std::string Hurd::getMultiarchTriple(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef SysRoot) const { if (TargetTriple.getArch() == llvm::Triple::x86) { // We use the existence of '/lib/' as a directory to detect some // common hurd triples that don't quite match the Clang triple for both diff --git a/clang/lib/Driver/ToolChains/Linux.h b/clang/lib/Driver/ToolChains/Linux.h --- a/clang/lib/Driver/ToolChains/Linux.h +++ b/clang/lib/Driver/ToolChains/Linux.h @@ -26,9 +26,6 @@ void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - void addLibCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; void addLibStdCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; @@ -52,6 +49,10 @@ protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; + + std::string getMultiarchTriple(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef SysRoot) const override; }; } // end namespace toolchains diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -37,9 +37,9 @@ /// a target-triple directory in the library and header search paths. /// Unfortunately, this triple does not align with the vanilla target triple, /// so we provide a rough mapping here. -static std::string getMultiarchTriple(const Driver &D, +std::string Linux::getMultiarchTriple(const Driver &D, const llvm::Triple &TargetTriple, - StringRef SysRoot) { + StringRef SysRoot) const { llvm::Triple::EnvironmentType TargetEnvironment = TargetTriple.getEnvironment(); bool IsAndroid = TargetTriple.isAndroid(); @@ -865,86 +865,23 @@ addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude); } -static std::string DetectLibcxxIncludePath(llvm::vfs::FileSystem &vfs, - StringRef base) { - std::error_code EC; - int MaxVersion = 0; - std::string MaxVersionString = ""; - for (llvm::vfs::directory_iterator LI = vfs.dir_begin(base, EC), LE; - !EC && LI != LE; LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->path()); - int Version; - if (VersionText[0] == 'v' && - !VersionText.slice(1, StringRef::npos).getAsInteger(10, Version)) { - if (Version > MaxVersion) { - MaxVersion = Version; - MaxVersionString = VersionText; - } - } - } - return MaxVersion ? (base + "/" + MaxVersionString).str() : ""; -} - -void Linux::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - const std::string& SysRoot = computeSysRoot(); - auto AddIncludePath = [&](std::string Path) { - std::string IncludePath = DetectLibcxxIncludePath(getVFS(), Path); - if (IncludePath.empty() || !getVFS().exists(IncludePath)) - return false; - addSystemInclude(DriverArgs, CC1Args, IncludePath); - return true; - }; - // Android never uses the libc++ headers installed alongside the toolchain, - // which are generally incompatible with the NDK libraries anyway. - if (!getTriple().isAndroid()) - if (AddIncludePath(getDriver().Dir + "/../include/c++")) - return; - // If this is a development, non-installed, clang, libcxx will - // not be found at ../include/c++ but it likely to be found at - // one of the following two locations: - if (AddIncludePath(SysRoot + "/usr/local/include/c++")) - return; - if (AddIncludePath(SysRoot + "/usr/include/c++")) - return; -} - void Linux::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { + // Try generic GCC detection first. + if (Generic_GCC::addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args)) + return; + // We need a detected GCC installation on Linux to provide libstdc++'s - // headers. + // headers in odd Linuxish places. if (!GCCInstallation.isValid()) return; - // 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 std::string GCCMultiarchTriple = getMultiarchTriple( - getDriver(), GCCInstallation.getTriple(), getDriver().SysRoot); - const std::string TargetMultiarchTriple = - getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot); const GCCVersion &Version = GCCInstallation.getVersion(); - // The primary search for libstdc++ supports multiarch variants. - if (addLibStdCXXIncludePaths(LibDir.str() + "/../include", - "/c++/" + Version.Text, TripleStr, - GCCMultiarchTriple, TargetMultiarchTriple, - Multilib.includeSuffix(), DriverArgs, CC1Args)) - return; - - // Otherwise, fall back on a bunch of options which don't use multiarch - // layouts for simplicity. const std::string LibStdCXXIncludePathCandidates[] = { - // Gentoo is weird and places its headers inside the GCC install, - // so if the first attempt to find the headers fails, try these patterns. - InstallDir.str() + "/include/g++-v" + Version.Text, - InstallDir.str() + "/include/g++-v" + Version.MajorStr + "." + - Version.MinorStr, - InstallDir.str() + "/include/g++-v" + Version.MajorStr, // Android standalone toolchain has C++ headers in yet another place. LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text, // Freescale SDK C++ headers are directly in /usr/include/c++,