r248592 - The Clang gcc-compatible driver (clang/tools/driver/driver.cpp) has some

Eric Christopher via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 25 10:44:31 PDT 2015


Author: echristo
Date: Fri Sep 25 12:44:31 2015
New Revision: 248592

URL: http://llvm.org/viewvc/llvm-project?rev=248592&view=rev
Log:
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!

Modified:
    cfe/trunk/include/clang/Driver/ToolChain.h
    cfe/trunk/lib/Driver/ToolChain.cpp
    cfe/trunk/tools/driver/driver.cpp

Modified: cfe/trunk/include/clang/Driver/ToolChain.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/ToolChain.h?rev=248592&r1=248591&r2=248592&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/ToolChain.h (original)
+++ cfe/trunk/include/clang/Driver/ToolChain.h Fri Sep 25 12:44:31 2015
@@ -151,6 +151,20 @@ public:
   // Returns the RTTIMode for the toolchain with the current arguments.
   RTTIMode getRTTIMode() const { return CachedRTTIMode; }
 
+  /// \brief Return any implicit target and/or mode flag for an invocation of
+  /// the compiler driver as `ProgName`.
+  ///
+  /// For example, when called with i686-linux-android-g++, the first element
+  /// of the return value will be set to `"i686-linux-android"` and the second
+  /// will be set to "--driver-mode=g++"`.
+  ///
+  /// \pre `llvm::InitializeAllTargets()` has been called.
+  /// \param ProgName The name the Clang driver was invoked with (from,
+  /// e.g., argv[0])
+  /// \return A pair of (`target`, `mode-flag`), where one or both may be empty.
+  static std::pair<std::string, std::string>
+  getTargetAndModeFromProgramName(StringRef ProgName);
+
   // Tool access.
 
   /// TranslateArgs - Create a new derived argument list for any argument

Modified: cfe/trunk/lib/Driver/ToolChain.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/ToolChain.cpp?rev=248592&r1=248591&r2=248592&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/ToolChain.cpp (original)
+++ cfe/trunk/lib/Driver/ToolChain.cpp Fri Sep 25 12:44:31 2015
@@ -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::getSanit
   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

Modified: cfe/trunk/tools/driver/driver.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/driver/driver.cpp?rev=248592&r1=248591&r2=248592&view=diff
==============================================================================
--- cfe/trunk/tools/driver/driver.cpp (original)
+++ cfe/trunk/tools/driver/driver.cpp Fri Sep 25 12:44:31 2015
@@ -18,6 +18,7 @@
 #include "clang/Driver/Driver.h"
 #include "clang/Driver/DriverDiagnostic.h"
 #include "clang/Driver/Options.h"
+#include "clang/Driver/ToolChain.h"
 #include "clang/Frontend/ChainedDiagnosticConsumer.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Frontend/SerializedDiagnosticPrinter.h"
@@ -44,7 +45,6 @@
 #include "llvm/Support/Regex.h"
 #include "llvm/Support/Signals.h"
 #include "llvm/Support/StringSaver.h"
-#include "llvm/Support/TargetRegistry.h"
 #include "llvm/Support/TargetSelect.h"
 #include "llvm/Support/Timer.h"
 #include "llvm/Support/raw_ostream.h"
@@ -201,101 +201,22 @@ extern int cc1_main(ArrayRef<const char
 extern int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0,
                       void *MainAddr);
 
-struct DriverSuffix {
-  const char *Suffix;
-  const char *ModeFlag;
-};
-
-static 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 if 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.
-static std::string normalizeProgramName(const char *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;
-}
-
-static 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, is gets 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;
-}
-
-static void insertArgsFromProgramName(StringRef ProgName,
-                                      const DriverSuffix *DS,
-                                      SmallVectorImpl<const char *> &ArgVector,
-                                      std::set<std::string> &SavedStrings) {
-  if (!DS)
-    return;
-
-  if (const char *Flag = DS->ModeFlag) {
-    // Add Flag to the arguments.
+static void insertTargetAndModeArgs(StringRef Target, StringRef Mode,
+                                    SmallVectorImpl<const char *> &ArgVector,
+                                    std::set<std::string> &SavedStrings) {
+  if (!Mode.empty()) {
+    // Add the mode flag to the arguments.
     auto it = ArgVector.begin();
     if (it != ArgVector.end())
       ++it;
-    ArgVector.insert(it, Flag);
+    ArgVector.insert(it, GetStableCStr(SavedStrings, Mode));
   }
 
-  StringRef::size_type LastComponent = ProgName.rfind(
-      '-', ProgName.size() - strlen(DS->Suffix));
-  if (LastComponent == StringRef::npos)
-    return;
-
-  // Infer target from the prefix.
-  StringRef Prefix = ProgName.slice(0, LastComponent);
-  std::string IgnoredError;
-  if (llvm::TargetRegistry::lookupTarget(Prefix, IgnoredError)) {
+  if (!Target.empty()) {
     auto it = ArgVector.begin();
     if (it != ArgVector.end())
       ++it;
-    const char *arr[] = { "-target", GetStableCStr(SavedStrings, Prefix) };
+    const char *arr[] = {"-target", GetStableCStr(SavedStrings, Target)};
     ArgVector.insert(it, std::begin(arr), std::end(arr));
   }
 }
@@ -402,8 +323,10 @@ int main(int argc_, const char **argv_)
     return 1;
   }
 
-  std::string ProgName = normalizeProgramName(argv[0]);
-  const DriverSuffix *DS = parseDriverSuffix(ProgName);
+  llvm::InitializeAllTargets();
+  std::string ProgName = argv[0];
+  std::pair<std::string, std::string> TargetAndMode =
+      ToolChain::getTargetAndModeFromProgramName(ProgName);
 
   llvm::BumpPtrAllocator A;
   llvm::StringSaver Saver(A);
@@ -416,7 +339,7 @@ int main(int argc_, const char **argv_)
   // Finally, our -cc1 tools don't care which tokenization mode we use because
   // response files written by clang will tokenize the same way in either mode.
   llvm::cl::TokenizerCallback Tokenizer = &llvm::cl::TokenizeGNUCommandLine;
-  if ((DS && DS->ModeFlag && strcmp(DS->ModeFlag, "--driver-mode=cl") == 0) ||
+  if (TargetAndMode.second == "--driver-mode=cl" ||
       std::find_if(argv.begin(), argv.end(), [](const char *F) {
         return F && strcmp(F, "--driver-mode=cl") == 0;
       }) != argv.end()) {
@@ -511,8 +434,8 @@ int main(int argc_, const char **argv_)
   Driver TheDriver(Path, llvm::sys::getDefaultTargetTriple(), Diags);
   SetInstallDir(argv, TheDriver, CanonicalPrefixes);
 
-  llvm::InitializeAllTargets();
-  insertArgsFromProgramName(ProgName, DS, argv, SavedStrings);
+  insertTargetAndModeArgs(TargetAndMode.first, TargetAndMode.second, argv,
+                          SavedStrings);
 
   SetBackdoorDriverOutputsFromEnvVars(TheDriver);
 




More information about the cfe-commits mailing list