diff options
author | Eric Christopher <echristo@gmail.com> | 2015-09-25 17:44:31 +0000 |
---|---|---|
committer | Eric Christopher <echristo@gmail.com> | 2015-09-25 17:44:31 +0000 |
commit | 74a7c5dc165376fe45d5ad5b6080bf10df4b72ea (patch) | |
tree | 11e31634e2af20d4d928b053288264fecacdf390 /clang/lib/Driver | |
parent | 0a109000705afd3dacbc1ddec29081d81ca55bae (diff) | |
download | bcm5719-llvm-74a7c5dc165376fe45d5ad5b6080bf10df4b72ea.tar.gz bcm5719-llvm-74a7c5dc165376fe45d5ad5b6080bf10df4b72ea.zip |
The Clang gcc-compatible driver (clang/tools/driver/driver.cpp) has some
logic to select an alternate target based on the executable it was
called as. For instance, if you symlink i686-linux-android-gcc to clang
and invoke it, the driver will act as though it were called with another
argument ("-target i686-linux-android"). This leads to visible effects
even in syntax-only compilations (like the ANDROID preprocessor symbol
being defined).
This behavior is not replicated for tool invocations--for instance,
clang::createInvocationFromCommandLine will not choose an alternate
target based on ArgList[0]. This means that configurations stored in
compilation databases aren't accurately replayed.
This patch separates the logic for selecting a mode flag and target from
the executable name into a new member function on ToolChain. It should
have no functional effects (but will allow other code to reuse the
target/mode selection logic).
Patch by Luke Zarko!
llvm-svn: 248592
Diffstat (limited to 'clang/lib/Driver')
-rw-r--r-- | clang/lib/Driver/ToolChain.cpp | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 570826e52af..15dd7104908 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -22,6 +22,7 @@ #include "llvm/Option/Option.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/TargetRegistry.h" using namespace clang::driver; using namespace clang; using namespace llvm::opt; @@ -88,6 +89,99 @@ const SanitizerArgs& ToolChain::getSanitizerArgs() const { return *SanitizerArguments.get(); } +namespace { +struct DriverSuffix { + const char *Suffix; + const char *ModeFlag; +}; + +const DriverSuffix *FindDriverSuffix(StringRef ProgName) { + // A list of known driver suffixes. Suffixes are compared against the + // program name in order. If there is a match, the frontend type is updated as + // necessary by applying the ModeFlag. + static const DriverSuffix DriverSuffixes[] = { + {"clang", nullptr}, + {"clang++", "--driver-mode=g++"}, + {"clang-c++", "--driver-mode=g++"}, + {"clang-cc", nullptr}, + {"clang-cpp", "--driver-mode=cpp"}, + {"clang-g++", "--driver-mode=g++"}, + {"clang-gcc", nullptr}, + {"clang-cl", "--driver-mode=cl"}, + {"cc", nullptr}, + {"cpp", "--driver-mode=cpp"}, + {"cl", "--driver-mode=cl"}, + {"++", "--driver-mode=g++"}, + }; + + for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i) + if (ProgName.endswith(DriverSuffixes[i].Suffix)) + return &DriverSuffixes[i]; + return nullptr; +} + +/// Normalize the program name from argv[0] by stripping the file extension if +/// present and lower-casing the string on Windows. +std::string normalizeProgramName(llvm::StringRef Argv0) { + std::string ProgName = llvm::sys::path::stem(Argv0); +#ifdef LLVM_ON_WIN32 + // Transform to lowercase for case insensitive file systems. + std::transform(ProgName.begin(), ProgName.end(), ProgName.begin(), ::tolower); +#endif + return ProgName; +} + +const DriverSuffix *parseDriverSuffix(StringRef ProgName) { + // Try to infer frontend type and default target from the program name by + // comparing it against DriverSuffixes in order. + + // If there is a match, the function tries to identify a target as prefix. + // E.g. "x86_64-linux-clang" as interpreted as suffix "clang" with target + // prefix "x86_64-linux". If such a target prefix is found, it may be + // added via -target as implicit first argument. + const DriverSuffix *DS = FindDriverSuffix(ProgName); + + if (!DS) { + // Try again after stripping any trailing version number: + // clang++3.5 -> clang++ + ProgName = ProgName.rtrim("0123456789."); + DS = FindDriverSuffix(ProgName); + } + + if (!DS) { + // Try again after stripping trailing -component. + // clang++-tot -> clang++ + ProgName = ProgName.slice(0, ProgName.rfind('-')); + DS = FindDriverSuffix(ProgName); + } + return DS; +} +} // anonymous namespace + +std::pair<std::string, std::string> +ToolChain::getTargetAndModeFromProgramName(StringRef PN) { + std::string ProgName = normalizeProgramName(PN); + const DriverSuffix *DS = parseDriverSuffix(ProgName); + if (!DS) + return std::make_pair("", ""); + std::string ModeFlag = DS->ModeFlag == nullptr ? "" : DS->ModeFlag; + + std::string::size_type LastComponent = + ProgName.rfind('-', ProgName.size() - strlen(DS->Suffix)); + if (LastComponent == std::string::npos) + return std::make_pair("", ModeFlag); + + // Infer target from the prefix. + StringRef Prefix(ProgName); + Prefix = Prefix.slice(0, LastComponent); + std::string IgnoredError; + std::string Target; + if (llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError)) { + Target = Prefix; + } + return std::make_pair(Target, ModeFlag); +} + StringRef ToolChain::getDefaultUniversalArchName() const { // In universal driver terms, the arch name accepted by -arch isn't exactly // the same as the ones that appear in the triple. Roughly speaking, this is |