blob: 45d5f3d5209dcf75ae0434c9003370ffb8a37acd [file] [log] [blame]
//===-- GccUtils.h --------------------------------------------------===//
//
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
//===----------------------------------------------------------------------===//
//
// Defines the GCCInstallationDetector class (helper for driver functionality).
//
//===----------------------------------------------------------------------===//
#ifndef GOLLVM_DRIVER_GCCUTILS_H
#define GOLLVM_DRIVER_GCCUTILS_H
#include "ToolChain.h"
#include "llvm/Option/ArgList.h"
namespace gnutools {
namespace gccdetect {
typedef llvm::SmallVector<std::string, 4> stringvec;
class GCCVersion;
class InspectFS;
// Gollvm relies on an installed copy of GCC to provide objects and
// libraries needed for linking. This class implements a GCC
// "installation detector" (modeled after the similarly named clang
// class), which looks for GCC bits in the expected places. This
// version is much simpler than the clang version.
//
// Expected usage model: construct a GCCInstallationDetector with
// a given set of args (target triple, etc), then invoke the init()
// routine. Once initialized it doesn't change much (expectation
// is that it will just be queried via various getters).
//
// Notes:
//
// 1) Clang's gcc detector contains a lot of very complex and thinly
// documented code for detecting and vetting "multilib" gcc
// installations (not supported here, although this code looks
// for biarch variants, such as x86 32-bit variant on x86_64).
//
// 2) Clang implements a filesystem cache to speed things up in
// the case where there are repeated "stat" calls made on files in
// a given directory (also not supported here, although in theory
// it could be added).
//
// 3) There is (apparently) a great deal of variation regarding
// how/where GCC is installed across various Linux distributions--
// in Clang the detector includes a linux distro detector and good
// deal of complicate "fuzzy matching" logic, which is not
// replicated here (could be added later).
class GCCInstallationDetector {
public:
GCCInstallationDetector(const llvm::Triple &targetTriple,
const std::string &gccToolchainDir,
const std::string &sysroot,
InspectFS &inspector);
void init();
// Return the version of the "best" or "most suitable" installation
// of GCC on the host (or in the sysroot, depending). If no GCC
// installation is found, version.valid() will return false.
GCCVersion &version() { return *version_; }
// Return the found triple (taking into account triple aliases).
llvm::Triple foundTriple() { return foundTriple_; }
// Returns the runtime install path of the detected GCC installation, e.g.
// /usr/lib/gcc/x86_64-linux-gnu/7.
llvm::StringRef getInstallPath() { return installPath_; }
// Return the library path for the specified target (e.g.
// /usr/lib/gcc/x86_64-linux-gnu/7/32).
llvm::StringRef getLibPath() { return libPath_; }
// Return the parent of the target-specific runtime path (can
// be used to form the path of corresponding "bin" dir for
// tool selection).
llvm::StringRef getParentLibPath() { return parentLibPath_; }
// for unit testing
std::string toString();
private:
llvm::Triple triple_; // target for which we looked
llvm::Triple foundTriple_; // target we found (taking into account aliases)
std::string gccToolchainDir_;
std::string sysroot_;
InspectFS &inspector_;
std::unique_ptr<GCCVersion> version_;
std::string libPath_;
std::string installPath_;
std::string parentLibPath_;
// Opaque search state object.
struct state;
bool selectLibDirs(state &s);
void scanPrefix(state &s, const std::string &pref);
void scanCandidate(state &s, const std::string &cand,
const std::string &alias,
const std::string &suffix);
bool validCandidate(const std::string &cand,
const std::string &suffix);
};
// GCC version helper class. Given something that looks like a GCC
// version number (e.g. 4.9, 7, 8.3.mypatch), parses the string into
// major and minor numbers plus any "remainder". A gcc version is
// considered valid if it has a parseable major version number of 4 or
// later.
class GCCVersion {
public:
GCCVersion();
static GCCVersion parse(llvm::StringRef vtext);
std::string toString() const;
std::string text() { return text_; }
bool operator<(const GCCVersion &rhs) const;
bool valid() { return maj_ > 0; }
private:
std::string text_; // unparsed
int maj_, min_;
std::string remainder_;
};
// Abstract helper class for file system inspection. This class
// provides the "scanDir", "is_directory", and "exists" abstract
// methods, which are expects to behave the corresponding
// llvm::sys::fs:: functions behave. The purpose for having this class
// is so that we can create a mock FS inspector for unit tests.
class InspectFS {
public:
InspectFS() { }
virtual ~InspectFS() { }
virtual stringvec scanDir(const std::string &dir) = 0;
virtual bool exists(const std::string &path) = 0;
virtual bool is_directory(const std::string &path) = 0;
};
// A concrete file system inspector. No caching at the moment, could
// be added later if need be.
class InspectRealFS : public InspectFS {
public:
InspectRealFS() { }
~InspectRealFS() { }
stringvec scanDir(const std::string &dir) override;
bool is_directory(const std::string &path) override;
bool exists(const std::string &path) override;
};
} // end namespace gccdetect
} // end namespace gnutools
#endif // GOLLVM_DRIVER_GCCUTILS_H