From: Benjamin Kramer Date: Wed, 7 Oct 2015 15:48:01 +0000 (+0000) Subject: [VFS] Port driver tool chains to VFS. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=032169da0a54b372a2d7e5f9f75a069c7034b9f7;p=clang [VFS] Port driver tool chains to VFS. There are still some loose ends here but it's sufficient so we can detect GCC headers that are inside of a VFS. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@249556 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/VirtualFileSystem.h b/include/clang/Basic/VirtualFileSystem.h index 36a14b794c..3f2d3b800a 100644 --- a/include/clang/Basic/VirtualFileSystem.h +++ b/include/clang/Basic/VirtualFileSystem.h @@ -206,6 +206,9 @@ public: /// Get the working directory of this file system. virtual llvm::ErrorOr getCurrentWorkingDirectory() const = 0; + /// Check whether a file exists. Provided for convenience. + bool exists(const Twine &Path); + /// Make \a Path an absolute path. /// /// Makes \a Path absolute using the current directory if it is not already. diff --git a/include/clang/Driver/Driver.h b/include/clang/Driver/Driver.h index 4a67fdb653..a7c5b6dbb8 100644 --- a/include/clang/Driver/Driver.h +++ b/include/clang/Driver/Driver.h @@ -36,6 +36,11 @@ namespace opt { } namespace clang { + +namespace vfs { +class FileSystem; +} + namespace driver { class Action; @@ -54,6 +59,8 @@ class Driver { DiagnosticsEngine &Diags; + IntrusiveRefCntPtr VFS; + enum DriverMode { GCCMode, GXXMode, @@ -201,9 +208,9 @@ private: SmallVectorImpl &Names) const; public: - Driver(StringRef _ClangExecutable, - StringRef _DefaultTargetTriple, - DiagnosticsEngine &_Diags); + Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple, + DiagnosticsEngine &Diags, + IntrusiveRefCntPtr VFS = nullptr); ~Driver(); /// @name Accessors @@ -216,6 +223,8 @@ public: const DiagnosticsEngine &getDiags() const { return Diags; } + vfs::FileSystem &getVFS() const { return *VFS; } + bool getCheckInputsExist() const { return CheckInputsExist; } void setCheckInputsExist(bool Value) { CheckInputsExist = Value; } diff --git a/include/clang/Driver/ToolChain.h b/include/clang/Driver/ToolChain.h index 9ab3559403..ba844b8e84 100644 --- a/include/clang/Driver/ToolChain.h +++ b/include/clang/Driver/ToolChain.h @@ -30,7 +30,10 @@ namespace opt { } namespace clang { - class ObjCRuntime; +class ObjCRuntime; +namespace vfs { +class FileSystem; +} namespace driver { class Compilation; @@ -119,7 +122,8 @@ public: // Accessors - const Driver &getDriver() const; + const Driver &getDriver() const { return D; } + vfs::FileSystem &getVFS() const; const llvm::Triple &getTriple() const { return Triple; } llvm::Triple::ArchType getArch() const { return Triple.getArch(); } diff --git a/lib/Basic/VirtualFileSystem.cpp b/lib/Basic/VirtualFileSystem.cpp index 227c5737aa..04383dbb87 100644 --- a/lib/Basic/VirtualFileSystem.cpp +++ b/lib/Basic/VirtualFileSystem.cpp @@ -105,6 +105,11 @@ std::error_code FileSystem::makeAbsolute(SmallVectorImpl &Path) const { return llvm::sys::fs::make_absolute(WorkingDir.get(), Path); } +bool FileSystem::exists(const Twine &Path) { + auto Status = status(Path); + return Status && Status->exists(); +} + //===-----------------------------------------------------------------------===/ // RealFileSystem implementation //===-----------------------------------------------------------------------===/ diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 0c0421321e..025e2de260 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -11,6 +11,7 @@ #include "InputInfo.h" #include "ToolChains.h" #include "clang/Basic/Version.h" +#include "clang/Basic/VirtualFileSystem.h" #include "clang/Config/config.h" #include "clang/Driver/Action.h" #include "clang/Driver/Compilation.h" @@ -46,8 +47,9 @@ using namespace clang; using namespace llvm::opt; Driver::Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple, - DiagnosticsEngine &Diags) - : Opts(createDriverOptTable()), Diags(Diags), Mode(GCCMode), + DiagnosticsEngine &Diags, + IntrusiveRefCntPtr VFS) + : Opts(createDriverOptTable()), Diags(Diags), VFS(VFS), Mode(GCCMode), SaveTemps(SaveTempsNone), ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT), UseStdLib(true), DefaultTargetTriple(DefaultTargetTriple), @@ -57,6 +59,10 @@ Driver::Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple, CCGenDiagnostics(false), CCCGenericGCCName(""), CheckInputsExist(true), CCCUsePCH(true), SuppressMissingInputWarning(false) { + // Provide a sane fallback if no VFS is specified. + if (!this->VFS) + this->VFS = vfs::getRealFileSystem(); + Name = llvm::sys::path::filename(ClangExecutable); Dir = llvm::sys::path::parent_path(ClangExecutable); diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index c8cefac555..790d9857e2 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -75,9 +75,7 @@ ToolChain::ToolChain(const Driver &D, const llvm::Triple &T, ToolChain::~ToolChain() { } -const Driver &ToolChain::getDriver() const { - return D; -} +vfs::FileSystem &ToolChain::getVFS() const { return getDriver().getVFS(); } bool ToolChain::useIntegratedAs() const { return Args.hasFlag(options::OPT_fintegrated_as, diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index eefa4f0dcb..a23693d174 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -10,6 +10,7 @@ #include "ToolChains.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Version.h" +#include "clang/Basic/VirtualFileSystem.h" #include "clang/Config/config.h" // for GCC_INSTALL_PREFIX #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" @@ -275,7 +276,7 @@ void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, // For now, allow missing resource libraries to support developers who may // not have compiler-rt checked out or integrated into their build (unless // we explicitly force linking with this library). - if (AlwaysLink || llvm::sys::fs::exists(P)) + if (AlwaysLink || getVFS().exists(P)) CmdArgs.push_back(Args.MakeArgString(P)); // Adding the rpaths might negatively interact when other rpaths are involved, @@ -424,13 +425,13 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { // isysroot. if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { // Warn if the path does not exist. - if (!llvm::sys::fs::exists(A->getValue())) + if (!getVFS().exists(A->getValue())) getDriver().Diag(clang::diag::warn_missing_sysroot) << A->getValue(); } else { if (char *env = ::getenv("SDKROOT")) { // We only use this value as the default if it is an absolute path, // exists, and it is not the root path. - if (llvm::sys::path::is_absolute(env) && llvm::sys::fs::exists(env) && + if (llvm::sys::path::is_absolute(env) && getVFS().exists(env) && StringRef(env) != "/") { Args.append(Args.MakeSeparateArg( nullptr, Opts.getOption(options::OPT_isysroot), env)); @@ -582,10 +583,10 @@ void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, SmallString<128> P(A->getValue()); llvm::sys::path::append(P, "usr", "lib", "libstdc++.dylib"); - if (!llvm::sys::fs::exists(P)) { + if (!getVFS().exists(P)) { llvm::sys::path::remove_filename(P); llvm::sys::path::append(P, "libstdc++.6.dylib"); - if (llvm::sys::fs::exists(P)) { + if (getVFS().exists(P)) { CmdArgs.push_back(Args.MakeArgString(P)); return; } @@ -595,8 +596,8 @@ void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, // Otherwise, look in the root. // FIXME: This should be removed someday when we don't have to care about // 10.6 and earlier, where /usr/lib/libstdc++.dylib does not exist. - if (!llvm::sys::fs::exists("/usr/lib/libstdc++.dylib") && - llvm::sys::fs::exists("/usr/lib/libstdc++.6.dylib")) { + if (!getVFS().exists("/usr/lib/libstdc++.dylib") && + getVFS().exists("/usr/lib/libstdc++.6.dylib")) { CmdArgs.push_back("/usr/lib/libstdc++.6.dylib"); return; } @@ -626,7 +627,7 @@ void DarwinClang::AddCCKextLibArgs(const ArgList &Args, // For now, allow missing resource libraries to support developers who may // not have compiler-rt checked out or integrated into their build. - if (llvm::sys::fs::exists(P)) + if (getVFS().exists(P)) CmdArgs.push_back(Args.MakeArgString(P)); } @@ -1166,7 +1167,7 @@ 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 Driver &D, const llvm::Triple &TargetTriple, const ArgList &Args, + const llvm::Triple &TargetTriple, const ArgList &Args, ArrayRef ExtraTripleAliases) { llvm::Triple BiarchVariantTriple = TargetTriple.isArch32Bit() ? TargetTriple.get64BitArchVariant() @@ -1209,11 +1210,11 @@ void Generic_GCC::GCCInstallationDetector::init( // installation available. GCC installs are ranked by version number. Version = GCCVersion::Parse("0.0.0"); for (const std::string &Prefix : Prefixes) { - if (!llvm::sys::fs::exists(Prefix)) + if (!D.getVFS().exists(Prefix)) continue; for (StringRef Suffix : CandidateLibDirs) { const std::string LibDir = Prefix + Suffix.str(); - if (!llvm::sys::fs::exists(LibDir)) + if (!D.getVFS().exists(LibDir)) continue; for (StringRef Candidate : ExtraTripleAliases) // Try these first. ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate); @@ -1222,7 +1223,7 @@ void Generic_GCC::GCCInstallationDetector::init( } for (StringRef Suffix : CandidateBiarchLibDirs) { const std::string LibDir = Prefix + Suffix.str(); - if (!llvm::sys::fs::exists(LibDir)) + if (!D.getVFS().exists(LibDir)) continue; for (StringRef Candidate : CandidateBiarchTripleAliases) ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate, @@ -1480,10 +1481,8 @@ bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { // \brief -- try common CUDA installation paths looking for files we need for // CUDA compilation. -void -Generic_GCC::CudaInstallationDetector::init(const Driver &D, - const llvm::Triple &TargetTriple, - const llvm::opt::ArgList &Args) { +void Generic_GCC::CudaInstallationDetector::init( + const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args) { SmallVector CudaPathCandidates; if (Args.hasArg(options::OPT_cuda_path_EQ)) @@ -1495,7 +1494,7 @@ Generic_GCC::CudaInstallationDetector::init(const Driver &D, } for (const auto &CudaPath : CudaPathCandidates) { - if (CudaPath.empty() || !llvm::sys::fs::exists(CudaPath)) + if (CudaPath.empty() || !D.getVFS().exists(CudaPath)) continue; CudaInstallPath = CudaPath; @@ -1504,9 +1503,9 @@ Generic_GCC::CudaInstallationDetector::init(const Driver &D, CudaLibPath = CudaInstallPath + (TargetTriple.isArch64Bit() ? "/lib64" : "/lib"); - if (!(llvm::sys::fs::exists(CudaIncludePath) && - llvm::sys::fs::exists(CudaLibPath) && - llvm::sys::fs::exists(CudaLibDevicePath))) + if (!(D.getVFS().exists(CudaIncludePath) && + D.getVFS().exists(CudaLibPath) && + D.getVFS().exists(CudaLibDevicePath))) continue; IsValid = true; @@ -1967,13 +1966,13 @@ void Generic_GCC::GCCInstallationDetector::scanLibDirForGCCTripleSolaris( // /usr/gcc/./lib/gcc//../, so we // need to iterate twice. std::error_code EC; - for (llvm::sys::fs::directory_iterator LI(LibDir, EC), LE; !EC && LI != LE; - LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->path()); + for (vfs::directory_iterator LI = D.getVFS().dir_begin(LibDir, EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->getName()); GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); if (CandidateVersion.Major != -1) // Filter obviously bad entries. - if (!CandidateGCCInstallPaths.insert(LI->path()).second) + if (!CandidateGCCInstallPaths.insert(LI->getName()).second) continue; // Saw this path before; no need to look at it again. if (CandidateVersion.isOlderThan(4, 1, 1)) continue; @@ -1982,16 +1981,18 @@ void Generic_GCC::GCCInstallationDetector::scanLibDirForGCCTripleSolaris( GCCInstallPath = LibDir + "/" + VersionText.str() + "/lib/gcc/" + CandidateTriple.str(); - if (!llvm::sys::fs::exists(GCCInstallPath)) + if (!D.getVFS().exists(GCCInstallPath)) continue; // If we make it here there has to be at least one GCC version, let's just // use the latest one. std::error_code EEC; - for (llvm::sys::fs::directory_iterator LLI(GCCInstallPath, EEC), LLE; + for (vfs::directory_iterator + LLI = D.getVFS().dir_begin(GCCInstallPath, EEC), + LLE; !EEC && LLI != LLE; LLI = LLI.increment(EEC)) { - StringRef SubVersionText = llvm::sys::path::filename(LLI->path()); + StringRef SubVersionText = llvm::sys::path::filename(LLI->getName()); GCCVersion CandidateSubVersion = GCCVersion::Parse(SubVersionText); if (CandidateSubVersion > Version) @@ -2048,12 +2049,14 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( for (unsigned i = 0; i < NumLibSuffixes; ++i) { StringRef LibSuffix = LibAndInstallSuffixes[i][0]; std::error_code EC; - for (llvm::sys::fs::directory_iterator LI(LibDir + LibSuffix, EC), LE; + for (vfs::directory_iterator + LI = D.getVFS().dir_begin(LibDir + LibSuffix, EC), + LE; !EC && LI != LE; LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->path()); + StringRef VersionText = llvm::sys::path::filename(LI->getName()); GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); if (CandidateVersion.Major != -1) // Filter obviously bad entries. - if (!CandidateGCCInstallPaths.insert(LI->path()).second) + if (!CandidateGCCInstallPaths.insert(LI->getName()).second) continue; // Saw this path before; no need to look at it again. if (CandidateVersion.isOlderThan(4, 1, 1)) continue; @@ -2065,9 +2068,9 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( // Debian mips multilibs behave more like the rest of the biarch ones, // so handle them there if (isMipsArch(TargetArch)) { - if (!findMIPSMultilibs(TargetTriple, LI->path(), Args, Detected)) + if (!findMIPSMultilibs(TargetTriple, LI->getName(), Args, Detected)) continue; - } else if (!findBiarchMultilibs(TargetTriple, LI->path(), Args, + } else if (!findBiarchMultilibs(TargetTriple, LI->getName(), Args, NeedsBiarchSuffix, Detected)) { continue; } @@ -2090,7 +2093,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : ToolChain(D, Triple, Args), GCCInstallation(), CudaInstallation() { + : ToolChain(D, Triple, Args), GCCInstallation(D), CudaInstallation(D) { getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); @@ -2183,7 +2186,7 @@ void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs, /// Hexagon Toolchain std::string HexagonToolChain::GetGnuDir(const std::string &InstalledDir, - const ArgList &Args) { + const ArgList &Args) const { // Locate the rest of the toolchain ... std::string GccToolchain = getGCCToolchainDir(Args); @@ -2191,11 +2194,11 @@ std::string HexagonToolChain::GetGnuDir(const std::string &InstalledDir, return GccToolchain; std::string InstallRelDir = InstalledDir + "/../../gnu"; - if (llvm::sys::fs::exists(InstallRelDir)) + if (getVFS().exists(InstallRelDir)) return InstallRelDir; std::string PrefixRelDir = std::string(LLVM_PREFIX) + "/../gnu"; - if (llvm::sys::fs::exists(PrefixRelDir)) + if (getVFS().exists(PrefixRelDir)) return PrefixRelDir; return InstallRelDir; @@ -2221,7 +2224,8 @@ bool HexagonToolChain::UsesG0(const char *smallDataThreshold) { return smallDataThreshold && smallDataThreshold[0] == '0'; } -static void GetHexagonLibraryPaths(const ArgList &Args, const std::string &Ver, +static void GetHexagonLibraryPaths(const HexagonToolChain &TC, + const ArgList &Args, const std::string &Ver, const std::string &MarchString, const std::string &InstalledDir, ToolChain::path_list *LibPaths) { @@ -2240,8 +2244,7 @@ static void GetHexagonLibraryPaths(const ArgList &Args, const std::string &Ver, const std::string MarchSuffix = "/" + MarchString; const std::string G0Suffix = "/G0"; const std::string MarchG0Suffix = MarchSuffix + G0Suffix; - const std::string RootDir = - HexagonToolChain::GetGnuDir(InstalledDir, Args) + "/"; + const std::string RootDir = TC.GetGnuDir(InstalledDir, Args) + "/"; // lib/gcc/hexagon/... std::string LibGCCHexagonDir = RootDir + "lib/gcc/hexagon/"; @@ -2269,21 +2272,21 @@ HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Linux(D, Triple, Args) { const std::string InstalledDir(getDriver().getInstalledDir()); - const std::string GnuDir = HexagonToolChain::GetGnuDir(InstalledDir, Args); + const std::string GnuDir = GetGnuDir(InstalledDir, Args); // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to // program paths const std::string BinDir(GnuDir + "/bin"); - if (llvm::sys::fs::exists(BinDir)) + if (D.getVFS().exists(BinDir)) getProgramPaths().push_back(BinDir); // Determine version of GCC libraries and headers to use. const std::string HexagonDir(GnuDir + "/lib/gcc/hexagon"); std::error_code ec; GCCVersion MaxVersion = GCCVersion::Parse("0.0.0"); - for (llvm::sys::fs::directory_iterator di(HexagonDir, ec), de; + for (vfs::directory_iterator di = D.getVFS().dir_begin(HexagonDir, ec), de; !ec && di != de; di = di.increment(ec)) { - GCCVersion cv = GCCVersion::Parse(llvm::sys::path::filename(di->path())); + GCCVersion cv = GCCVersion::Parse(llvm::sys::path::filename(di->getName())); if (MaxVersion < cv) MaxVersion = cv; } @@ -2296,8 +2299,8 @@ HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple, // support 'linux' we'll need to fix this up LibPaths->clear(); - GetHexagonLibraryPaths(Args, GetGCCLibAndIncVersion(), GetTargetCPU(Args), - InstalledDir, LibPaths); + GetHexagonLibraryPaths(*this, Args, GetGCCLibAndIncVersion(), + GetTargetCPU(Args), InstalledDir, LibPaths); } HexagonToolChain::~HexagonToolChain() {} @@ -2319,7 +2322,7 @@ void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, return; std::string Ver(GetGCCLibAndIncVersion()); - std::string GnuDir = HexagonToolChain::GetGnuDir(D.InstalledDir, DriverArgs); + std::string GnuDir = GetGnuDir(D.InstalledDir, DriverArgs); std::string HexagonDir(GnuDir + "/lib/gcc/hexagon/" + Ver); addExternCSystemInclude(DriverArgs, CC1Args, HexagonDir + "/include"); addExternCSystemInclude(DriverArgs, CC1Args, HexagonDir + "/include-fixed"); @@ -2334,8 +2337,7 @@ void HexagonToolChain::AddClangCXXStdlibIncludeArgs( const Driver &D = getDriver(); std::string Ver(GetGCCLibAndIncVersion()); - SmallString<128> IncludeDir( - HexagonToolChain::GetGnuDir(D.InstalledDir, DriverArgs)); + SmallString<128> IncludeDir(GetGnuDir(D.InstalledDir, DriverArgs)); llvm::sys::path::append(IncludeDir, "hexagon/include/c++/"); llvm::sys::path::append(IncludeDir, Ver); @@ -2742,7 +2744,7 @@ FreeBSD::FreeBSD(const Driver &D, const llvm::Triple &Triple, // back to '/usr/lib' if it doesn't exist. if ((Triple.getArch() == llvm::Triple::x86 || Triple.getArch() == llvm::Triple::ppc) && - llvm::sys::fs::exists(getDriver().SysRoot + "/usr/lib32/crt1.o")) + D.getVFS().exists(getDriver().SysRoot + "/usr/lib32/crt1.o")) getFilePaths().push_back(getDriver().SysRoot + "/usr/lib32"); else getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); @@ -2952,8 +2954,9 @@ Tool *Minix::buildAssembler() const { Tool *Minix::buildLinker() const { return new tools::minix::Linker(*this); } -static void addPathIfExists(Twine Path, ToolChain::path_list &Paths) { - if (llvm::sys::fs::exists(Path)) +static void addPathIfExists(const Driver &D, const Twine &Path, + ToolChain::path_list &Paths) { + if (D.getVFS().exists(Path)) Paths.push_back(Path.str()); } @@ -2963,17 +2966,17 @@ Solaris::Solaris(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_GCC(D, Triple, Args) { - GCCInstallation.init(D, Triple, Args); + GCCInstallation.init(Triple, Args); path_list &Paths = getFilePaths(); if (GCCInstallation.isValid()) - addPathIfExists(GCCInstallation.getInstallPath(), Paths); + addPathIfExists(D, GCCInstallation.getInstallPath(), Paths); - addPathIfExists(getDriver().getInstalledDir(), Paths); + addPathIfExists(D, getDriver().getInstalledDir(), Paths); if (getDriver().getInstalledDir() != getDriver().Dir) - addPathIfExists(getDriver().Dir, Paths); + addPathIfExists(D, getDriver().Dir, Paths); - addPathIfExists(getDriver().SysRoot + getDriver().Dir + "/../lib", Paths); + addPathIfExists(D, getDriver().SysRoot + getDriver().Dir + "/../lib", Paths); std::string LibPath = "/usr/lib/"; switch (Triple.getArch()) { @@ -2990,7 +2993,7 @@ Solaris::Solaris(const Driver &D, const llvm::Triple &Triple, llvm_unreachable("Unsupported architecture"); } - addPathIfExists(getDriver().SysRoot + LibPath, Paths); + addPathIfExists(D, getDriver().SysRoot + LibPath, Paths); } Tool *Solaris::buildAssembler() const { @@ -3076,7 +3079,7 @@ static bool IsUbuntu(enum Distro Distro) { return Distro >= UbuntuHardy && Distro <= UbuntuWily; } -static Distro DetectDistro(llvm::Triple::ArchType Arch) { +static Distro DetectDistro(const Driver &D, llvm::Triple::ArchType Arch) { llvm::ErrorOr> File = llvm::MemoryBuffer::getFile("/etc/lsb-release"); if (File) { @@ -3142,13 +3145,13 @@ static Distro DetectDistro(llvm::Triple::ArchType Arch) { return UnknownDistro; } - if (llvm::sys::fs::exists("/etc/SuSE-release")) + if (D.getVFS().exists("/etc/SuSE-release")) return OpenSUSE; - if (llvm::sys::fs::exists("/etc/exherbo-release")) + if (D.getVFS().exists("/etc/exherbo-release")) return Exherbo; - if (llvm::sys::fs::exists("/etc/arch-release")) + if (D.getVFS().exists("/etc/arch-release")) return ArchLinux; return UnknownDistro; @@ -3160,7 +3163,8 @@ static Distro DetectDistro(llvm::Triple::ArchType Arch) { /// 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 llvm::Triple &TargetTriple, +static std::string getMultiarchTriple(const Driver &D, + const llvm::Triple &TargetTriple, StringRef SysRoot) { llvm::Triple::EnvironmentType TargetEnvironment = TargetTriple.getEnvironment(); @@ -3177,85 +3181,85 @@ static std::string getMultiarchTriple(const llvm::Triple &TargetTriple, case llvm::Triple::arm: case llvm::Triple::thumb: if (TargetEnvironment == llvm::Triple::GNUEABIHF) { - if (llvm::sys::fs::exists(SysRoot + "/lib/arm-linux-gnueabihf")) + if (D.getVFS().exists(SysRoot + "/lib/arm-linux-gnueabihf")) return "arm-linux-gnueabihf"; } else { - if (llvm::sys::fs::exists(SysRoot + "/lib/arm-linux-gnueabi")) + if (D.getVFS().exists(SysRoot + "/lib/arm-linux-gnueabi")) return "arm-linux-gnueabi"; } break; case llvm::Triple::armeb: case llvm::Triple::thumbeb: if (TargetEnvironment == llvm::Triple::GNUEABIHF) { - if (llvm::sys::fs::exists(SysRoot + "/lib/armeb-linux-gnueabihf")) + if (D.getVFS().exists(SysRoot + "/lib/armeb-linux-gnueabihf")) return "armeb-linux-gnueabihf"; } else { - if (llvm::sys::fs::exists(SysRoot + "/lib/armeb-linux-gnueabi")) + if (D.getVFS().exists(SysRoot + "/lib/armeb-linux-gnueabi")) return "armeb-linux-gnueabi"; } break; case llvm::Triple::x86: - if (llvm::sys::fs::exists(SysRoot + "/lib/i386-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/i386-linux-gnu")) return "i386-linux-gnu"; break; case llvm::Triple::x86_64: // We don't want this for x32, otherwise it will match x86_64 libs if (TargetEnvironment != llvm::Triple::GNUX32 && - llvm::sys::fs::exists(SysRoot + "/lib/x86_64-linux-gnu")) + D.getVFS().exists(SysRoot + "/lib/x86_64-linux-gnu")) return "x86_64-linux-gnu"; break; case llvm::Triple::aarch64: - if (llvm::sys::fs::exists(SysRoot + "/lib/aarch64-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/aarch64-linux-gnu")) return "aarch64-linux-gnu"; break; case llvm::Triple::aarch64_be: - if (llvm::sys::fs::exists(SysRoot + "/lib/aarch64_be-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/aarch64_be-linux-gnu")) return "aarch64_be-linux-gnu"; break; case llvm::Triple::mips: - if (llvm::sys::fs::exists(SysRoot + "/lib/mips-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/mips-linux-gnu")) return "mips-linux-gnu"; break; case llvm::Triple::mipsel: - if (llvm::sys::fs::exists(SysRoot + "/lib/mipsel-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/mipsel-linux-gnu")) return "mipsel-linux-gnu"; break; case llvm::Triple::mips64: - if (llvm::sys::fs::exists(SysRoot + "/lib/mips64-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/mips64-linux-gnu")) return "mips64-linux-gnu"; - if (llvm::sys::fs::exists(SysRoot + "/lib/mips64-linux-gnuabi64")) + if (D.getVFS().exists(SysRoot + "/lib/mips64-linux-gnuabi64")) return "mips64-linux-gnuabi64"; break; case llvm::Triple::mips64el: - if (llvm::sys::fs::exists(SysRoot + "/lib/mips64el-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/mips64el-linux-gnu")) return "mips64el-linux-gnu"; - if (llvm::sys::fs::exists(SysRoot + "/lib/mips64el-linux-gnuabi64")) + if (D.getVFS().exists(SysRoot + "/lib/mips64el-linux-gnuabi64")) return "mips64el-linux-gnuabi64"; break; case llvm::Triple::ppc: - if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc-linux-gnuspe")) + if (D.getVFS().exists(SysRoot + "/lib/powerpc-linux-gnuspe")) return "powerpc-linux-gnuspe"; - if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/powerpc-linux-gnu")) return "powerpc-linux-gnu"; break; case llvm::Triple::ppc64: - if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc64-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/powerpc64-linux-gnu")) return "powerpc64-linux-gnu"; break; case llvm::Triple::ppc64le: - if (llvm::sys::fs::exists(SysRoot + "/lib/powerpc64le-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/powerpc64le-linux-gnu")) return "powerpc64le-linux-gnu"; break; case llvm::Triple::sparc: - if (llvm::sys::fs::exists(SysRoot + "/lib/sparc-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/sparc-linux-gnu")) return "sparc-linux-gnu"; break; case llvm::Triple::sparcv9: - if (llvm::sys::fs::exists(SysRoot + "/lib/sparc64-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/sparc64-linux-gnu")) return "sparc64-linux-gnu"; break; case llvm::Triple::systemz: - if (llvm::sys::fs::exists(SysRoot + "/lib/s390x-linux-gnu")) + if (D.getVFS().exists(SysRoot + "/lib/s390x-linux-gnu")) return "s390x-linux-gnu"; break; } @@ -3294,8 +3298,8 @@ 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(D, Triple, Args); - CudaInstallation.init(D, Triple, Args); + GCCInstallation.init(Triple, Args); + CudaInstallation.init(Triple, Args); Multilibs = GCCInstallation.getMultilibs(); llvm::Triple::ArchType Arch = Triple.getArch(); std::string SysRoot = computeSysRoot(); @@ -3315,7 +3319,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) Linker = GetLinkerPath(); - Distro Distro = DetectDistro(Arch); + Distro Distro = DetectDistro(D, Arch); if (IsOpenSUSE(Distro) || IsUbuntu(Distro)) { ExtraOpts.push_back("-z"); @@ -3365,7 +3369,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) path_list &Paths = getFilePaths(); const std::string OSLibDir = getOSLibDir(Triple, Args); - const std::string MultiarchTriple = getMultiarchTriple(Triple, SysRoot); + const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot); // Add the multilib suffixed paths where they are available. if (GCCInstallation.isValid()) { @@ -3375,7 +3379,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // Sourcery CodeBench MIPS toolchain holds some libraries under // a biarch-like suffix of the GCC installation. - addPathIfExists((GCCInstallation.getInstallPath() + Multilib.gccSuffix()), + addPathIfExists(D, GCCInstallation.getInstallPath() + Multilib.gccSuffix(), Paths); // GCC cross compiling toolchains will install target libraries which ship @@ -3396,8 +3400,8 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // // Note that this matches the GCC behavior. See the below comment for where // Clang diverges from GCC's behavior. - addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib/../" + OSLibDir + - Multilib.osSuffix(), + addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib/../" + + OSLibDir + Multilib.osSuffix(), Paths); // If the GCC installation we found is inside of the sysroot, we want to @@ -3410,8 +3414,8 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // configurations but this seems somewhere between questionable and simply // a bug. if (StringRef(LibPath).startswith(SysRoot)) { - addPathIfExists(LibPath + "/" + MultiarchTriple, Paths); - addPathIfExists(LibPath + "/../" + OSLibDir, Paths); + addPathIfExists(D, LibPath + "/" + MultiarchTriple, Paths); + addPathIfExists(D, LibPath + "/../" + OSLibDir, Paths); } } @@ -3421,27 +3425,29 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // FIXME: It's not clear whether we should use the driver's installed // directory ('Dir' below) or the ResourceDir. if (StringRef(D.Dir).startswith(SysRoot)) { - addPathIfExists(D.Dir + "/../lib/" + MultiarchTriple, Paths); - addPathIfExists(D.Dir + "/../" + OSLibDir, Paths); + addPathIfExists(D, D.Dir + "/../lib/" + MultiarchTriple, Paths); + addPathIfExists(D, D.Dir + "/../" + OSLibDir, Paths); } - addPathIfExists(SysRoot + "/lib/" + MultiarchTriple, Paths); - addPathIfExists(SysRoot + "/lib/../" + OSLibDir, Paths); - addPathIfExists(SysRoot + "/usr/lib/" + MultiarchTriple, Paths); - addPathIfExists(SysRoot + "/usr/lib/../" + OSLibDir, Paths); + addPathIfExists(D, SysRoot + "/lib/" + MultiarchTriple, Paths); + addPathIfExists(D, SysRoot + "/lib/../" + OSLibDir, Paths); + addPathIfExists(D, SysRoot + "/usr/lib/" + MultiarchTriple, Paths); + addPathIfExists(D, SysRoot + "/usr/lib/../" + OSLibDir, Paths); // Try walking via the GCC triple path in case of biarch or multiarch GCC // installations with strange symlinks. if (GCCInstallation.isValid()) { - addPathIfExists(SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() + + addPathIfExists(D, + SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() + "/../../" + OSLibDir, Paths); // Add the 'other' biarch variant path Multilib BiarchSibling; if (GCCInstallation.getBiarchSibling(BiarchSibling)) { - addPathIfExists( - GCCInstallation.getInstallPath() + BiarchSibling.gccSuffix(), Paths); + addPathIfExists(D, GCCInstallation.getInstallPath() + + BiarchSibling.gccSuffix(), + Paths); } // See comments above on the multilib variant for details of why this is @@ -3449,14 +3455,14 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) const std::string &LibPath = GCCInstallation.getParentLibPath(); const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); const Multilib &Multilib = GCCInstallation.getMultilib(); - addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib" + - Multilib.osSuffix(), + addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib" + + Multilib.osSuffix(), Paths); // See comments above on the multilib variant for details of why this is // only included from within the sysroot. if (StringRef(LibPath).startswith(SysRoot)) - addPathIfExists(LibPath, Paths); + addPathIfExists(D, LibPath, Paths); } // Similar to the logic for GCC above, if we are currently running Clang @@ -3465,10 +3471,10 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // FIXME: It's not clear whether we should use the driver's installed // directory ('Dir' below) or the ResourceDir. if (StringRef(D.Dir).startswith(SysRoot)) - addPathIfExists(D.Dir + "/../lib", Paths); + addPathIfExists(D, D.Dir + "/../lib", Paths); - addPathIfExists(SysRoot + "/lib", Paths); - addPathIfExists(SysRoot + "/usr/lib", Paths); + addPathIfExists(D, SysRoot + "/lib", Paths); + addPathIfExists(D, SysRoot + "/usr/lib", Paths); } bool Linux::HasNativeLLVMSupport() const { return true; } @@ -3498,12 +3504,12 @@ std::string Linux::computeSysRoot() const { (InstallDir + "/../../../../" + TripleStr + "/libc" + Multilib.osSuffix()) .str(); - if (llvm::sys::fs::exists(Path)) + if (getVFS().exists(Path)) return Path; Path = (InstallDir + "/../../../../sysroot" + Multilib.osSuffix()).str(); - if (llvm::sys::fs::exists(Path)) + if (getVFS().exists(Path)) return Path; return std::string(); @@ -3651,7 +3657,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, break; } for (StringRef Dir : MultiarchIncludeDirs) { - if (llvm::sys::fs::exists(SysRoot + Dir)) { + if (D.getVFS().exists(SysRoot + Dir)) { addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + Dir); break; } @@ -3669,11 +3675,11 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, } /// \brief Helper to add the variant paths of a libstdc++ installation. -/*static*/ bool Linux::addLibStdCXXIncludePaths( +bool Linux::addLibStdCXXIncludePaths( Twine Base, Twine Suffix, StringRef GCCTriple, StringRef GCCMultiarchTriple, StringRef TargetMultiarchTriple, Twine IncludeSuffix, - const ArgList &DriverArgs, ArgStringList &CC1Args) { - if (!llvm::sys::fs::exists(Base + Suffix)) + const ArgList &DriverArgs, ArgStringList &CC1Args) const { + if (!getVFS().exists(Base + Suffix)) return false; addSystemInclude(DriverArgs, CC1Args, Base + Suffix); @@ -3682,7 +3688,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, // that path exists or we have neither a GCC nor target multiarch triple, use // this vanilla search path. if ((GCCMultiarchTriple.empty() && TargetMultiarchTriple.empty()) || - llvm::sys::fs::exists(Base + Suffix + "/" + GCCTriple + IncludeSuffix)) { + getVFS().exists(Base + Suffix + "/" + GCCTriple + IncludeSuffix)) { addSystemInclude(DriverArgs, CC1Args, Base + Suffix + "/" + GCCTriple + IncludeSuffix); } else { @@ -3720,7 +3726,7 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, // FIXME: We should really remove this. It doesn't make any sense. getDriver().SysRoot + "/usr/include/c++/v1"}; for (const auto &IncludePath : LibCXXIncludePathCandidates) { - if (!llvm::sys::fs::exists(IncludePath)) + if (!getVFS().exists(IncludePath)) continue; // Add the first candidate that exists. addSystemInclude(DriverArgs, CC1Args, IncludePath); @@ -3741,10 +3747,10 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, StringRef InstallDir = GCCInstallation.getInstallPath(); StringRef TripleStr = GCCInstallation.getTriple().str(); const Multilib &Multilib = GCCInstallation.getMultilib(); - const std::string GCCMultiarchTriple = - getMultiarchTriple(GCCInstallation.getTriple(), getDriver().SysRoot); + const std::string GCCMultiarchTriple = getMultiarchTriple( + getDriver(), GCCInstallation.getTriple(), getDriver().SysRoot); const std::string TargetMultiarchTriple = - getMultiarchTriple(getTriple(), getDriver().SysRoot); + getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot); const GCCVersion &Version = GCCInstallation.getVersion(); // The primary search for libstdc++ supports multiarch variants. @@ -3821,7 +3827,7 @@ DragonFly::DragonFly(const Driver &D, const llvm::Triple &Triple, getFilePaths().push_back(getDriver().Dir + "/../lib"); getFilePaths().push_back("/usr/lib"); - if (llvm::sys::fs::exists("/usr/lib/gcc47")) + if (D.getVFS().exists("/usr/lib/gcc47")) getFilePaths().push_back("/usr/lib/gcc47"); else getFilePaths().push_back("/usr/lib/gcc44"); @@ -3973,7 +3979,7 @@ MyriadToolChain::MyriadToolChain(const Driver &D, const llvm::Triple &Triple, case llvm::Triple::sparc: case llvm::Triple::sparcel: case llvm::Triple::shave: - GCCInstallation.init(D, Triple, Args, {"sparc-myriad-elf"}); + GCCInstallation.init(Triple, Args, {"sparc-myriad-elf"}); } } diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 55b2bf9095..ee571dbc0a 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -78,6 +78,7 @@ public: class GCCInstallationDetector { bool IsValid; llvm::Triple GCCTriple; + const Driver &D; // FIXME: These might be better as path objects. std::string GCCInstallPath; @@ -99,9 +100,8 @@ public: MultilibSet Multilibs; public: - GCCInstallationDetector() : IsValid(false) {} - void init(const Driver &D, const llvm::Triple &TargetTriple, - const llvm::opt::ArgList &Args, + explicit GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {} + void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args, ArrayRef ExtraTripleAliases = None); /// \brief Check whether we detected a valid GCC install. @@ -161,15 +161,15 @@ protected: class CudaInstallationDetector { bool IsValid; + const Driver &D; std::string CudaInstallPath; std::string CudaLibPath; std::string CudaLibDevicePath; std::string CudaIncludePath; public: - CudaInstallationDetector() : IsValid(false) {} - void init(const Driver &D, const llvm::Triple &TargetTriple, - const llvm::opt::ArgList &Args); + CudaInstallationDetector(const Driver &D) : IsValid(false), D(D) {} + void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args); /// \brief Check whether we detected a valid Cuda install. bool isValid() const { return IsValid; } @@ -733,13 +733,12 @@ protected: Tool *buildLinker() const override; private: - static bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix, - StringRef GCCTriple, - StringRef GCCMultiarchTriple, - StringRef TargetMultiarchTriple, - Twine IncludeSuffix, - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args); + bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix, StringRef GCCTriple, + StringRef GCCMultiarchTriple, + StringRef TargetMultiarchTriple, + Twine IncludeSuffix, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; std::string computeSysRoot() const; }; @@ -777,8 +776,8 @@ public: StringRef GetGCCLibAndIncVersion() const { return GCCLibAndIncVersion.Text; } - static std::string GetGnuDir(const std::string &InstalledDir, - const llvm::opt::ArgList &Args); + std::string GetGnuDir(const std::string &InstalledDir, + const llvm::opt::ArgList &Args) const; static StringRef GetTargetCPU(const llvm::opt::ArgList &Args); diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index 649f90784e..26e767f54a 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -5955,8 +5955,7 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, const std::string MarchSuffix = "/" + MarchString; const std::string G0Suffix = "/G0"; const std::string MarchG0Suffix = MarchSuffix + G0Suffix; - const std::string RootDir = - toolchains::HexagonToolChain::GetGnuDir(D.InstalledDir, Args) + "/"; + const std::string RootDir = ToolChain.GetGnuDir(D.InstalledDir, Args) + "/"; const std::string StartFilesDir = RootDir + "hexagon/lib" + (useG0 ? MarchG0Suffix : MarchSuffix); diff --git a/unittests/Driver/CMakeLists.txt b/unittests/Driver/CMakeLists.txt index 8cc963b33a..acd0b76a12 100644 --- a/unittests/Driver/CMakeLists.txt +++ b/unittests/Driver/CMakeLists.txt @@ -3,6 +3,7 @@ set(LLVM_LINK_COMPONENTS ) add_clang_unittest(ClangDriverTests + ToolChainTest.cpp MultilibTest.cpp ) diff --git a/unittests/Driver/ToolChainTest.cpp b/unittests/Driver/ToolChainTest.cpp new file mode 100644 index 0000000000..8fddc9b6a0 --- /dev/null +++ b/unittests/Driver/ToolChainTest.cpp @@ -0,0 +1,74 @@ +//===- unittests/Driver/ToolChainTest.cpp --- ToolChain tests -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Unit tests for ToolChains. +// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/ToolChain.h" +#include "clang/Basic/DiagnosticIDs.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/VirtualFileSystem.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "llvm/Support/raw_ostream.h" +#include "gtest/gtest.h" +using namespace clang; +using namespace clang::driver; + +namespace { + +TEST(ToolChainTest, VFSGCCInstallation) { + IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); + + IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); + struct TestDiagnosticConsumer : public DiagnosticConsumer {}; + DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer); + IntrusiveRefCntPtr InMemoryFileSystem( + new vfs::InMemoryFileSystem); + Driver TheDriver("/usr/bin/clang", "arm-linux-gnueabihf", Diags, + InMemoryFileSystem); + + const char *EmptyFiles[] = { + "foo.cpp", + "/usr/bin/clang", + "/usr/lib/gcc/arm-linux-gnueabi/4.6.1/crtbegin.o", + "/usr/lib/gcc/arm-linux-gnueabi/4.6.1/crtend.o", + "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/crtbegin.o", + "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3/crtend.o", + "/usr/lib/arm-linux-gnueabi/crt1.o", + "/usr/lib/arm-linux-gnueabi/crti.o", + "/usr/lib/arm-linux-gnueabi/crtn.o", + "/usr/lib/arm-linux-gnueabihf/crt1.o", + "/usr/lib/arm-linux-gnueabihf/crti.o", + "/usr/lib/arm-linux-gnueabihf/crtn.o", + "/usr/include/arm-linux-gnueabi/.keep", + "/usr/include/arm-linux-gnueabihf/.keep", + "/lib/arm-linux-gnueabi/.keep", + "/lib/arm-linux-gnueabihf/.keep"}; + + for (const char *Path : EmptyFiles) + InMemoryFileSystem->addFile(Path, 0, + llvm::MemoryBuffer::getMemBuffer("\n")); + + std::unique_ptr C( + TheDriver.BuildCompilation({"-fsyntax-only", "foo.cpp"})); + + std::string S; + { + llvm::raw_string_ostream OS(S); + C->getDefaultToolChain().printVerboseInfo(OS); + } + EXPECT_EQ("Found candidate GCC installation: " + "/usr/lib/gcc/arm-linux-gnueabihf/4.6.3\n", + S); +} + +} // end anonymous namespace