[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
Michael Spencer
bigcheesegs at gmail.com
Fri Dec 7 17:26:42 PST 2012
On Fri, Dec 7, 2012 at 4:58 PM, Nick Kledzik <kledzik at apple.com> wrote:
> Michael,
>
> Is there some documentation on how to use the new options infrastructure?
Not yet.
>
> Do you plan to switch all of lld (e.g. readFile() and friends) to start using ErrorOr?
Yes. I will eventually try to switch parts of llvm over too.
- Michael Spencer
>
> -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