[lld] r178798 - [Driver] Fix symlinked universal driver behavior and add a test.

Michael J. Spencer bigcheesegs at gmail.com
Thu Apr 4 15:04:16 PDT 2013


Author: mspencer
Date: Thu Apr  4 17:04:16 2013
New Revision: 178798

URL: http://llvm.org/viewvc/llvm-project?rev=178798&view=rev
Log:
[Driver] Fix symlinked universal driver behavior and add a test.

Added:
    lld/trunk/unittests/CoreTests/
    lld/trunk/unittests/CoreTests/CMakeLists.txt
    lld/trunk/unittests/CoreTests/RangeTest.cpp
      - copied, changed from r178788, lld/trunk/unittests/RangeTest.cpp
    lld/trunk/unittests/DriverTests/
    lld/trunk/unittests/DriverTests/CMakeLists.txt
    lld/trunk/unittests/DriverTests/UniversalDriverTest.cpp
Removed:
    lld/trunk/unittests/RangeTest.cpp
Modified:
    lld/trunk/include/lld/Driver/Driver.h
    lld/trunk/lib/Driver/UniversalDriver.cpp
    lld/trunk/unittests/CMakeLists.txt

Modified: lld/trunk/include/lld/Driver/Driver.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Driver/Driver.h?rev=178798&r1=178797&r2=178798&view=diff
==============================================================================
--- lld/trunk/include/lld/Driver/Driver.h (original)
+++ lld/trunk/include/lld/Driver/Driver.h Thu Apr  4 17:04:16 2013
@@ -48,21 +48,11 @@ private:
 class UniversalDriver : public Driver {
 public:
   /// Determine flavor and pass control to Driver for that flavor.
-  static bool link(int argc, const char *argv[]);
+  static bool link(int argc, const char *argv[],
+                   raw_ostream &diagnostics = llvm::errs());
 
 private:
   UniversalDriver() LLVM_DELETED_FUNCTION; 
-
-  enum class Flavor {
-    invalid,
-    gnu_ld,       // -flavor gnu
-    win_link,     // -flavor link
-    darwin_ld,    // -flavor darwin
-    core          // -flavor core OR -core
-  };
-
-  static Flavor selectFlavor(std::vector<const char*> &args);
-  static Flavor strToFlavor(StringRef str);
 };
 
 

Modified: lld/trunk/lib/Driver/UniversalDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/UniversalDriver.cpp?rev=178798&r1=178797&r2=178798&view=diff
==============================================================================
--- lld/trunk/lib/Driver/UniversalDriver.cpp (original)
+++ lld/trunk/lib/Driver/UniversalDriver.cpp Thu Apr  4 17:04:16 2013
@@ -14,96 +14,120 @@
 //===----------------------------------------------------------------------===//
 
 #include "lld/Driver/Driver.h"
-#include "lld/ReaderWriter/MachOTargetInfo.h"
 
-#include "llvm/ADT/ArrayRef.h"
+#include "lld/Core/LLVM.h"
+
 #include "llvm/ADT/StringExtras.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/Option/Arg.h"
-#include "llvm/Option/Option.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/FileSystem.h"
+#include "llvm/ADT/StringSwitch.h"
 #include "llvm/Support/Host.h"
-#include "llvm/Support/ManagedStatic.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Signals.h"
-
-#include <memory>
 
