Index: lib/Driver/ToolChains/Gnu.h =================================================================== --- lib/Driver/ToolChains/Gnu.h +++ lib/Driver/ToolChains/Gnu.h @@ -265,9 +265,15 @@ StringRef CandidateTriple, bool NeedsBiarchSuffix = false); + bool ScanGentooConfigs(const llvm::Triple &TargetTriple, + const llvm::opt::ArgList &Args, + const SmallVectorImpl &CandidateTriples, + const SmallVectorImpl &BiarchTriples); + bool ScanGentooGccConfig(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args, StringRef CandidateTriple, + const std::string& SysRootPrefix, bool NeedsBiarchSuffix = false); }; Index: lib/Driver/ToolChains/Gnu.cpp =================================================================== --- lib/Driver/ToolChains/Gnu.cpp +++ lib/Driver/ToolChains/Gnu.cpp @@ -1707,18 +1707,21 @@ // in /usr. This avoids accidentally enforcing the system GCC version // when using a custom toolchain. if (GCCToolchainDir == "" || GCCToolchainDir == D.SysRoot + "/usr") { - for (StringRef CandidateTriple : ExtraTripleAliases) { - if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple)) - return; - } - for (StringRef CandidateTriple : CandidateTripleAliases) { - if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple)) - return; - } - for (StringRef CandidateTriple : CandidateBiarchTripleAliases) { - if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple, true)) - return; - } + SmallVector GentooTestTriples; + // Try to match an exact triple as target triple first. + // e.g. crossdev -S x86_64-gentoo-linux-gnu will install gcc libs for + // x86_64-gentoo-linux-gnu. But "clang -target x86_64-gentoo-linux-gnu" + // may pick the libraries for x86_64-pc-linux-gnu even when exact matching + // triple x86_64-gentoo-linux-gnu is present. + GentooTestTriples.push_back(TargetTriple.str()); + // Check rest of triples. + GentooTestTriples.append(ExtraTripleAliases.begin(), + ExtraTripleAliases.end()); + GentooTestTriples.append(CandidateTripleAliases.begin(), + CandidateTripleAliases.end()); + if (ScanGentooConfigs(TargetTriple, Args, GentooTestTriples, + CandidateBiarchTripleAliases)) + return; } // Loop over the various components which exist and select the best GCC @@ -2224,11 +2227,44 @@ } } +bool Generic_GCC::GCCInstallationDetector::ScanGentooConfigs( + const llvm::Triple &TargetTriple, const ArgList &Args, + const SmallVectorImpl &CandidateTriples, + const SmallVectorImpl &CandidateBiarchTriples) { + // First scan libraries from the sysroot directory if specified. + // If not successful, scan the root directories. This is needed to find + // cross-compilation files/libraries installed by crossdev. For instance, + // crossdev -S aarch64-gentoo-linux-gnu installs GCC libraries in + // /usr/lib/gcc/version/aarch64-gentoo-linux-gnu and the headers are + // installed at /usr/aarch64-gentoo-linux-gnu. Sysroot argument is + // needed to find the headers installed in /usr/aarch64-gentoo-linux-gnu. + SmallVector SysRootPrefixes; + if (!D.SysRoot.empty()) { + SysRootPrefixes.push_back(D.SysRoot); + } + SysRootPrefixes.push_back(""); + + for (const std::string &SysRoot : SysRootPrefixes) { + for (StringRef CandidateTriple : CandidateTriples) { + if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple, SysRoot)) + return true; + } + + for (StringRef CandidateTriple : CandidateBiarchTriples) { + if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple, SysRoot, + true)) + return true; + } + } + return false; +} + bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig( const llvm::Triple &TargetTriple, const ArgList &Args, - StringRef CandidateTriple, bool NeedsBiarchSuffix) { + StringRef CandidateTriple, const std::string &SysRootPrefix, + bool NeedsBiarchSuffix) { llvm::ErrorOr> File = - D.getVFS().getBufferForFile(D.SysRoot + "/etc/env.d/gcc/config-" + + D.getVFS().getBufferForFile(SysRootPrefix + "/etc/env.d/gcc/config-" + CandidateTriple.str()); if (File) { SmallVector Lines; @@ -2236,23 +2272,52 @@ for (StringRef Line : Lines) { Line = Line.trim(); // CURRENT=triple-version - if (Line.consume_front("CURRENT=")) { - const std::pair ActiveVersion = - Line.rsplit('-'); - // Note: Strictly speaking, we should be reading - // /etc/env.d/gcc/${CURRENT} now. However, the file doesn't - // contain anything new or especially useful to us. - const std::string GentooPath = D.SysRoot + "/usr/lib/gcc/" + - ActiveVersion.first.str() + "/" + - ActiveVersion.second.str(); + if (!Line.consume_front("CURRENT=")) + continue; + // Process the config file pointed to by CURRENT. + llvm::ErrorOr> ConfigFile = + D.getVFS().getBufferForFile(SysRootPrefix + "/etc/env.d/gcc/" + + Line.str()); + std::pair ActiveVersion = Line.rsplit('-'); + // List of paths to scan for libraries. + SmallVector GentooScanPaths; + // Scan the Config file to find installed GCC libraries path. + // Typical content of the GCC config file: + // LDPATH="/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.x:/usr/lib/gcc/ + // (continued from previous line) x86_64-pc-linux-gnu/4.9.x/32" + // MANPATH="/usr/share/gcc-data/x86_64-pc-linux-gnu/4.9.x/man" + // INFOPATH="/usr/share/gcc-data/x86_64-pc-linux-gnu/4.9.x/info" + // STDCXX_INCDIR="/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.x/include/g++-v4" + // We are looking for the paths listed in LDPATH=... . + if (ConfigFile) { + SmallVector ConfigLines; + ConfigFile.get()->getBuffer().split(ConfigLines, "\n"); + for (StringRef ConfLine : ConfigLines) { + ConfLine = ConfLine.trim(); + if (ConfLine.consume_front("LDPATH=")) { + // Drop '"' from front and back if present. + ConfLine.consume_back("\""); + ConfLine.consume_front("\""); + // Get all paths sperated by ':' + ConfLine.split(GentooScanPaths, ':', -1, /*AllowEmpty*/ false); + } + } + } + // Test the path based on the version in /etc/env.d/gcc/config-{tuple}. + std::string basePath = SysRootPrefix + "/usr/lib/gcc/" + + ActiveVersion.first.str() + "/" + ActiveVersion.second.str(); + GentooScanPaths.push_back(StringRef(basePath)); + + // Scan all paths for GCC libraries. + for (const auto &GentooPath : GentooScanPaths) { if (D.getVFS().exists(GentooPath + "/crtbegin.o")) { if (!ScanGCCForMultilibs(TargetTriple, Args, GentooPath, NeedsBiarchSuffix)) - return false; + continue; Version = GCCVersion::Parse(ActiveVersion.second); GCCInstallPath = GentooPath; - GCCParentLibPath = GentooPath + "/../../.."; + GCCParentLibPath = std::string(GentooPath) + "/../../.."; GCCTriple.setTriple(ActiveVersion.first); IsValid = true; return true;