Index: clang/lib/Driver/ToolChains/Gnu.cpp =================================================================== --- clang/lib/Driver/ToolChains/Gnu.cpp +++ clang/lib/Driver/ToolChains/Gnu.cpp @@ -2150,17 +2150,35 @@ // Non-Solaris is much simpler - most systems just go with "/usr". if (SysRoot.empty() && TargetTriple.getOS() == llvm::Triple::Linux) { // Yet, still look for RHEL/CentOS devtoolsets and gcc-toolsets. - Prefixes.push_back("/opt/rh/gcc-toolset-11/root/usr"); - Prefixes.push_back("/opt/rh/gcc-toolset-10/root/usr"); - Prefixes.push_back("/opt/rh/devtoolset-11/root/usr"); - Prefixes.push_back("/opt/rh/devtoolset-10/root/usr"); - Prefixes.push_back("/opt/rh/devtoolset-9/root/usr"); - Prefixes.push_back("/opt/rh/devtoolset-8/root/usr"); - Prefixes.push_back("/opt/rh/devtoolset-7/root/usr"); - Prefixes.push_back("/opt/rh/devtoolset-6/root/usr"); - Prefixes.push_back("/opt/rh/devtoolset-4/root/usr"); - Prefixes.push_back("/opt/rh/devtoolset-3/root/usr"); - Prefixes.push_back("/opt/rh/devtoolset-2/root/usr"); + // Find the directory in /opt/rh/ starting with gcc-toolset-* or + // devtoolset-* with the highest version number and add that + // one to our prefixes. + std::string PrefixDir = SysRoot.str() + "/opt/rh"; + std::string ChosenToolsetDir; + unsigned ChosenToolsetVersion = 0; + std::error_code EC; + for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(PrefixDir, EC), + LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef ToolsetDir = llvm::sys::path::filename(LI->path()); + + if (!ToolsetDir.startswith("gcc-toolset-") && + !ToolsetDir.startswith("devtoolset-")) + continue; + + unsigned ToolsetVersion; + if (ToolsetDir.substr(ToolsetDir.rfind('-') + 1) + .getAsInteger(10, ToolsetVersion)) + continue; + + if (ToolsetVersion > ChosenToolsetVersion) { + ChosenToolsetVersion = ToolsetVersion; + ChosenToolsetDir = PrefixDir + "/" + ToolsetDir.str(); + } + } + + if (ChosenToolsetVersion > 0) + Prefixes.push_back(ChosenToolsetDir); } Prefixes.push_back(SysRoot.str() + "/usr"); } Index: clang/unittests/Driver/ToolChainTest.cpp =================================================================== --- clang/unittests/Driver/ToolChainTest.cpp +++ clang/unittests/Driver/ToolChainTest.cpp @@ -610,4 +610,90 @@ DiagConsumer->clear(); } +TEST(ToolChainTest, Toolsets) { + IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); + IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); + struct TestDiagnosticConsumer : public DiagnosticConsumer {}; + + // Check (newer) GCC toolset installation + { + IntrusiveRefCntPtr InMemoryFileSystem( + new llvm::vfs::InMemoryFileSystem); + + InMemoryFileSystem->addFile("/opt/rh/gcc-toolset-", 0, + llvm::MemoryBuffer::getMemBuffer("\n")); + InMemoryFileSystem->addFile("/opt/rh/gcc-toolset--", 0, + llvm::MemoryBuffer::getMemBuffer("\n")); + InMemoryFileSystem->addFile("/opt/rh/gcc-toolset-2", 0, + llvm::MemoryBuffer::getMemBuffer("\n")); + InMemoryFileSystem->addFile("/opt/rh/gcc-toolset--1", 0, + llvm::MemoryBuffer::getMemBuffer("\n")); + + // File needed for GCC installation detection + InMemoryFileSystem->addFile( + "/opt/rh/gcc-toolset-512/lib/gcc/x86_64-redhat-linux/11/crtbegin.o", 0, + llvm::MemoryBuffer::getMemBuffer("\n")); + + DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer); + Driver TheDriver("/bin/clang", "x86_64-redhat-linux", Diags, + "clang LLVM compiler", InMemoryFileSystem); + std::unique_ptr C(TheDriver.BuildCompilation({"-v"})); + ASSERT_TRUE(C); + std::string S; + { + llvm::raw_string_ostream OS(S); + C->getDefaultToolChain().printVerboseInfo(OS); + } + if (is_style_windows(llvm::sys::path::Style::native)) + std::replace(S.begin(), S.end(), '\\', '/'); + EXPECT_EQ("Found candidate GCC installation: " + "/opt/rh/gcc-toolset-512/lib/gcc/x86_64-redhat-linux/11\n" + "Selected GCC installation: " + "/opt/rh/gcc-toolset-512/lib/gcc/x86_64-redhat-linux/11\n" + "Candidate multilib: .;@m64\n" + "Selected multilib: .;@m64\n", + S); + } + + // And older devtoolset + { + IntrusiveRefCntPtr InMemoryFileSystem( + new llvm::vfs::InMemoryFileSystem); + + InMemoryFileSystem->addFile("/opt/rh/devtoolset-", 0, + llvm::MemoryBuffer::getMemBuffer("\n")); + InMemoryFileSystem->addFile("/opt/rh/devtoolset--", 0, + llvm::MemoryBuffer::getMemBuffer("\n")); + InMemoryFileSystem->addFile("/opt/rh/devtoolset-2", 0, + llvm::MemoryBuffer::getMemBuffer("\n")); + InMemoryFileSystem->addFile("/opt/rh/devtoolset--1", 0, + llvm::MemoryBuffer::getMemBuffer("\n")); + + // File needed for GCC installation detection + InMemoryFileSystem->addFile( + "/opt/rh/devtoolset-512/lib/gcc/x86_64-redhat-linux/11/crtbegin.o", 0, + llvm::MemoryBuffer::getMemBuffer("\n")); + + DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer); + Driver TheDriver("/bin/clang", "x86_64-redhat-linux", Diags, + "clang LLVM compiler", InMemoryFileSystem); + std::unique_ptr C(TheDriver.BuildCompilation({"-v"})); + ASSERT_TRUE(C); + std::string S; + { + llvm::raw_string_ostream OS(S); + C->getDefaultToolChain().printVerboseInfo(OS); + } + if (is_style_windows(llvm::sys::path::Style::native)) + std::replace(S.begin(), S.end(), '\\', '/'); + EXPECT_EQ("Found candidate GCC installation: " + "/opt/rh/devtoolset-512/lib/gcc/x86_64-redhat-linux/11\n" + "Selected GCC installation: " + "/opt/rh/devtoolset-512/lib/gcc/x86_64-redhat-linux/11\n" + "Candidate multilib: .;@m64\n" + "Selected multilib: .;@m64\n", + S); + } +} + } // end anonymous namespace.