-namespace lld {
+using namespace lld;
 
+namespace {
+enum class Flavor {
+  invalid,
+  gnu_ld,       // -flavor gnu
+  win_link,     // -flavor link
+  darwin_ld,    // -flavor darwin
+  core          // -flavor core OR -core
+};
 
-bool UniversalDriver::link(int argc, const char *argv[]) {
-  // Convert argv[] C-array to vector.
-  std::vector<const char *> args;
-  args.assign(&argv[0], &argv[argc]);
-  
-  // Determine flavor of link based on command name or -flavor argument.
-  // Note: 'args' is modified to remove -flavor option.
-  Flavor flavor = selectFlavor(args);
-  
-  // Switch to appropriate driver.
-  switch (flavor) {
-  case Flavor::gnu_ld:
-    return GnuLdDriver::linkELF(args.size(), &args[0]);
-  case Flavor::darwin_ld:
-    return DarwinLdDriver::linkMachO(args.size(), &args[0]);
-  case Flavor::core:
-    return CoreDriver::link(args.size(), &args[0]);
-  case Flavor::win_link:
-    llvm_unreachable("Unsupported flavor");
-  case Flavor::invalid:
-    return true;
-  }
+Flavor strToFlavor(StringRef str) {
+  return llvm::StringSwitch<Flavor>(str)
+           .Case("gnu", Flavor::gnu_ld)
+           .Case("link", Flavor::win_link)
+           .Case("darwin", Flavor::darwin_ld)
+           .Case("core", Flavor::core)
+           .Case("ld", Flavor::gnu_ld) // deprecated
+           .Default(Flavor::invalid);
 }
 
+struct ProgramNameParts {
+  StringRef _target;
+  StringRef _flavor;
+};
+
+ProgramNameParts parseProgramName(StringRef programName) {
+  SmallVector<StringRef, 3> components;
+  llvm::SplitString(programName, components, "-");
+  ProgramNameParts ret;
 
+  using std::begin;
+  using std::end;
+
+  // Erase any lld components.
+  components.erase(std::remove(components.begin(), components.end(), "lld"),
+                   components.end());
+
+  // Find the flavor component.
+  auto flIter = std::find_if(components.begin(), components.end(),
+                             [](StringRef str)->bool {
+    return strToFlavor(str) != Flavor::invalid;
+  });
+
+  if (flIter != components.end()) {
+    ret._flavor = *flIter;
+    components.erase(flIter);
+  }
 
+  // Any remaining component must be the target.
+  if (components.size() == 1)
+    ret._target = components[0];
 
+  return ret;
+}
 
-/// Pick the flavor of driver to use based on the command line and
-/// host environment.
-UniversalDriver::Flavor UniversalDriver::selectFlavor(
-                                              std::vector<const char*> &args) {
+Flavor selectFlavor(std::vector<const char *> &args, raw_ostream &diag) {
   // -core as first arg is shorthand for -flavor core.
-  if (args.size() >= 1 && StringRef(args[1]) == "-core") {
+  if (args.size() > 1 && StringRef(args[1]) == "-core") {
     args.erase(args.begin() + 1);
     return Flavor::core;
   }
   // Handle -flavor as first arg.
-  if (args.size() >= 2 && StringRef(args[1]) == "-flavor") {
+  if (args.size() > 2 && StringRef(args[1]) == "-flavor") {
     Flavor flavor = strToFlavor(args[2]);
     args.erase(args.begin() + 1);
     args.erase(args.begin() + 1);
     if (flavor == Flavor::invalid)
-      llvm::errs() << "error: '" << args[2] << "' invalid value for -flavor.\n";
+      diag << "error: '" << args[2] << "' invalid value for -flavor.\n";
     return flavor;
   }
 
-  // Check if flavor is at end of program name (e.g. "lld-gnu");
-  SmallVector<StringRef, 3> components;
-  llvm::SplitString(args[0], components, "-");
-  Flavor flavor = strToFlavor(components.back());
-  
+  Flavor flavor =
+      strToFlavor(parseProgramName(llvm::sys::path::stem(args[0]))._flavor);
+
   // If flavor still undetermined, then error out.
   if (flavor == Flavor::invalid)
-    llvm::errs() << "error: failed to determine driver flavor from program name"
-                    " '" << args[0] << "'.\n";
+    diag << "error: failed to determine driver flavor from program name"
+            " '" << args[0] << "'.\n";
   return flavor;
 }
-
-/// Maps flavor strings to Flavor enum values.
-UniversalDriver::Flavor UniversalDriver::strToFlavor(StringRef str) {
-  return llvm::StringSwitch<Flavor>(str)
-           .Case("gnu",    Flavor::gnu_ld)
-           .Case("darwin", Flavor::darwin_ld)
-           .Case("link",   Flavor::win_link)
-           .Case("core",   Flavor::core)
-           .Case("ld",     Flavor::gnu_ld) // deprecated
-           .Default(Flavor::invalid);
 }
 
+namespace lld {
+bool UniversalDriver::link(int argc, const char *argv[],
+                           raw_ostream &diagnostics) {
+  // Convert argv[] C-array to vector.
+  std::vector<const char *> args(argv, argv + argc);
+
+  // Determine flavor of link based on command name or -flavor argument.
+  // Note: 'args' is modified to remove -flavor option.
+  Flavor flavor = selectFlavor(args, diagnostics);
 
-} // namespace lld
+  // Switch to appropriate driver.
+  switch (flavor) {
+  case Flavor::gnu_ld:
+    return GnuLdDriver::linkELF(args.size(), args.data(), diagnostics);
+  case Flavor::darwin_ld:
+    return DarwinLdDriver::linkMachO(args.size(), args.data(), diagnostics);
+  case Flavor::core:
+    return CoreDriver::link(args.size(), args.data(), diagnostics);
+  case Flavor::win_link:
+    llvm_unreachable("Unsupported flavor");
+  case Flavor::invalid:
+    return true;
+  }
+}
+} // end namespace lld

Modified: lld/trunk/unittests/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/CMakeLists.txt?rev=178798&r1=178797&r2=178798&view=diff
==============================================================================
--- lld/trunk/unittests/CMakeLists.txt (original)
+++ lld/trunk/unittests/CMakeLists.txt Thu Apr  4 17:04:16 2013
@@ -7,12 +7,8 @@ set_target_properties(LLDUnitTests PROPE
 # Produces a binary named 'basename(test_dirname)'.
 function(add_lld_unittest test_dirname)
   add_unittest(LLDUnitTests ${test_dirname} ${ARGN})
+  target_link_libraries(${test_dirname} ${LLVM_COMMON_LIBS})
 endfunction()
 
-set(LLVM_LINK_COMPONENTS
-    support
-    )
-
-add_lld_unittest(CoreTests
-  RangeTest.cpp
-  )
+add_subdirectory(CoreTests)
+add_subdirectory(DriverTests)

Added: lld/trunk/unittests/CoreTests/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/CoreTests/CMakeLists.txt?rev=178798&view=auto
==============================================================================
--- lld/trunk/unittests/CoreTests/CMakeLists.txt (added)
+++ lld/trunk/unittests/CoreTests/CMakeLists.txt Thu Apr  4 17:04:16 2013
@@ -0,0 +1,3 @@
+add_lld_unittest(CoreTests
+  RangeTest.cpp
+  )

Copied: lld/trunk/unittests/CoreTests/RangeTest.cpp (from r178788, lld/trunk/unittests/RangeTest.cpp)
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/CoreTests/RangeTest.cpp?p2=lld/trunk/unittests/CoreTests/RangeTest.cpp&p1=lld/trunk/unittests/RangeTest.cpp&r1=178788&r2=178798&rev=178798&view=diff
==============================================================================
    (empty)

Added: lld/trunk/unittests/DriverTests/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/DriverTests/CMakeLists.txt?rev=178798&view=auto
==============================================================================
--- lld/trunk/unittests/DriverTests/CMakeLists.txt (added)
+++ lld/trunk/unittests/DriverTests/CMakeLists.txt Thu Apr  4 17:04:16 2013
@@ -0,0 +1,7 @@
+add_lld_unittest(DriverTests
+  UniversalDriverTest.cpp
+  )
+
+target_link_libraries(DriverTests
+  lldDriver
+  )

Added: lld/trunk/unittests/DriverTests/UniversalDriverTest.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/DriverTests/UniversalDriverTest.cpp?rev=178798&view=auto
==============================================================================
--- lld/trunk/unittests/DriverTests/UniversalDriverTest.cpp (added)
+++ lld/trunk/unittests/DriverTests/UniversalDriverTest.cpp Thu Apr  4 17:04:16 2013
@@ -0,0 +1,35 @@
+//===- lld/unittest/UniversalDriverTest.cpp -------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Universal driver tests that depend on the value of argv[0].
+///
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "lld/Driver/Driver.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace lld;
+
+TEST(UniversalDriver, flavor) {
+  const char *args[] = { "ld" };
+
+  std::string diags;
+  raw_string_ostream os(diags);
+  UniversalDriver::link(array_lengthof(args), args, os);
+  EXPECT_EQ(os.str().find("failed to determine driver flavor"),
+            std::string::npos);
+  EXPECT_NE(os.str().find("No input files"),
+            std::string::npos);
+}

Removed: lld/trunk/unittests/RangeTest.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/RangeTest.cpp?rev=178797&view=auto
==============================================================================
--- lld/trunk/unittests/RangeTest.cpp (original)
+++ lld/trunk/unittests/RangeTest.cpp (removed)
@@ -1,245 +0,0 @@
-//===- lld/unittest/RangeTest.cpp -----------------------------------------===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// \brief range.h unit tests.
-///
-//===----------------------------------------------------------------------===//
-
-#include "gtest/gtest.h"
-
-#include "lld/Core/range.h"
-
-#include <assert.h>
-#include <array>
-#include <deque>
-#include <forward_list>
-#include <iterator>
-#include <list>
-#include <numeric>
-#include <sstream>
-#include <vector>
-
-template <typename T, typename U> struct AssertTypesSame;
-template <typename T> struct AssertTypesSame<T, T> {};
-#define ASSERT_TYPES_SAME(T, U) AssertTypesSame<T, U>()
-
-struct no_begin {};
-struct member_begin {
-  int *begin();
-};
-struct free_begin {};
-int *begin(free_begin);
-
-template <typename T>
-auto type_of_forward(T &&t) -> decltype(std::forward<T>(t)) {
-  return std::forward<T>(t);
-}
-
-template <typename To> To implicit_cast(To val) { return val; }
-
-void test_traits() {
-  using namespace lld::detail;
-  ASSERT_TYPES_SAME(begin_result<no_begin>::type, undefined);
-  // This causes clang to segfault.
-#if 0
-  ASSERT_TYPES_SAME(
-      begin_result<decltype(type_of_forward(member_begin()))>::type, int *);
-#endif
-  ASSERT_TYPES_SAME(begin_result<free_begin>::type, int *);
-}
-
-TEST(Range, constructors) {
-  std::vector<int> v(5);
-  std::iota(v.begin(), v.end(), 0);
-  lld::range<std::vector<int>::iterator> r = v;
-  EXPECT_EQ(v.begin(), r.begin());
-  EXPECT_EQ(v.end(), r.end());
-
-  int arr[] = { 1, 2, 3, 4, 5 };
-  std::begin(arr);
-  lld::range<int *> r2 = arr;
-  EXPECT_EQ(5, r2.back());
-}
-
-TEST(Range, conversion_to_pointer_range) {
-  std::vector<int> v(5);
-  std::iota(v.begin(), v.end(), 0);
-  lld::range<int *> r = v;
-  EXPECT_EQ(&*v.begin(), r.begin());
-  EXPECT_EQ(2, r[2]);
-}
-
-template <typename Iter> void takes_range(lld::range<Iter> r) {
-  int expected = 0;
-  for (int val : r) {
-    EXPECT_EQ(expected++, val);
-  }
-}
-
-void takes_ptr_range(lld::range<const int *> r) {
-  int expected = 0;
-  for (int val : r) {
-    EXPECT_EQ(expected++, val);
-  }
-}
-
-TEST(Range, passing) {
-  using lld::make_range;
-  using lld::make_ptr_range;
-  std::list<int> l(5);
-  std::iota(l.begin(), l.end(), 0);
-  takes_range(make_range(l));
-  takes_range(make_range(implicit_cast<const std::list<int> &>(l)));
-  std::deque<int> d(5);
-  std::iota(d.begin(), d.end(), 0);
-  takes_range(make_range(d));
-  takes_range(make_range(implicit_cast<const std::deque<int> &>(d)));
-  std::vector<int> v(5);
-  std::iota(v.begin(), v.end(), 0);
-  takes_range(make_range(v));
-  takes_range(make_range(implicit_cast<const std::vector<int> &>(v)));
-  // MSVC Can't compile make_ptr_range.
-#ifndef _MSC_VER
-  static_assert(
-      std::is_same<decltype(make_ptr_range(v)), lld::range<int *> >::value,
-      "make_ptr_range should return a range of pointers");
-  takes_range(make_ptr_range(v));
-  takes_range(make_ptr_range(implicit_cast<const std::vector<int> &>(v)));
-#endif
-  int arr[] = { 0, 1, 2, 3, 4 };
-  takes_range(make_range(arr));
-  const int carr[] = { 0, 1, 2, 3, 4 };
-  takes_range(make_range(carr));
-
-  takes_ptr_range(v);
-  takes_ptr_range(implicit_cast<const std::vector<int> &>(v));
-  takes_ptr_range(arr);
-  takes_ptr_range(carr);
-}
-
-TEST(Range, access) {
-  std::array<int, 5> a = { { 1, 2, 3, 4, 5 } };
-  lld::range<decltype(a.begin())> r = a;
-  EXPECT_EQ(4, r[3]);
-  EXPECT_EQ(4, r[-2]);
-}
-
-template <bool b> struct CompileAssert;
-template <> struct CompileAssert<true> {};
-
-#if __has_feature(cxx_constexpr)
-constexpr int arr[] = { 1, 2, 3, 4, 5 };
-TEST(Range, constexpr) {
-  constexpr lld::range<const int *> r(arr, arr + 5);
-  CompileAssert<r.front() == 1>();
-  CompileAssert<r.size() == 5>();
-  CompileAssert<r[4] == 5>();
-}
-#endif
-
-template <typename Container> void test_slice() {
-  Container cont(10);
-  std::iota(cont.begin(), cont.end(), 0);
-  lld::range<decltype(cont.begin())> r = cont;
-
-  // One argument.
-  EXPECT_EQ(10, r.slice(0).size());
-  EXPECT_EQ(8, r.slice(2).size());
-  EXPECT_EQ(2, r.slice(2).front());
-  EXPECT_EQ(1, r.slice(-1).size());
-  EXPECT_EQ(9, r.slice(-1).front());
-
-  // Two positive arguments.
-  EXPECT_TRUE(r.slice(5, 2).empty());
-  EXPECT_EQ(next(cont.begin(), 5), r.slice(5, 2).begin());
-  EXPECT_EQ(1, r.slice(1, 2).size());
-  EXPECT_EQ(1, r.slice(1, 2).front());
-
-  // Two negative arguments.
-  EXPECT_TRUE(r.slice(-2, -5).empty());
-  EXPECT_EQ(next(cont.begin(), 8), r.slice(-2, -5).begin());
-  EXPECT_EQ(1, r.slice(-2, -1).size());
-  EXPECT_EQ(8, r.slice(-2, -1).front());
-
-  // Positive start, negative stop.
-  EXPECT_EQ(1, r.slice(6, -3).size());
-  EXPECT_EQ(6, r.slice(6, -3).front());
-  EXPECT_TRUE(r.slice(6, -5).empty());
-  EXPECT_EQ(next(cont.begin(), 6), r.slice(6, -5).begin());
-
-  // Negative start, positive stop.
-  EXPECT_TRUE(r.slice(-3, 6).empty());
-  EXPECT_EQ(next(cont.begin(), 7), r.slice(-3, 6).begin());
-  EXPECT_EQ(1, r.slice(-5, 6).size());
-  EXPECT_EQ(5, r.slice(-5, 6).front());
-}
-
-TEST(Range, slice) {
-  // -fsanitize=undefined complains about this, but only if optimizations are
-  // enabled.
-#if 0
-  test_slice<std::forward_list<int> >();
-#endif
-  test_slice<std::list<int> >();
-  // gcc doesn't like this.
-#if !(defined(__GNUC__) && !defined(__clang__)) || defined(_MSC_VER)
-  test_slice<std::deque<int> >();
-#endif
-}
-
-// This test is flaky and I've yet to pin down why. Changing between
-// EXPECT_EQ(1, input.front()) and EXPECT_TRUE(input.front() == 1) makes it work
-// with VS 2012 in Debug mode. Clang on Linux seems to fail with -03 and -02 -g
-// -fsanitize=undefined.
-#if 0
-TEST(Range, istream_range) {
-  std::istringstream stream("1 2 3 4 5");
-  // MSVC interprets input as a function declaration if you don't declare start
-  // and instead directly pass std::istream_iterator<int>(stream).
-  auto start = std::istream_iterator<int>(stream);
-  lld::range<std::istream_iterator<int> > input(
-      start, std::istream_iterator<int>());
-  EXPECT_TRUE(input.front() == 1);
-  input.pop_front();
-  EXPECT_TRUE(input.front() == 2);
-  input.pop_front(2);
-  EXPECT_TRUE(input.front() == 4);
-  input.pop_front_upto(7);
-  EXPECT_TRUE(input.empty());
-}
-#endif
-
-//! [algorithm using range]
-template <typename T> void partial_sum(T &container) {
-  using lld::make_range;
-  auto range = make_range(container);
-  typename T::value_type sum = 0;
-  // One would actually use a range-based for loop
-  // in this case, but you get the idea:
-  for (; !range.empty(); range.pop_front()) {
-    sum += range.front();
-    range.front() = sum;
-  }
-}
-
-TEST(Range, user1) {
-  std::vector<int> v(5, 2);
-  partial_sum(v);
-  EXPECT_EQ(8, v[3]);
-}
-//! [algorithm using range]
-
-//! [algorithm using ptr_range]
-void my_write(int fd, lld::range<const char *> buffer) {}
-
-TEST(Range, user2) {
-  std::string s("Hello world");
-  my_write(1, s);
-}





More information about the llvm-commits mailing list