[llvm-commits] [lld] r169659 - in /lld/trunk: include/lld/Core/ErrorOr.h include/lld/Driver/ include/lld/Driver/Driver.h include/lld/Driver/LinkerInvocation.h include/lld/Driver/LinkerOptions.h include/lld/Driver/Target.h lib/CMakeLists.txt lib/Driver/ lib/Driver/CMakeLists.txt lib/Driver/CoreOptions.td lib/Driver/Driver.cpp lib/Driver/Drivers.cpp lib/Driver/LDOptions.td lib/Driver/LinkerInvocation.cpp lib/Driver/Target.cpp lib/Driver/Targets.cpp tools/lld/CMakeLists.txt tools/lld/lld.cpp

Nick Kledzik kledzik at apple.com
Fri Dec 7 16:58:38 PST 2012


Michael,

Is there some documentation on how to use the new options infrastructure?  

Do you plan to switch all of lld (e.g. readFile() and friends) to start using ErrorOr?

-Nick


On Dec 7, 2012, at 4:47 PM, Michael J. Spencer wrote:
> Author: mspencer
> Date: Fri Dec  7 18:47:36 2012
> New Revision: 169659
> 
> URL: http://llvm.org/viewvc/llvm-project?rev=169659&view=rev
> Log:
> Add the core architecture for the lld driver.
> 
> This includes selecting which driver to emulate, option parsing, invocation
> building, and running the link. This currently only supports a very basic
> subset of ld for x86_64-linux.
> 
> lld -flavor ld obj.o -o obj
> 
> or symlink lld as (ld , link, ld64, core) to get the desired behavior without
> -flavor.
> 
> Added:
>    lld/trunk/include/lld/Core/ErrorOr.h
>    lld/trunk/include/lld/Driver/
>    lld/trunk/include/lld/Driver/Driver.h
>    lld/trunk/include/lld/Driver/LinkerInvocation.h
>    lld/trunk/include/lld/Driver/LinkerOptions.h
>    lld/trunk/include/lld/Driver/Target.h
>    lld/trunk/lib/Driver/
>    lld/trunk/lib/Driver/CMakeLists.txt
>    lld/trunk/lib/Driver/CoreOptions.td
>    lld/trunk/lib/Driver/Driver.cpp
>    lld/trunk/lib/Driver/Drivers.cpp
>    lld/trunk/lib/Driver/LDOptions.td
>    lld/trunk/lib/Driver/LinkerInvocation.cpp
>    lld/trunk/lib/Driver/Target.cpp
>    lld/trunk/lib/Driver/Targets.cpp
> Modified:
>    lld/trunk/lib/CMakeLists.txt
>    lld/trunk/tools/lld/CMakeLists.txt
>    lld/trunk/tools/lld/lld.cpp
> 
> Added: lld/trunk/include/lld/Core/ErrorOr.h
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Core/ErrorOr.h?rev=169659&view=auto
> ==============================================================================
> --- lld/trunk/include/lld/Core/ErrorOr.h (added)
> +++ lld/trunk/include/lld/Core/ErrorOr.h Fri Dec  7 18:47:36 2012
> @@ -0,0 +1,213 @@
> +//===- lld/Core/ErrorOr.h - Error Smart Pointer ---------------------------===//
> +//
> +//                             The LLVM Linker
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +///
> +/// \file
> +///
> +/// Provides ErrorOr<T> smart pointer.
> +///
> +/// This should be moved to LLVMSupport when someone has time to make it c++03.
> +///
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLD_CORE_ERROR_OR_H
> +#define LLD_CORE_ERROR_OR_H
> +
> +#include "llvm/Support/AlignOf.h"
> +#include "llvm/Support/system_error.h"
> +
> +#include <cassert>
> +#include <type_traits>
> +
> +namespace lld {
> +template<class T>
> +class ErrorOrBase {
> +  static const bool isRef = std::is_reference<T>::value;
> +  typedef std::reference_wrapper<typename std::remove_reference<T>::type> wrap;
> +
> +public:
> +  typedef typename
> +    std::conditional< isRef
> +                    , wrap
> +                    , T
> +                    >::type storage_type;
> +
> +private:
> +  typedef T &reference;
> +  typedef typename std::remove_reference<T>::type *pointer;
> +
> +  ErrorOrBase(const ErrorOrBase&) LLVM_DELETED_FUNCTION;
> +  ErrorOrBase &operator =(const ErrorOrBase&) LLVM_DELETED_FUNCTION;
> +  ErrorOrBase(ErrorOrBase &&other) LLVM_DELETED_FUNCTION;
> +  ErrorOrBase &operator =(ErrorOrBase &&other) LLVM_DELETED_FUNCTION;
> +
> +public:
> +  ErrorOrBase() : _error(llvm::make_error_code(llvm::errc::invalid_argument)) {}
> +
> +  ErrorOrBase(llvm::error_code ec) {
> +    if (!_error)
> +      get()->~storage_type();
> +    _error = ec;
> +  }
> +
> +  ErrorOrBase(T t) : _error(llvm::error_code::success()) {
> +    new (get()) storage_type(t);
> +  }
> +
> +  ~ErrorOrBase() {
> +    if (!_error)
> +      get()->~storage_type();
> +  }
> +
> +  /// \brief Return false if there is an error.
> +  operator bool() {
> +    return !_error;
> +  }
> +
> +  operator llvm::error_code() {
> +    return _error;
> +  }
> +
> +  operator reference() {
> +    return *get();
> +  }
> +
> +  pointer operator ->() {
> +    return toPointer(get());
> +  }
> +
> +  reference operator *() {
> +    return *get();
> +  }
> +
> +private:
> +  pointer toPointer(pointer t) {
> +    return t;
> +  }
> +
> +  pointer toPointer(wrap *t) {
> +    return &t->get();
> +  }
> +
> +protected:
> +  storage_type *get() {
> +    assert(!_error && "T not valid!");
> +    return reinterpret_cast<storage_type*>(_t.buffer);
> +  }
> +
> +  llvm::error_code _error;
> +  llvm::AlignedCharArrayUnion<storage_type> _t;
> +};
> +
> +/// \brief Represents either an error or a value T.
> +///
> +/// ErrorOr<T> is a pointer-like class that represents the result of an
> +/// operation. The result is either an error, or a value of type T. This is
> +/// designed to emulate the usage of returning a pointer where nullptr indicates
> +/// failure. However instead of just knowing that the operation failed, we also
> +/// have an error_code that describes why it failed.
> +///
> +/// It is used like the following.
> +/// \code
> +///   ErrorOr<Buffer> getBuffer();
> +///   void handleError(error_code ec);
> +///
> +///   auto buffer = getBuffer();
> +///   if (!buffer)
> +///     handleError(buffer);
> +///   buffer->write("adena");
> +/// \endcode
> +///
> +/// An implicit conversion to bool provides a way to check if there was an
> +/// error. The unary * and -> operators provide pointer like access to the
> +/// value. Accessing the value when there is an error has undefined behavior.
> +///
> +/// When T is a reference type the behaivor is slightly different. The reference
> +/// is held in a std::reference_wrapper<std::remove_reference<T>::type>, and
> +/// there is special handling to make operator -> work as if T was not a
> +/// reference.
> +///
> +/// T cannot be a rvalue reference.
> +template<class T,
> +  bool isMoveable =
> +    std::is_move_constructible<typename ErrorOrBase<T>::storage_type>::value>
> +class ErrorOr;
> +
> +template<class T>
> +class ErrorOr<T, true> : public ErrorOrBase<T> {
> +  ErrorOr(const ErrorOr &other) LLVM_DELETED_FUNCTION;
> +  ErrorOr &operator =(const ErrorOr &other) LLVM_DELETED_FUNCTION;
> +public:
> +  ErrorOr(llvm::error_code ec) : ErrorOrBase<T>(ec) {}
> +  ErrorOr(T t) : ErrorOrBase<T>(t) {}
> +  ErrorOr(ErrorOr &&other) : ErrorOrBase<T>() {
> +    // Get the other value.
> +    if (!other._error)
> +      new (this->get())
> +        typename ErrorOrBase<T>::storage_type(std::move(*other.get()));
> +
> +    // Get the other error.
> +    this->_error = other._error;
> +
> +    // Make sure other doesn't try to delete its storage.
> +    other._error = llvm::make_error_code(llvm::errc::invalid_argument);
> +  }
> +
> +  ErrorOr &operator =(ErrorOr &&other) {
> +    // Delete any existing value.
> +    if (!this->_error)
> +      this->get()->~storage_type();
> +
> +    // Get the other value.
> +    if (!other._error)
> +      new (this->get())
> +        typename ErrorOrBase<T>::storage_type(std::move(*other.get()));
> +
> +    // Get the other error.
> +    this->_error = other._error;
> +
> +    // Make sure other doesn't try to delete its storage.
> +    other._error = llvm::make_error_code(llvm::errc::invalid_argument);
> +  }
> +};
> +
> +template<class T>
> +class ErrorOr<T, false> : public ErrorOrBase<T> {
> +  static_assert(std::is_copy_constructible<T>::value,
> +                "T must be copy or move constructible!");
> +
> +  ErrorOr(ErrorOr &&other) LLVM_DELETED_FUNCTION;
> +  ErrorOr &operator =(ErrorOr &&other) LLVM_DELETED_FUNCTION;
> +public:
> +  ErrorOr(llvm::error_code ec) : ErrorOrBase<T>(ec) {}
> +  ErrorOr(T t) : ErrorOrBase<T>(t) {}
> +  ErrorOr(const ErrorOr &other) : ErrorOrBase<T>() {
> +    // Get the other value.
> +    if (!other._error)
> +      new (this->get()) typename ErrorOrBase<T>::storage_type(*other.get());
> +
> +    // Get the other error.
> +    this->_error = other._error;
> +  }
> +
> +  ErrorOr &operator =(const ErrorOr &other) {
> +    // Delete any existing value.
> +    if (!this->_error)
> +      this->get()->~storage_type();
> +
> +    // Get the other value.
> +    if (!other._error)
> +      new (this->get()) typename ErrorOrBase<T>::storage_type(*other.get());
> +
> +    // Get the other error.
> +    this->_error = other._error;
> +  }
> +};
> +}
> +
> +#endif
> 
> Added: lld/trunk/include/lld/Driver/Driver.h
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Driver/Driver.h?rev=169659&view=auto
> ==============================================================================
> --- lld/trunk/include/lld/Driver/Driver.h (added)
> +++ lld/trunk/include/lld/Driver/Driver.h Fri Dec  7 18:47:36 2012
> @@ -0,0 +1,64 @@
> +//===- lld/Driver/Driver.h - Linker Driver Emulator -----------------------===//
> +//
> +//                             The LLVM Linker
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +///
> +/// \file
> +///
> +/// Interface and factory for creating a specific driver emulator. A Driver is
> +/// used to transform command line arguments into command line arguments for
> +/// core. Core arguments are used to generate a LinkerOptions object.
> +///
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLD_DRIVER_DRIVER_H
> +#define LLD_DRIVER_DRIVER_H
> +
> +#include "lld/Core/LLVM.h"
> +
> +#include "llvm/Option/ArgList.h"
> +
> +#include <memory>
> +#include <string>
> +
> +namespace lld {
> +struct LinkerOptions;
> +
> +/// \brief Base class for all Drivers.
> +class Driver {
> +protected:
> +  Driver(StringRef defaultTargetTriple)
> +    : _defaultTargetTriple(defaultTargetTriple) {}
> +
> +  std::string _defaultTargetTriple;
> +
> +public:
> +  enum class Flavor {
> +    invalid,
> +    ld,
> +    link,
> +    ld64,
> +    core
> +  };
> +
> +  virtual ~Driver();
> +
> +  virtual std::unique_ptr<llvm::opt::DerivedArgList>
> +    transform(llvm::ArrayRef<const char *const> args) = 0;
> +
> +  /// \param flavor driver flavor to create.
> +  /// \param defaultTargetTriple target triple as determined by the program name
> +  ///        or host. May be overridden by -target.
> +  /// \returns the created driver.
> +  static std::unique_ptr<Driver> create(Flavor flavor,
> +                                        StringRef defaultTargetTriple);
> +};
> +
> +LinkerOptions generateOptions(const llvm::opt::ArgList &args);
> +} // end namespace lld
> +
> +#endif
> 
> Added: lld/trunk/include/lld/Driver/LinkerInvocation.h
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Driver/LinkerInvocation.h?rev=169659&view=auto
> ==============================================================================
> --- lld/trunk/include/lld/Driver/LinkerInvocation.h (added)
> +++ lld/trunk/include/lld/Driver/LinkerInvocation.h Fri Dec  7 18:47:36 2012
> @@ -0,0 +1,34 @@
> +//===- lld/Driver/LinkerInvocation.h - Linker Invocation ------------------===//
> +//
> +//                             The LLVM Linker
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +///
> +/// \file
> +///
> +/// Drives the actual link.
> +///
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLD_DRIVER_LINKER_INVOCATION_H
> +#define LLD_DRIVER_LINKER_INVOCATION_H
> +
> +#include "lld/Driver/LinkerOptions.h"
> +
> +namespace lld {
> +class LinkerInvocation {
> +public:
> +  LinkerInvocation(const LinkerOptions &lo) : _options(lo) {}
> +
> +  /// \brief Perform the link.
> +  void operator()();
> +
> +private:
> +  const LinkerOptions &_options;
> +};
> +}
> +
> +#endif
> 
> Added: lld/trunk/include/lld/Driver/LinkerOptions.h
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Driver/LinkerOptions.h?rev=169659&view=auto
> ==============================================================================
> --- lld/trunk/include/lld/Driver/LinkerOptions.h (added)
> +++ lld/trunk/include/lld/Driver/LinkerOptions.h Fri Dec  7 18:47:36 2012
> @@ -0,0 +1,126 @@
> +//===- lld/Driver/LinkerOptions.h - Linker Options ------------------------===//
> +//
> +//                             The LLVM Linker
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +///
> +/// \file
> +///
> +/// All linker options to be provided to a LinkerInvocation.
> +///
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLD_DRIVER_LINKER_OPTIONS_H
> +#define LLD_DRIVER_LINKER_OPTIONS_H
> +
> +#include "lld/Core/ErrorOr.h"
> +#include "lld/Core/LLVM.h"
> +
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/ADT/StringSwitch.h"
> +#include "llvm/Support/Compiler.h"
> +#include "llvm/Support/FileSystem.h"
> +#include "llvm/Support/MemoryBuffer.h"
> +
> +#include <memory>
> +
> +namespace lld {
> +enum class InputKind {
> +  Unknown,
> +  YAML,
> +  Native,
> +  Object,
> +  LLVM,
> +  Script
> +};
> +
> +class LinkerInput {
> +  LinkerInput(const LinkerInput &) LLVM_DELETED_FUNCTION;
> +
> +public:
> +  LinkerInput(StringRef file, InputKind kind = InputKind::Unknown)
> +    : _file(file)
> +    , _kind(kind) {}
> +
> +  LinkerInput(llvm::MemoryBuffer *buffer, InputKind kind = InputKind::Unknown)
> +    : _buffer(buffer)
> +    , _file(_buffer->getBufferIdentifier())
> +    , _kind(kind) {}
> +
> +  LinkerInput(LinkerInput &&other)
> +    : _buffer(std::move(other._buffer))
> +    , _file(std::move(other._file))
> +    , _kind(other._kind) {}
> +
> +  ErrorOr<llvm::MemoryBuffer&> getBuffer() const {
> +    if (!_buffer) {
> +      llvm::OwningPtr<llvm::MemoryBuffer> buf;
> +      if (error_code ec = llvm::MemoryBuffer::getFileOrSTDIN(_file, buf))
> +        return ec;
> +      _buffer.reset(buf.take());
> +    }
> +
> +    return *_buffer;
> +  }
> +
> +  ErrorOr<InputKind> getKind() const {
> +    if (_kind == InputKind::Unknown) {
> +      _kind = llvm::StringSwitch<InputKind>(getPath())
> +        .EndsWith(".objtxt", InputKind::YAML)
> +        .EndsWith(".yaml", InputKind::YAML)
> +        .Default(InputKind::Unknown);
> +
> +      if (_kind != InputKind::Unknown)
> +        return _kind;
> +
> +      auto buf = getBuffer();
> +      if (!buf)
> +        return error_code(buf);
> +
> +      llvm::sys::fs::file_magic magic =
> +        llvm::sys::fs::identify_magic(buf->getBuffer());
> +
> +      switch (magic) {
> +      case llvm::sys::fs::file_magic::elf_relocatable:
> +        _kind = InputKind::Object;
> +        break;
> +      }
> +    }
> +
> +    return _kind;
> +  }
> +
> +  StringRef getPath() const {
> +    return _file;
> +  }
> +
> +private:
> +  mutable std::unique_ptr<llvm::MemoryBuffer> _buffer;
> +  std::string _file;
> +  mutable InputKind _kind;
> +};
> +
> +struct LinkerOptions {
> +  LinkerOptions() {}
> +  LinkerOptions(LinkerOptions &&other)
> +    : _input(std::move(other._input))
> +    , _target(std::move(other._target))
> +    , _outputPath(std::move(other._outputPath))
> +    , _entrySymbol(std::move(other._entrySymbol))
> +    , _relocatable(other._relocatable) {}
> +
> +  std::vector<LinkerInput> _input;
> +  std::string _target;
> +  std::string _outputPath;
> +  std::string _entrySymbol;
> +  unsigned _relocatable : 1;
> +
> +private:
> +  LinkerOptions(const LinkerOptions&) LLVM_DELETED_FUNCTION;
> +};
> +}
> +
> +#endif
> 
> Added: lld/trunk/include/lld/Driver/Target.h
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/Driver/Target.h?rev=169659&view=auto
> ==============================================================================
> --- lld/trunk/include/lld/Driver/Target.h (added)
> +++ lld/trunk/include/lld/Driver/Target.h Fri Dec  7 18:47:36 2012
> @@ -0,0 +1,46 @@
> +//===- lld/Driver/Target.h - Linker Target Abstraction --------------------===//
> +//
> +//                             The LLVM Linker
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +///
> +/// \file
> +///
> +/// Interface and factory for creating a specific Target. A Target is used to
> +/// encapsulate all of the target specific configurations for the linker.
> +///
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLD_DRIVER_TARGET_H
> +#define LLD_DRIVER_TARGET_H
> +
> +#include "lld/ReaderWriter/Reader.h"
> +#include "lld/ReaderWriter/Writer.h"
> +#include "lld/Driver/LinkerOptions.h"
> +
> +namespace lld {
> +/// \brief Represents a specific target.
> +class Target {
> +public:
> +  Target(const LinkerOptions &lo) : _options(lo) {}
> +  virtual ~Target();
> +
> +  /// \brief Get a reference to a Reader for the given input.
> +  ///
> +  /// Will always return the same object for the same input.
> +  virtual ErrorOr<lld::Reader&> getReader(const LinkerInput &input) = 0;
> +
> +  /// \brief Get the writer.
> +  virtual ErrorOr<lld::Writer&> getWriter() = 0;
> +
> +  static std::unique_ptr<Target> create(const LinkerOptions&);
> +
> +protected:
> +  const LinkerOptions &_options;
> +};
> +}
> +
> +#endif
> 
> Modified: lld/trunk/lib/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/CMakeLists.txt?rev=169659&r1=169658&r2=169659&view=diff
> ==============================================================================
> --- lld/trunk/lib/CMakeLists.txt (original)
> +++ lld/trunk/lib/CMakeLists.txt Fri Dec  7 18:47:36 2012
> @@ -1,3 +1,4 @@
> add_subdirectory(Core)
> +add_subdirectory(Driver)
> add_subdirectory(Passes)
> add_subdirectory(ReaderWriter)
> 
> Added: lld/trunk/lib/Driver/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/CMakeLists.txt?rev=169659&view=auto
> ==============================================================================
> --- lld/trunk/lib/Driver/CMakeLists.txt (added)
> +++ lld/trunk/lib/Driver/CMakeLists.txt Fri Dec  7 18:47:36 2012
> @@ -0,0 +1,29 @@
> +set(LLVM_TARGET_DEFINITIONS LDOptions.td)
> +tablegen(LLVM LDOptions.inc -gen-opt-parser-defs)
> +set(LLVM_TARGET_DEFINITIONS CoreOptions.td)
> +tablegen(LLVM CoreOptions.inc -gen-opt-parser-defs)
> +add_public_tablegen_target(DriverOptionsTableGen)
> +
> +add_lld_library(lldDriver
> +  Driver.cpp
> +  Drivers.cpp
> +  LinkerInvocation.cpp
> +  Target.cpp
> +  Targets.cpp
> +  )
> +
> +add_dependencies(lldDriver DriverOptionsTableGen)
> +
> +target_link_libraries(lldDriver
> +  lldPasses
> +  lldMachO
> +  lldPECOFF
> +  lldELF
> +  lldNative
> +  lldReaderWriter
> +  lldYAML
> +  lldCore
> +  LLVMObject
> +  LLVMOption
> +  LLVMSupport
> +  )
> 
> Added: lld/trunk/lib/Driver/CoreOptions.td
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/CoreOptions.td?rev=169659&view=auto
> ==============================================================================
> --- lld/trunk/lib/Driver/CoreOptions.td (added)
> +++ lld/trunk/lib/Driver/CoreOptions.td Fri Dec  7 18:47:36 2012
> @@ -0,0 +1,7 @@
> +include "llvm/Option/OptParser.td"
> +
> +def target : Separate<["-"], "target">, HelpText<"Target triple to link for">;
> +
> +def output : Joined<["-"], "output=">;
> +def entry : Joined<["-"], "entry=">;
> +def relocatable : Flag<["-"], "relocatable">;
> 
> Added: lld/trunk/lib/Driver/Driver.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/Driver.cpp?rev=169659&view=auto
> ==============================================================================
> --- lld/trunk/lib/Driver/Driver.cpp (added)
> +++ lld/trunk/lib/Driver/Driver.cpp Fri Dec  7 18:47:36 2012
> @@ -0,0 +1,14 @@
> +//===- lib/Driver/Driver.cpp - Linker Driver Emulator ---------------------===//
> +//
> +//                             The LLVM Linker
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "lld/Driver/Driver.h"
> +
> +using namespace lld;
> +
> +Driver::~Driver() {}
> 
> Added: lld/trunk/lib/Driver/Drivers.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/Drivers.cpp?rev=169659&view=auto
> ==============================================================================
> --- lld/trunk/lib/Driver/Drivers.cpp (added)
> +++ lld/trunk/lib/Driver/Drivers.cpp Fri Dec  7 18:47:36 2012
> @@ -0,0 +1,180 @@
> +//===- lib/Driver/Drivers.cpp - Linker Driver Emulators -------------------===//
> +//
> +//                             The LLVM Linker
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +///
> +/// \file
> +///
> +/// Concrete instances of the Driver interface.
> +///
> +//===----------------------------------------------------------------------===//
> +
> +#include "lld/Driver/Driver.h"
> +
> +#include "lld/Driver/LinkerOptions.h"
> +
> +#include "llvm/ADT/ArrayRef.h"
> +#include "llvm/ADT/STLExtras.h"
> +#include "llvm/ADT/Triple.h"
> +#include "llvm/Option/Arg.h"
> +#include "llvm/Option/Option.h"
> +#include "llvm/Support/raw_ostream.h"
> +
> +using namespace lld;
> +
> +namespace core {
> +enum ID {
> +  OPT_INVALID = 0,
> +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, HELP, META) \
> +          OPT_##ID,
> +#include "CoreOptions.inc"
> +  LastOption
> +#undef OPTION
> +};
> +
> +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#include "CoreOptions.inc"
> +#undef PREFIX
> +
> +static const llvm::opt::OptTable::Info InfoTable[] = {
> +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
> +               HELPTEXT, METAVAR)   \
> +  { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
> +    PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS },
> +#include "CoreOptions.inc"
> +#undef OPTION
> +};
> +
> +class CoreOptTable : public llvm::opt::OptTable {
> +public:
> +  CoreOptTable() : OptTable(InfoTable, llvm::array_lengthof(InfoTable)){}
> +};
> +}
> +
> +namespace ld {
> +enum LDOpt {
> +  OPT_INVALID = 0,
> +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, HELP, META) \
> +          OPT_##ID,
> +#include "LDOptions.inc"
> +  LastOption
> +#undef OPTION
> +};
> +
> +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
> +#include "LDOptions.inc"
> +#undef PREFIX
> +
> +static const llvm::opt::OptTable::Info InfoTable[] = {
> +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
> +               HELPTEXT, METAVAR)   \
> +  { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
> +    PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS },
> +#include "LDOptions.inc"
> +#undef OPTION
> +};
> +
> +class LDOptTable : public llvm::opt::OptTable {
> +public:
> +  LDOptTable() : OptTable(InfoTable, llvm::array_lengthof(InfoTable)){}
> +};
> +}
> +
> +class LDDriver final : public Driver {
> +public:
> +  LDDriver(StringRef defaultTargetTriple) : Driver(defaultTargetTriple) {}
> +
> +  virtual std::unique_ptr<llvm::opt::DerivedArgList>
> +  transform(llvm::ArrayRef<const char *const> args) {
> +    assert(!_inputArgs && "transform may only be called once!");
> +
> +    unsigned missingIndex, missingCount;
> +    _inputArgs.reset(_opt.ParseArgs( args.begin(), args.end()
> +                                   , missingIndex, missingCount));
> +
> +    if (missingCount) {
> +      llvm::errs() << "error: missing arg value for '"
> +                   << _inputArgs->getArgString(missingIndex)
> +                   << "' expected " << missingCount << " argument(s).\n";
> +      return std::unique_ptr<llvm::opt::DerivedArgList>();
> +    }
> +
> +    std::unique_ptr<llvm::opt::DerivedArgList> newArgs(
> +      new llvm::opt::DerivedArgList(*_inputArgs));
> +
> +    if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_target)) {
> +      llvm::errs() << A->getValue() << "\n";
> +      newArgs->AddSeparateArg( A, _core.getOption(core::OPT_target)
> +                             , A->getValue());
> +      llvm::errs() << A->getValue() << "\n";
> +    } else {
> +      assert(!_defaultTargetTriple.empty() && "Got empty target triple!");
> +      newArgs->AddSeparateArg(nullptr, _core.getOption(core::OPT_target)
> +                             , _defaultTargetTriple);
> +    }
> +
> +    if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_entry))
> +      newArgs->AddJoinedArg(A, _core.getOption(core::OPT_entry), A->getValue());
> +    else
> +      newArgs->AddJoinedArg(nullptr, _core.getOption(core::OPT_entry), "start");
> +
> +    if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_output))
> +      newArgs->AddJoinedArg(A, _core.getOption(core::OPT_output),
> +                            A->getValue());
> +    else
> +      newArgs->AddJoinedArg(nullptr, _core.getOption(core::OPT_output),
> +                            "a.out");
> +
> +    if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_relocatable))
> +      newArgs->AddFlagArg(A, _core.getOption(core::OPT_relocatable));
> +
> +    // Copy input args.
> +    for (llvm::opt::arg_iterator it = _inputArgs->filtered_begin(ld::OPT_INPUT),
> +                                 ie = _inputArgs->filtered_end();
> +                                 it != ie; ++it) {
> +      newArgs->AddPositionalArg(*it, _core.getOption(core::OPT_INPUT),
> +                                (*it)->getValue());
> +    }
> +
> +    return std::move(newArgs);
> +  }
> +
> +private:
> +  std::unique_ptr<llvm::opt::InputArgList> _inputArgs;
> +  core::CoreOptTable _core;
> +  ld::LDOptTable _opt;
> +};
> +
> +std::unique_ptr<Driver> Driver::create( Driver::Flavor flavor
> +                                      , StringRef defaultTargetTriple) {
> +  switch (flavor) {
> +  case Flavor::ld:
> +    return std::unique_ptr<Driver>(new LDDriver(defaultTargetTriple));
> +  case Flavor::core:
> +  case Flavor::ld64:
> +  case Flavor::link:
> +  case Flavor::invalid:
> +    llvm_unreachable("Unsupported flavor");
> +  }
> +}
> +
> +LinkerOptions lld::generateOptions(const llvm::opt::ArgList &args) {
> +  LinkerOptions ret;
> +
> +  for (llvm::opt::arg_iterator it = args.filtered_begin(ld::OPT_INPUT),
> +                               ie = args.filtered_end();
> +                               it != ie; ++it) {
> +    ret._input.push_back(LinkerInput((*it)->getValue(), InputKind::Object));
> +  }
> +
> +  ret._target = llvm::Triple::normalize(args.getLastArgValue(core::OPT_target));
> +  ret._outputPath = args.getLastArgValue(core::OPT_output);
> +  ret._entrySymbol = args.getLastArgValue(core::OPT_entry);
> +  ret._relocatable = args.hasArg(core::OPT_relocatable);
> +
> +  return std::move(ret);
> +}
> 
> Added: lld/trunk/lib/Driver/LDOptions.td
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/LDOptions.td?rev=169659&view=auto
> ==============================================================================
> --- lld/trunk/lib/Driver/LDOptions.td (added)
> +++ lld/trunk/lib/Driver/LDOptions.td Fri Dec  7 18:47:36 2012
> @@ -0,0 +1,13 @@
> +include "llvm/Option/OptParser.td"
> +
> +def flavor : Separate<["-"], "flavor">;
> +def target : Separate<["-"], "target">, HelpText<"Target triple to link for">;
> +
> +def entry : Joined<["--"], "entry=">;
> +def entry_e : Separate<["-"], "e">, Alias<entry>;
> +
> +def output : Joined<["--"], "output=">;
> +def output_e : Separate<["-"], "o">, Alias<output>;
> +
> +def relocatable : Flag<["--"], "relocatable">;
> +def relocatable_r : Flag<["-"], "r">, Alias<relocatable>;
> 
> Added: lld/trunk/lib/Driver/LinkerInvocation.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/LinkerInvocation.cpp?rev=169659&view=auto
> ==============================================================================
> --- lld/trunk/lib/Driver/LinkerInvocation.cpp (added)
> +++ lld/trunk/lib/Driver/LinkerInvocation.cpp Fri Dec  7 18:47:36 2012
> @@ -0,0 +1,70 @@
> +//===- lib/Driver/LinkerInvocation.cpp - Linker Invocation ----------------===//
> +//
> +//                             The LLVM Linker
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "lld/Driver/LinkerInvocation.h"
> +
> +#include "lld/Core/InputFiles.h"
> +#include "lld/Core/Resolver.h"
> +#include "lld/Driver/Target.h"
> +
> +#include "llvm/Support/raw_ostream.h"
> +
> +using namespace lld;
> +
> +void LinkerInvocation::operator()() {
> +    // Create target.
> +    std::unique_ptr<Target> target(Target::create(_options));
> +
> +    if (!target) {
> +      llvm::errs() << "Failed to create target for " << _options._target
> +                   << "\n";
> +      return;
> +    }
> +
> +    // Read inputs
> +    InputFiles inputs;
> +    for (const auto &input : _options._input) {
> +      auto reader = target->getReader(input);
> +      if (error_code ec = reader) {
> +        llvm::errs() << "Failed to get reader for: " << input.getPath() << ": "
> +                     << ec.message() << "\n";
> +        return;
> +      }
> +
> +      auto buffer = input.getBuffer();
> +      if (error_code ec = buffer) {
> +        llvm::errs() << "Failed to read file: " << input.getPath() << ": "
> +                     << ec.message() << "\n";
> +        return;
> +      }
> +
> +      std::vector<std::unique_ptr<File>> files;
> +      if (llvm::error_code ec = reader->readFile(
> +            buffer->getBufferIdentifier(), files)) {
> +        llvm::errs() << "Failed to read file: " << input.getPath() << ": "
> +                     << ec.message() << "\n";
> +        return;
> +      }
> +      inputs.appendFiles(files);
> +    }
> +
> +    ResolverOptions ro;
> +    Resolver resolver(ro, inputs);
> +    resolver.resolve();
> +    File &merged = resolver.resultFile();
> +
> +    auto writer = target->getWriter();
> +    if (error_code ec = writer) {
> +      llvm::errs() << "Failed to get writer: " << ec.message() << ".\n";
> +      return;
> +    }
> +
> +    if (error_code ec = writer->writeFile(merged, _options._outputPath))
> +      llvm::errs() << "Failed to write file: " << ec.message() << "\n";
> +  }
> 
> Added: lld/trunk/lib/Driver/Target.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/Target.cpp?rev=169659&view=auto
> ==============================================================================
> --- lld/trunk/lib/Driver/Target.cpp (added)
> +++ lld/trunk/lib/Driver/Target.cpp Fri Dec  7 18:47:36 2012
> @@ -0,0 +1,14 @@
> +//===- lib/Driver/Target.cpp - Linker Target Abstraction ------------------===//
> +//
> +//                             The LLVM Linker
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#include "lld/Driver/Target.h"
> +
> +using namespace lld;
> +
> +Target::~Target() {}
> 
> Added: lld/trunk/lib/Driver/Targets.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Driver/Targets.cpp?rev=169659&view=auto
> ==============================================================================
> --- lld/trunk/lib/Driver/Targets.cpp (added)
> +++ lld/trunk/lib/Driver/Targets.cpp Fri Dec  7 18:47:36 2012
> @@ -0,0 +1,75 @@
> +//===- lib/Driver/Targets.cpp - Linker Targets ----------------------------===//
> +//
> +//                             The LLVM Linker
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +///
> +/// \file
> +///
> +/// Concrete instances of the Target interface.
> +///
> +//===----------------------------------------------------------------------===//
> +
> +#include "lld/Driver/Target.h"
> +
> +#include "lld/ReaderWriter/ReaderArchive.h"
> +#include "lld/ReaderWriter/ReaderELF.h"
> +#include "lld/ReaderWriter/ReaderYAML.h"
> +#include "lld/ReaderWriter/WriterELF.h"
> +
> +#include "llvm/ADT/Triple.h"
> +
> +using namespace lld;
> +
> +class X86LinuxTarget final : public Target {
> +public:
> +  X86LinuxTarget(const LinkerOptions &lo) : Target(lo) {
> +    _readerELF.reset(createReaderELF(_roe, _roa));
> +    _readerYAML.reset(createReaderYAML(_roy));
> +    _writer.reset(createWriterELF(_woe));
> +  }
> +
> +  virtual ErrorOr<lld::Reader&> getReader(const LinkerInput &input) {
> +    auto kind = input.getKind();
> +    if (!kind)
> +      return error_code(kind);
> +
> +    if (*kind == InputKind::YAML)
> +      return *_readerYAML;
> +
> +    if (*kind == InputKind::Object)
> +      return *_readerELF;
> +
> +    return llvm::make_error_code(llvm::errc::invalid_argument);
> +  }
> +
> +  virtual ErrorOr<lld::Writer&> getWriter() {
> +    return *_writer;
> +  }
> +
> +private:
> +  lld::ReaderOptionsELF _roe;
> +  lld::ReaderOptionsArchive _roa;
> +  struct : lld::ReaderOptionsYAML {
> +    virtual Reference::Kind kindFromString(StringRef kindName) const {
> +      int k;
> +      if (kindName.getAsInteger(0, k))
> +        k = 0;
> +      return k;
> +    }
> +  } _roy;
> +  lld::WriterOptionsELF _woe;
> +
> +  std::unique_ptr<lld::Reader> _readerELF, _readerYAML;
> +  std::unique_ptr<lld::Writer> _writer;
> +};
> +
> +std::unique_ptr<Target> Target::create(const LinkerOptions &lo) {
> +  llvm::Triple t(lo._target);
> +  if (t.getOS() == llvm::Triple::Linux && t.getArch() == llvm::Triple::x86_64)
> +    return std::unique_ptr<Target>(new X86LinuxTarget(lo));
> +  return std::unique_ptr<Target>();
> +}
> 
> Modified: lld/trunk/tools/lld/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/tools/lld/CMakeLists.txt?rev=169659&r1=169658&r2=169659&view=diff
> ==============================================================================
> --- lld/trunk/tools/lld/CMakeLists.txt (original)
> +++ lld/trunk/tools/lld/CMakeLists.txt Fri Dec  7 18:47:36 2012
> @@ -2,5 +2,9 @@
>   lld.cpp
>   )
> 
> +target_link_libraries(lld
> +  lldDriver
> +  )
> +
> install(TARGETS lld
>   RUNTIME DESTINATION bin)
> 
> Modified: lld/trunk/tools/lld/lld.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/tools/lld/lld.cpp?rev=169659&r1=169658&r2=169659&view=diff
> ==============================================================================
> --- lld/trunk/tools/lld/lld.cpp (original)
> +++ lld/trunk/tools/lld/lld.cpp Fri Dec  7 18:47:36 2012
> @@ -1,4 +1,4 @@
> -//===- tools/lld/lld.cpp - Linker Driver Dispatcher ---------------------===//
> +//===- tools/lld/lld.cpp - Linker Driver Dispatcher -----------------------===//
> //
> //                             The LLVM Linker
> //
> @@ -6,12 +6,137 @@
> // License. See LICENSE.TXT for details.
> //
> //===----------------------------------------------------------------------===//
> -//
> -// This is the entry point to the lld driver. This is a thin wrapper which
> -// dispatches to the given platform specific driver.
> -//
> +///
> +/// \file
> +///
> +/// This is the entry point to the lld driver. This is a thin wrapper which
> +/// dispatches to the given platform specific driver.
> +///
> //===----------------------------------------------------------------------===//
> 
> +#include "lld/Core/LLVM.h"
> +#include "lld/Driver/Driver.h"
> +#include "lld/Driver/LinkerInvocation.h"
> +
> +#include "llvm/ADT/ArrayRef.h"
> +#include "llvm/ADT/SmallVector.h"
> +#include "llvm/ADT/StringExtras.h"
> +#include "llvm/ADT/StringRef.h"
> +#include "llvm/ADT/StringSwitch.h"
> +#include "llvm/Option/Arg.h"
> +#include "llvm/Support/FileSystem.h"
> +#include "llvm/Support/Host.h"
> +#include "llvm/Support/ManagedStatic.h"
> +#include "llvm/Support/PrettyStackTrace.h"
> +#include "llvm/Support/Path.h"
> +#include "llvm/Support/raw_ostream.h"
> +#include "llvm/Support/Signals.h"
> +
> +using namespace lld;
> +
> +Driver::Flavor strToFlavor(StringRef str) {
> +  return llvm::StringSwitch<Driver::Flavor>(str)
> +           .Case("ld", Driver::Flavor::ld)
> +           .Case("link", Driver::Flavor::link)
> +           .Case("ld64", Driver::Flavor::ld64)
> +           .Case("core", Driver::Flavor::core)
> +           .Default(Driver::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) != Driver::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;
> +}
> +
> +/// \brief Pick the flavor of driver to use based on the command line and
> +///        host environment.
> +Driver::Flavor selectFlavor(int argc, const char * const * const argv) {
> +  if (argc >= 2 && StringRef(argv[1]) == "-core")
> +    return Driver::Flavor::core;
> +  if (argc >= 3 && StringRef(argv[1]) == "-flavor") {
> +    Driver::Flavor flavor = strToFlavor(argv[2]);
> +    if (flavor == Driver::Flavor::invalid)
> +      llvm::errs() << "error: '" << argv[2] << "' invalid value for -flavor.\n";
> +    return flavor;
> +  }
> +
> +  Driver::Flavor flavor = strToFlavor(
> +    parseProgramName(llvm::sys::path::stem(argv[0]))._flavor);
> +
> +  if (flavor == Driver::Flavor::invalid)
> +    llvm::errs() << "error: failed to determine driver flavor from program name"
> +                    " '" << argv[0] << "'.\n";
> +  return flavor;
> +}
> +
> +/// \brief Get the default target triple based on either the program name or
> +///        the primary target llvm was configured for.
> +std::string getDefaultTarget(int argc, const char *const *const argv) {
> +  std::string ret = parseProgramName(llvm::sys::path::stem(argv[0]))._target;
> +  if (ret.empty())
> +    ret = llvm::sys::getDefaultTargetTriple();
> +  return ret;
> +}
> +
> int main(int argc, char **argv) {
> +  llvm::sys::PrintStackTraceOnErrorSignal();
> +  llvm::PrettyStackTraceProgram X(argc, argv);
> +  llvm::llvm_shutdown_obj Y;
> +
> +  Driver::Flavor iHazAFlavor = selectFlavor(argc, argv);
> +  if (iHazAFlavor == Driver::Flavor::invalid)
> +    return 1;
> +
> +  std::unique_ptr<llvm::opt::ArgList> coreArgs;
> +  std::unique_ptr<Driver> driver;
> +  if (iHazAFlavor != Driver::Flavor::core) {
> +    // Transform to core arguments.
> +    driver = Driver::create(iHazAFlavor, getDefaultTarget(argc, argv));
> +    coreArgs = driver->transform(
> +      llvm::ArrayRef<const char *const>(argv + 1, argv + argc));
> +  }
> +
> +  if (!coreArgs)
> +    return 1;
> +
> +  for (auto arg : *coreArgs) {
> +    llvm::outs() << arg->getAsString(*coreArgs) << " ";
> +  }
> +  llvm::outs() << "\n";
> +
> +  LinkerOptions lo(generateOptions(*coreArgs));
> +  LinkerInvocation invocation(lo);
> +  invocation();
> +
>   return 0;
> }
> 
> 
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits




More information about the llvm-commits mailing list