forked from OSchip/llvm-project
Revert "Convert other drivers to use WrapperNode" and subsequent commits.
r225764 broke a basic functionality on Mac OS. This change reverts r225764, r225766, r225767, r225769, r225814, r225816, r225829, and r225832. llvm-svn: 225859
This commit is contained in:
parent
8efadbf868
commit
cfb2534ef8
lld
docs
include/lld
Core
Driver
ReaderWriter
lib
Core
Driver
CMakeLists.txtCoreDriver.cppDarwinInputGraph.cppDarwinLdDriver.cppDriver.cppGnuLdDriver.cppGnuLdInputGraph.cppWinLinkDriver.cppWinLinkInputGraph.cpp
Passes
ReaderWriter
test
unittests/DriverTests
|
@ -66,7 +66,7 @@ Readers are factories
|
|||
---------------------
|
||||
|
||||
The linker will usually only instantiate your Reader once. That one Reader will
|
||||
have its loadFile() method called many times with different input files.
|
||||
have its parseFile() method called many times with different input files.
|
||||
To support multithreaded linking, the Reader may be parsing multiple input
|
||||
files in parallel. Therefore, there should be no parsing state in you Reader
|
||||
object. Any parsing state should be in ivars of your File subclass or in
|
||||
|
@ -74,8 +74,8 @@ some temporary object.
|
|||
|
||||
The key method to implement in a reader is::
|
||||
|
||||
virtual error_code loadFile(LinkerInput &input,
|
||||
std::vector<std::unique_ptr<File>> &result);
|
||||
virtual error_code parseFile(LinkerInput &input,
|
||||
std::vector<std::unique_ptr<File>> &result);
|
||||
|
||||
It takes a memory buffer (which contains the contents of the object file
|
||||
being read) and returns an instantiated lld::File object which is
|
||||
|
|
|
@ -35,7 +35,7 @@ public:
|
|||
virtual const File *find(StringRef name, bool dataSymbolOnly) const = 0;
|
||||
|
||||
virtual std::error_code
|
||||
parseAllMembers(std::vector<std::unique_ptr<File>> &result) = 0;
|
||||
parseAllMembers(std::vector<std::unique_ptr<File>> &result) const = 0;
|
||||
|
||||
/// Returns a set of all defined symbols in the archive, i.e. all
|
||||
/// resolvable symbol using this file.
|
||||
|
|
|
@ -274,8 +274,7 @@ protected:
|
|||
/// can do unit testing a driver using non-existing file paths.
|
||||
class ErrorFile : public File {
|
||||
public:
|
||||
ErrorFile(StringRef path, std::error_code ec)
|
||||
: File(path, kindObject), _ec(ec) {}
|
||||
ErrorFile(StringRef p, std::error_code ec) : File(p, kindObject), _ec(ec) {}
|
||||
|
||||
std::error_code doParse() override { return _ec; }
|
||||
|
||||
|
|
|
@ -49,7 +49,18 @@ public:
|
|||
typedef FileVectorT::iterator FileIterT;
|
||||
|
||||
/// \brief Initialize the inputgraph
|
||||
InputGraph() : _index(0) {}
|
||||
InputGraph() : _nextElementIndex(0), _currentInputElement(nullptr) {}
|
||||
virtual ~InputGraph();
|
||||
|
||||
/// getNextFile returns the next file that needs to be processed by
|
||||
/// the resolver. When there are no more files to be processed, an
|
||||
/// nullptr is returned.
|
||||
File *getNextFile();
|
||||
|
||||
/// Adds an observer of getNextFile(). Each time a new file is about to be
|
||||
/// returned from getNextFile(), registered observers are called with the file
|
||||
/// being returned.
|
||||
void registerObserver(std::function<void(File *)>);
|
||||
|
||||
/// \brief Adds a node into the InputGraph
|
||||
void addInputElement(std::unique_ptr<InputElement>);
|
||||
|
@ -57,16 +68,34 @@ public:
|
|||
/// \brief Adds a node at the beginning of the InputGraph
|
||||
void addInputElementFront(std::unique_ptr<InputElement>);
|
||||
|
||||
InputElementVectorT &inputElements() { return _inputArgs; }
|
||||
/// Normalize the InputGraph. It calls getReplacements() on each element.
|
||||
void normalize();
|
||||
|
||||
InputElementVectorT &inputElements() {
|
||||
return _inputArgs;
|
||||
}
|
||||
|
||||
// Returns the current group size if we are at an --end-group.
|
||||
// Otherwise returns 0.
|
||||
int getGroupSize();
|
||||
void skipGroup();
|
||||
|
||||
// \brief Returns the number of input files.
|
||||
size_t size() const { return _inputArgs.size(); }
|
||||
|
||||
/// \brief Dump the input Graph
|
||||
bool dump(raw_ostream &diagnostics = llvm::errs());
|
||||
|
||||
protected:
|
||||
// Input arguments
|
||||
InputElementVectorT _inputArgs;
|
||||
// Index of the next element to be processed
|
||||
size_t _index;
|
||||
uint32_t _nextElementIndex;
|
||||
InputElement *_currentInputElement;
|
||||
std::vector<std::function<void(File *)>> _observers;
|
||||
|
||||
private:
|
||||
InputElement *getNextInputElement();
|
||||
};
|
||||
|
||||
/// \brief This describes each element in the InputGraph. The Kind
|
||||
|
@ -96,6 +125,11 @@ public:
|
|||
/// Get the next file to be processed by the resolver
|
||||
virtual File *getNextFile() = 0;
|
||||
|
||||
/// Get the elements that we want to expand with.
|
||||
virtual bool getReplacements(InputGraph::InputElementVectorT &) {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
Kind _kind; // The type of the Element
|
||||
};
|
||||
|
@ -131,13 +165,9 @@ private:
|
|||
class FileNode : public InputElement {
|
||||
public:
|
||||
FileNode(StringRef path)
|
||||
: InputElement(InputElement::Kind::File), _path(path), _done(false) {
|
||||
: InputElement(InputElement::Kind::File), _path(path), _nextFileIndex(0) {
|
||||
}
|
||||
|
||||
FileNode(StringRef path, std::unique_ptr<File> f)
|
||||
: InputElement(InputElement::Kind::File), _path(path), _file(std::move(f)),
|
||||
_done(false) {}
|
||||
|
||||
virtual ErrorOr<StringRef> getPath(const LinkingContext &) const {
|
||||
return _path;
|
||||
}
|
||||
|
@ -156,33 +186,36 @@ public:
|
|||
}
|
||||
|
||||
/// \brief Get the list of files
|
||||
File *getFile() { return _file.get(); }
|
||||
range<InputGraph::FileIterT> files() {
|
||||
return make_range(_files.begin(), _files.end());
|
||||
}
|
||||
|
||||
/// \brief add a file to the list of files
|
||||
virtual void addFiles(InputGraph::FileVectorT files) {
|
||||
assert(files.size() == 1);
|
||||
assert(!_file);
|
||||
_file = std::move(files[0]);
|
||||
assert(_files.empty());
|
||||
for (std::unique_ptr<File> &ai : files)
|
||||
_files.push_back(std::move(ai));
|
||||
}
|
||||
|
||||
bool getReplacements(InputGraph::InputElementVectorT &result) override;
|
||||
|
||||
/// \brief Return the next File thats part of this node to the
|
||||
/// resolver.
|
||||
File *getNextFile() override {
|
||||
assert(_file);
|
||||
if (_done)
|
||||
if (_nextFileIndex == _files.size())
|
||||
return nullptr;
|
||||
_done = true;
|
||||
return _file.get();
|
||||
return _files[_nextFileIndex++].get();
|
||||
}
|
||||
|
||||
std::error_code parse(const LinkingContext &, raw_ostream &) override;
|
||||
|
||||
protected:
|
||||
StringRef _path; // The path of the Input file
|
||||
std::unique_ptr<File> _file; // An lld File object
|
||||
InputGraph::FileVectorT _files; // A vector of lld File objects
|
||||
|
||||
// The next file that would be processed by the resolver
|
||||
bool _done;
|
||||
uint32_t _nextFileIndex;
|
||||
};
|
||||
|
||||
/// \brief Represents Internal Input files
|
||||
|
@ -190,13 +223,15 @@ class SimpleFileNode : public FileNode {
|
|||
public:
|
||||
SimpleFileNode(StringRef path) : FileNode(path) {}
|
||||
SimpleFileNode(StringRef path, std::unique_ptr<File> f)
|
||||
: FileNode(path, std::move(f)) {}
|
||||
: FileNode(path) {
|
||||
_files.push_back(std::move(f));
|
||||
}
|
||||
|
||||
virtual ~SimpleFileNode() {}
|
||||
|
||||
/// \brief add a file to the list of files
|
||||
virtual void appendInputFile(std::unique_ptr<File> f) {
|
||||
_file = std::move(f);
|
||||
_files.push_back(std::move(f));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -55,8 +55,8 @@ public:
|
|||
private:
|
||||
typedef std::function<void(StringRef, bool)> UndefCallback;
|
||||
|
||||
bool undefinesAdded(int begin, int end);
|
||||
File *getFile(int &index, int &groupLevel);
|
||||
bool undefinesAdded(int count);
|
||||
File *nextFile(bool &inGroup);
|
||||
|
||||
/// \brief Add section group/.gnu.linkonce if it does not exist previously.
|
||||
void maybeAddSectionGroupOrGnuLinkOnce(const DefinedAtom &atom);
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
//===- lld/Driver/DarwinInputGraph.h - Input Graph Node for Mach-O linker -===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
///
|
||||
/// Handles Options for MachO linking and provides InputElements
|
||||
/// for MachO linker
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_DRIVER_DARWIN_INPUT_GRAPH_H
|
||||
#define LLD_DRIVER_DARWIN_INPUT_GRAPH_H
|
||||
|
||||
#include "lld/Core/ArchiveLibraryFile.h"
|
||||
#include "lld/Core/InputGraph.h"
|
||||
#include "lld/ReaderWriter/MachOLinkingContext.h"
|
||||
|
||||
namespace lld {
|
||||
|
||||
/// \brief Represents a MachO File
|
||||
class MachOFileNode : public FileNode {
|
||||
public:
|
||||
MachOFileNode(StringRef path, MachOLinkingContext &ctx)
|
||||
: FileNode(path), _context(ctx), _isWholeArchive(false),
|
||||
_upwardDylib(false) {}
|
||||
|
||||
/// \brief Parse the input file to lld::File.
|
||||
std::error_code parse(const LinkingContext &ctx,
|
||||
raw_ostream &diagnostics) override;
|
||||
|
||||
void setLoadWholeArchive(bool value=true) {
|
||||
_isWholeArchive = value;
|
||||
}
|
||||
|
||||
void setUpwardDylib(bool value=true) {
|
||||
_upwardDylib = value;
|
||||
}
|
||||
|
||||
private:
|
||||
void narrowFatBuffer(std::unique_ptr<MemoryBuffer> &mb, StringRef filePath);
|
||||
|
||||
MachOLinkingContext &_context;
|
||||
std::unique_ptr<const ArchiveLibraryFile> _archiveFile;
|
||||
bool _isWholeArchive;
|
||||
bool _upwardDylib;
|
||||
};
|
||||
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
|
@ -36,7 +36,7 @@ typedef std::vector<std::unique_ptr<File>> FileVector;
|
|||
|
||||
FileVector makeErrorFile(StringRef path, std::error_code ec);
|
||||
FileVector parseMemberFiles(FileVector &files);
|
||||
FileVector loadFile(LinkingContext &ctx, StringRef path, bool wholeArchive);
|
||||
FileVector parseFile(LinkingContext &ctx, StringRef path, bool wholeArchive);
|
||||
|
||||
/// Base class for all Drivers.
|
||||
class Driver {
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
//===- lld/Driver/GnuLdInputGraph.h - Input Graph Node for ELF linker------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
///
|
||||
/// Handles Options for the GNU style linker for ELF and provides InputElements
|
||||
/// for the GNU style linker for ELF
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_DRIVER_GNU_LD_INPUT_GRAPH_H
|
||||
#define LLD_DRIVER_GNU_LD_INPUT_GRAPH_H
|
||||
|
||||
#include "lld/Core/ArchiveLibraryFile.h"
|
||||
#include "lld/Core/InputGraph.h"
|
||||
#include "lld/Core/Resolver.h"
|
||||
#include "lld/ReaderWriter/ELFLinkingContext.h"
|
||||
|
||||
namespace lld {
|
||||
|
||||
/// \brief Represents a ELF File
|
||||
class ELFFileNode : public FileNode {
|
||||
public:
|
||||
/// \brief The attributes class provides a way for a input file to look into
|
||||
/// all the positional attributes that were specified in the command line.
|
||||
/// There are few positional operators and the number of arguments to the
|
||||
/// ELFFileNode class keeps growing. This achieves code to be clean as well.
|
||||
class Attributes {
|
||||
public:
|
||||
Attributes()
|
||||
: _isWholeArchive(false), _asNeeded(false), _isDashlPrefix(false),
|
||||
_isSysRooted(false) {}
|
||||
void setWholeArchive(bool isWholeArchive) {
|
||||
_isWholeArchive = isWholeArchive;
|
||||
}
|
||||
void setAsNeeded(bool asNeeded) { _asNeeded = asNeeded; }
|
||||
void setDashlPrefix(bool isDashlPrefix) { _isDashlPrefix = isDashlPrefix; }
|
||||
void setSysRooted(bool isSysRooted) { _isSysRooted = isSysRooted; }
|
||||
|
||||
public:
|
||||
bool _isWholeArchive;
|
||||
bool _asNeeded;
|
||||
bool _isDashlPrefix;
|
||||
bool _isSysRooted;
|
||||
};
|
||||
|
||||
ELFFileNode(ELFLinkingContext &ctx, StringRef path, Attributes &attributes)
|
||||
: FileNode(path), _elfLinkingContext(ctx), _attributes(attributes) {}
|
||||
|
||||
ErrorOr<StringRef> getPath(const LinkingContext &ctx) const override;
|
||||
|
||||
/// \brief create an error string for printing purposes
|
||||
std::string errStr(std::error_code) override;
|
||||
|
||||
/// \brief Dump the Input Element
|
||||
bool dump(raw_ostream &diagnostics) override {
|
||||
diagnostics << "Name : " << *getPath(_elfLinkingContext) << "\n"
|
||||
<< "Type : ELF File\n"
|
||||
<< "Attributes :\n"
|
||||
<< " - wholeArchive : "
|
||||
<< ((_attributes._isWholeArchive) ? "true" : "false") << "\n"
|
||||
<< " - asNeeded : "
|
||||
<< ((_attributes._asNeeded) ? "true" : "false") << "\n";
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \brief Parse the input file to lld::File.
|
||||
std::error_code parse(const LinkingContext &, raw_ostream &) override;
|
||||
|
||||
private:
|
||||
llvm::BumpPtrAllocator _alloc;
|
||||
const ELFLinkingContext &_elfLinkingContext;
|
||||
std::unique_ptr<const ArchiveLibraryFile> _archiveFile;
|
||||
const Attributes _attributes;
|
||||
};
|
||||
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
|
@ -0,0 +1,45 @@
|
|||
//===- lld/Driver/WinLinkInputGraph.h - Input Graph Node for COFF linker --===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
///
|
||||
/// Handles Options for PECOFF linking and provides InputElements
|
||||
/// for PECOFF linker
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_DRIVER_WIN_LINK_INPUT_GRAPH_H
|
||||
#define LLD_DRIVER_WIN_LINK_INPUT_GRAPH_H
|
||||
|
||||
#include "lld/Core/InputGraph.h"
|
||||
#include "lld/ReaderWriter/PECOFFLinkingContext.h"
|
||||
#include <map>
|
||||
|
||||
namespace lld {
|
||||
|
||||
/// \brief Represents a PECOFF File
|
||||
class PECOFFFileNode : public FileNode {
|
||||
public:
|
||||
PECOFFFileNode(PECOFFLinkingContext &ctx, StringRef path)
|
||||
: FileNode(path), _ctx(ctx), _parsed(false) {}
|
||||
|
||||
/// \brief Parse the input file to lld::File.
|
||||
std::error_code parse(const LinkingContext &ctx,
|
||||
raw_ostream &diagnostics) override;
|
||||
|
||||
protected:
|
||||
const PECOFFLinkingContext &_ctx;
|
||||
|
||||
private:
|
||||
bool _parsed;
|
||||
};
|
||||
|
||||
} // namespace lld
|
||||
|
||||
#endif
|
|
@ -21,7 +21,9 @@ namespace lld {
|
|||
|
||||
class WrapperNode : public FileNode {
|
||||
public:
|
||||
WrapperNode(std::unique_ptr<File> f) : FileNode(f->path(), std::move(f)) {}
|
||||
WrapperNode(std::unique_ptr<File> file) : FileNode(file->path()) {
|
||||
_files.push_back(std::move(file));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -290,28 +290,6 @@ public:
|
|||
bool alignSegments() const { return _alignSegments; }
|
||||
void setAlignSegments(bool align) { _alignSegments = align; }
|
||||
|
||||
/// \brief The attributes class provides a way for a input file to look into
|
||||
/// all the positional attributes that were specified in the command line.
|
||||
/// There are few positional operators and the number of arguments to the
|
||||
/// ELFFileNode class keeps growing. This achieves code to be clean as well.
|
||||
class Attributes {
|
||||
public:
|
||||
Attributes()
|
||||
: _isWholeArchive(false), _asNeeded(false), _isDashlPrefix(false),
|
||||
_isSysRooted(false) {}
|
||||
void setWholeArchive(bool isWholeArchive) {
|
||||
_isWholeArchive = isWholeArchive;
|
||||
}
|
||||
void setAsNeeded(bool asNeeded) { _asNeeded = asNeeded; }
|
||||
void setDashlPrefix(bool isDashlPrefix) { _isDashlPrefix = isDashlPrefix; }
|
||||
void setSysRooted(bool isSysRooted) { _isSysRooted = isSysRooted; }
|
||||
|
||||
bool _isWholeArchive;
|
||||
bool _asNeeded;
|
||||
bool _isDashlPrefix;
|
||||
bool _isSysRooted;
|
||||
};
|
||||
|
||||
private:
|
||||
ELFLinkingContext() LLVM_DELETED_FUNCTION;
|
||||
|
||||
|
|
|
@ -350,7 +350,7 @@ private:
|
|||
mutable llvm::StringMap<mach_o::MachODylibFile*> _pathToDylibMap;
|
||||
mutable std::set<mach_o::MachODylibFile*> _allDylibs;
|
||||
mutable std::set<mach_o::MachODylibFile*> _upwardDylibs;
|
||||
mutable std::vector<std::unique_ptr<File>> _indirectDylibs;
|
||||
mutable std::vector<std::unique_ptr<class MachOFileNode>> _indirectDylibs;
|
||||
ExportMode _exportMode;
|
||||
llvm::StringSet<> _exportedSymbols;
|
||||
DebugInfoMode _debugInfoMode;
|
||||
|
|
|
@ -30,28 +30,6 @@ static const uint8_t DEFAULT_DOS_STUB[128] = {'M', 'Z'};
|
|||
|
||||
namespace lld {
|
||||
|
||||
namespace pecoff {
|
||||
class ResolvableSymbols {
|
||||
public:
|
||||
void add(File *file);
|
||||
|
||||
const std::set<std::string> &defined() {
|
||||
readAllSymbols();
|
||||
return _defined;
|
||||
}
|
||||
|
||||
private:
|
||||
// Files are read lazily, so that it has no runtime overhead if
|
||||
// no one accesses this class.
|
||||
void readAllSymbols();
|
||||
|
||||
std::set<std::string> _defined;
|
||||
std::set<File *> _seen;
|
||||
std::set<File *> _queue;
|
||||
std::mutex _mutex;
|
||||
};
|
||||
} // end namespace pecoff
|
||||
|
||||
class PECOFFLinkingContext : public LinkingContext {
|
||||
public:
|
||||
PECOFFLinkingContext()
|
||||
|
@ -350,10 +328,6 @@ public:
|
|||
|
||||
std::recursive_mutex &getMutex() { return _mutex; }
|
||||
|
||||
pecoff::ResolvableSymbols *getResolvableSymsFile() {
|
||||
return &_resolvableSyms;
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Method to create a internal file for the entry symbol
|
||||
std::unique_ptr<File> createEntrySymbolFile() const override;
|
||||
|
@ -468,8 +442,6 @@ private:
|
|||
// Name of the temporary file for lib.exe subcommand. For debugging
|
||||
// only.
|
||||
std::string _moduleDefinitionFile;
|
||||
|
||||
pecoff::ResolvableSymbols _resolvableSyms;
|
||||
};
|
||||
|
||||
} // end namespace lld
|
||||
|
|
|
@ -55,8 +55,8 @@ public:
|
|||
/// file) and create a File object.
|
||||
/// The resulting File object takes ownership of the MemoryBuffer.
|
||||
virtual std::error_code
|
||||
loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
|
||||
std::vector<std::unique_ptr<File>> &result) const = 0;
|
||||
parseFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
|
||||
std::vector<std::unique_ptr<File>> &result) const = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -93,8 +93,8 @@ public:
|
|||
|
||||
/// Walk the list of registered Readers and find one that can parse the
|
||||
/// supplied file and parse it.
|
||||
std::error_code loadFile(std::unique_ptr<MemoryBuffer> mb,
|
||||
std::vector<std::unique_ptr<File>> &result) const;
|
||||
std::error_code parseFile(std::unique_ptr<MemoryBuffer> mb,
|
||||
std::vector<std::unique_ptr<File>> &result) const;
|
||||
|
||||
/// Walk the list of registered kind tables to convert a Reference Kind
|
||||
/// name to a value.
|
||||
|
|
|
@ -13,6 +13,33 @@
|
|||
|
||||
using namespace lld;
|
||||
|
||||
InputGraph::~InputGraph() { }
|
||||
|
||||
File *InputGraph::getNextFile() {
|
||||
// Try to get the next file of _currentInputElement. If the current input
|
||||
// element points to an archive file, and there's a file left in the archive,
|
||||
// it will succeed. If not, try to get the next file in the input graph.
|
||||
for (;;) {
|
||||
if (_currentInputElement) {
|
||||
File *next = _currentInputElement->getNextFile();
|
||||
if (next) {
|
||||
for (const std::function<void(File *)> &observer : _observers)
|
||||
observer(next);
|
||||
return next;
|
||||
}
|
||||
}
|
||||
|
||||
InputElement *elt = getNextInputElement();
|
||||
if (!elt)
|
||||
return nullptr;
|
||||
_currentInputElement = elt;
|
||||
}
|
||||
}
|
||||
|
||||
void InputGraph::registerObserver(std::function<void(File *)> fn) {
|
||||
_observers.push_back(fn);
|
||||
}
|
||||
|
||||
void InputGraph::addInputElement(std::unique_ptr<InputElement> ie) {
|
||||
_inputArgs.push_back(std::move(ie));
|
||||
}
|
||||
|
@ -21,9 +48,63 @@ void InputGraph::addInputElementFront(std::unique_ptr<InputElement> ie) {
|
|||
_inputArgs.insert(_inputArgs.begin(), std::move(ie));
|
||||
}
|
||||
|
||||
bool InputGraph::dump(raw_ostream &diagnostics) {
|
||||
for (std::unique_ptr<InputElement> &ie : _inputArgs)
|
||||
if (!ie->dump(diagnostics))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \brief Helper functions for the resolver
|
||||
InputElement *InputGraph::getNextInputElement() {
|
||||
if (_nextElementIndex >= _inputArgs.size())
|
||||
return nullptr;
|
||||
InputElement *elem = _inputArgs[_nextElementIndex++].get();
|
||||
if (isa<GroupEnd>(elem))
|
||||
return getNextInputElement();
|
||||
return elem;
|
||||
}
|
||||
|
||||
void InputGraph::normalize() {
|
||||
std::vector<std::unique_ptr<InputElement>> vec;
|
||||
for (std::unique_ptr<InputElement> &elt : _inputArgs) {
|
||||
if (elt->getReplacements(vec))
|
||||
continue;
|
||||
vec.push_back(std::move(elt));
|
||||
}
|
||||
_inputArgs = std::move(vec);
|
||||
}
|
||||
|
||||
// If we are at the end of a group, return its size (which indicates
|
||||
// how many files we need to go back in the command line).
|
||||
// Returns 0 if we are not at the end of a group.
|
||||
int InputGraph::getGroupSize() {
|
||||
if (_nextElementIndex >= _inputArgs.size())
|
||||
return 0;
|
||||
InputElement *elem = _inputArgs[_nextElementIndex].get();
|
||||
if (const GroupEnd *group = dyn_cast<GroupEnd>(elem))
|
||||
return group->getSize();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void InputGraph::skipGroup() {
|
||||
if (_nextElementIndex >= _inputArgs.size())
|
||||
return;
|
||||
if (isa<GroupEnd>(_inputArgs[_nextElementIndex].get()))
|
||||
_nextElementIndex++;
|
||||
}
|
||||
|
||||
bool FileNode::getReplacements(InputGraph::InputElementVectorT &result) {
|
||||
if (_files.size() < 2)
|
||||
return false;
|
||||
for (std::unique_ptr<File> &file : _files)
|
||||
result.push_back(llvm::make_unique<SimpleFileNode>(_path, std::move(file)));
|
||||
return true;
|
||||
}
|
||||
|
||||
std::error_code FileNode::parse(const LinkingContext &, raw_ostream &) {
|
||||
if (_file)
|
||||
if (std::error_code ec = _file->parse())
|
||||
for (std::unique_ptr<File> &file : _files)
|
||||
if (std::error_code ec = file->parse())
|
||||
return ec;
|
||||
return std::error_code();
|
||||
}
|
||||
|
|
|
@ -231,52 +231,52 @@ void Resolver::addAtoms(const std::vector<const DefinedAtom *> &newAtoms) {
|
|||
|
||||
// Returns true if at least one of N previous files has created an
|
||||
// undefined symbol.
|
||||
bool Resolver::undefinesAdded(int begin, int end) {
|
||||
std::vector<std::unique_ptr<InputElement>> &inputs =
|
||||
_context.getInputGraph().inputElements();
|
||||
for (int i = begin; i < end; ++i)
|
||||
if (FileNode *node = dyn_cast<FileNode>(inputs[i].get()))
|
||||
if (_newUndefinesAdded[node->getFile()])
|
||||
return true;
|
||||
bool Resolver::undefinesAdded(int n) {
|
||||
for (size_t i = _fileIndex - n; i < _fileIndex; ++i)
|
||||
if (_newUndefinesAdded[_files[i]])
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
File *Resolver::getFile(int &index, int &groupLevel) {
|
||||
std::vector<std::unique_ptr<InputElement>> &inputs
|
||||
= _context.getInputGraph().inputElements();
|
||||
if ((size_t)index >= inputs.size())
|
||||
return nullptr;
|
||||
if (GroupEnd *group = dyn_cast<GroupEnd>(inputs[index].get())) {
|
||||
File *Resolver::nextFile(bool &inGroup) {
|
||||
if (size_t groupSize = _context.getInputGraph().getGroupSize()) {
|
||||
// We are at the end of the current group. If one or more new
|
||||
// undefined atom has been added in the last groupSize files, we
|
||||
// reiterate over the files.
|
||||
int size = group->getSize();
|
||||
if (undefinesAdded(index - size, index)) {
|
||||
index -= size;
|
||||
++groupLevel;
|
||||
return getFile(index, groupLevel);
|
||||
}
|
||||
++index;
|
||||
--groupLevel;
|
||||
return getFile(index, groupLevel);
|
||||
if (undefinesAdded(groupSize))
|
||||
_fileIndex -= groupSize;
|
||||
_context.getInputGraph().skipGroup();
|
||||
return nextFile(inGroup);
|
||||
}
|
||||
return cast<FileNode>(inputs[index++].get())->getFile();
|
||||
if (_fileIndex < _files.size()) {
|
||||
// We are still in the current group.
|
||||
inGroup = true;
|
||||
return _files[_fileIndex++];
|
||||
}
|
||||
// We are not in a group. Get a new file.
|
||||
File *file = _context.getInputGraph().getNextFile();
|
||||
if (!file)
|
||||
return nullptr;
|
||||
_files.push_back(&*file);
|
||||
++_fileIndex;
|
||||
inGroup = false;
|
||||
return file;
|
||||
}
|
||||
|
||||
// Keep adding atoms until _context.getNextFile() returns an error. This
|
||||
// function is where undefined atoms are resolved.
|
||||
void Resolver::resolveUndefines() {
|
||||
ScopedTask task(getDefaultDomain(), "resolveUndefines");
|
||||
int index = 0;
|
||||
int groupLevel = 0;
|
||||
|
||||
for (;;) {
|
||||
bool inGroup = false;
|
||||
bool undefAdded = false;
|
||||
File *file = getFile(index, groupLevel);
|
||||
File *file = nextFile(inGroup);
|
||||
if (!file)
|
||||
return;
|
||||
switch (file->kind()) {
|
||||
case File::kindObject:
|
||||
if (groupLevel > 0)
|
||||
if (inGroup)
|
||||
break;
|
||||
assert(!file->hasOrdinal());
|
||||
file->setOrdinal(_context.getNextOrdinalAndIncrement());
|
||||
|
@ -293,7 +293,7 @@ void Resolver::resolveUndefines() {
|
|||
handleSharedLibrary(*file);
|
||||
break;
|
||||
}
|
||||
_newUndefinesAdded[file] = undefAdded;
|
||||
_newUndefinesAdded[&*file] = undefAdded;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,11 +12,14 @@ add_public_tablegen_target(DriverOptionsTableGen)
|
|||
|
||||
add_lld_library(lldDriver
|
||||
CoreDriver.cpp
|
||||
DarwinInputGraph.cpp
|
||||
DarwinLdDriver.cpp
|
||||
Driver.cpp
|
||||
GnuLdDriver.cpp
|
||||
GnuLdInputGraph.cpp
|
||||
UniversalDriver.cpp
|
||||
WinLinkDriver.cpp
|
||||
WinLinkInputGraph.cpp
|
||||
WinLinkModuleDef.cpp
|
||||
)
|
||||
|
||||
|
|
|
@ -152,7 +152,7 @@ bool CoreDriver::parse(int argc, const char *argv[], CoreLinkingContext &ctx,
|
|||
|
||||
case OPT_INPUT: {
|
||||
std::vector<std::unique_ptr<File>> files
|
||||
= loadFile(ctx, inputArg->getValue(), false);
|
||||
= parseFile(ctx, inputArg->getValue(), false);
|
||||
for (std::unique_ptr<File> &file : files) {
|
||||
inputGraph->addInputElement(std::unique_ptr<InputElement>(
|
||||
new WrapperNode(std::move(file))));
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
//===- lib/ReaderWriter/MachO/DarwinInputGraph.cpp ------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "lld/Driver/DarwinInputGraph.h"
|
||||
#include "lld/Core/ArchiveLibraryFile.h"
|
||||
#include "lld/Core/DefinedAtom.h"
|
||||
#include "lld/Core/File.h"
|
||||
#include "lld/Core/LLVM.h"
|
||||
#include "lld/Core/Reference.h"
|
||||
#include "lld/Core/SharedLibraryFile.h"
|
||||
|
||||
namespace lld {
|
||||
|
||||
|
||||
/// \brief Parse the input file to lld::File.
|
||||
std::error_code MachOFileNode::parse(const LinkingContext &ctx,
|
||||
raw_ostream &diagnostics) {
|
||||
ErrorOr<StringRef> filePath = getPath(ctx);
|
||||
if (std::error_code ec = filePath.getError())
|
||||
return ec;
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr =
|
||||
MemoryBuffer::getFileOrSTDIN(*filePath);
|
||||
if (std::error_code ec = mbOrErr.getError())
|
||||
return ec;
|
||||
std::unique_ptr<MemoryBuffer> mb = std::move(mbOrErr.get());
|
||||
|
||||
_context.addInputFileDependency(*filePath);
|
||||
if (ctx.logInputFiles())
|
||||
diagnostics << *filePath << "\n";
|
||||
|
||||
narrowFatBuffer(mb, *filePath);
|
||||
|
||||
std::vector<std::unique_ptr<File>> parsedFiles;
|
||||
if (std::error_code ec = ctx.registry().parseFile(std::move(mb), parsedFiles))
|
||||
return ec;
|
||||
for (std::unique_ptr<File> &pf : parsedFiles) {
|
||||
// If file is a dylib, inform LinkingContext about it.
|
||||
if (SharedLibraryFile *shl = dyn_cast<SharedLibraryFile>(pf.get())) {
|
||||
_context.registerDylib(reinterpret_cast<mach_o::MachODylibFile*>(shl),
|
||||
_upwardDylib);
|
||||
}
|
||||
// If file is an archive and -all_load, then add all members.
|
||||
if (ArchiveLibraryFile *archive = dyn_cast<ArchiveLibraryFile>(pf.get())) {
|
||||
if (_isWholeArchive) {
|
||||
// Have this node own the FileArchive object.
|
||||
_archiveFile.reset(archive);
|
||||
pf.release();
|
||||
// Add all members to _files vector
|
||||
return archive->parseAllMembers(_files);
|
||||
}
|
||||
}
|
||||
_files.push_back(std::move(pf));
|
||||
}
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
|
||||
/// If buffer contains a fat file, find required arch in fat buffer and
|
||||
/// switch buffer to point to just that required slice.
|
||||
void MachOFileNode::narrowFatBuffer(std::unique_ptr<MemoryBuffer> &mb,
|
||||
StringRef filePath) {
|
||||
// Check if buffer is a "fat" file that contains needed arch.
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
if (!_context.sliceFromFatFile(*mb, offset, size)) {
|
||||
return;
|
||||
}
|
||||
// Create new buffer containing just the needed slice.
|
||||
auto subuf = MemoryBuffer::getFileSlice(filePath, size, offset);
|
||||
if (subuf.getError())
|
||||
return;
|
||||
// The assignment to mb will release previous buffer.
|
||||
mb = std::move(subuf.get());
|
||||
}
|
||||
|
||||
|
||||
} // end namesapce lld
|
|
@ -13,11 +13,8 @@
|
|||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "lld/Core/File.h"
|
||||
#include "lld/Core/ArchiveLibraryFile.h"
|
||||
#include "lld/Core/SharedLibraryFile.h"
|
||||
#include "lld/Driver/Driver.h"
|
||||
#include "lld/Driver/WrapperInputGraph.h"
|
||||
#include "lld/Driver/DarwinInputGraph.h"
|
||||
#include "lld/ReaderWriter/MachOLinkingContext.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
|
@ -25,7 +22,6 @@
|
|||
#include "llvm/Option/Arg.h"
|
||||
#include "llvm/Option/Option.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/Host.h"
|
||||
|
@ -72,50 +68,6 @@ public:
|
|||
DarwinLdOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){}
|
||||
};
|
||||
|
||||
std::vector<std::unique_ptr<File>>
|
||||
loadFiles(MachOLinkingContext &ctx, StringRef path,
|
||||
raw_ostream &diag, bool wholeArchive, bool upwardDylib) {
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr =
|
||||
MemoryBuffer::getFileOrSTDIN(path);
|
||||
if (std::error_code ec = mbOrErr.getError())
|
||||
return makeErrorFile(path, ec);
|
||||
std::unique_ptr<MemoryBuffer> mb = std::move(mbOrErr.get());
|
||||
|
||||
ctx.addInputFileDependency(path);
|
||||
if (ctx.logInputFiles())
|
||||
diag << path << "\n";
|
||||
|
||||
// If buffer contains a fat file, find required arch in fat buffer
|
||||
// and switch buffer to point to just that required slice.
|
||||
// Check if buffer is a "fat" file that contains needed arch.
|
||||
uint32_t offset;
|
||||
uint32_t size;
|
||||
if (ctx.sliceFromFatFile(*mb, offset, size)) {
|
||||
// Create new buffer containing just the needed slice.
|
||||
auto subuf = MemoryBuffer::getFileSlice(path, size, offset);
|
||||
if (std::error_code ec = subuf.getError())
|
||||
return makeErrorFile(path, ec);
|
||||
// The assignment to mb will release previous buffer.
|
||||
mb = std::move(subuf.get());
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<File>> files;
|
||||
if (std::error_code ec = ctx.registry().loadFile(std::move(mb), files))
|
||||
return makeErrorFile(path, ec);
|
||||
for (std::unique_ptr<File> &pf : files) {
|
||||
// If file is a dylib, inform LinkingContext about it.
|
||||
if (SharedLibraryFile *shl = dyn_cast<SharedLibraryFile>(pf.get())) {
|
||||
if (std::error_code ec = shl->parse())
|
||||
return makeErrorFile(path, ec);
|
||||
ctx.registerDylib(reinterpret_cast<mach_o::MachODylibFile*>(shl),
|
||||
upwardDylib);
|
||||
}
|
||||
}
|
||||
if (wholeArchive)
|
||||
return parseMemberFiles(files);
|
||||
return files;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// Test may be running on Windows. Canonicalize the path
|
||||
|
@ -133,12 +85,13 @@ static std::string canonicalizePath(StringRef path) {
|
|||
|
||||
static void addFile(StringRef path, std::unique_ptr<InputGraph> &inputGraph,
|
||||
MachOLinkingContext &ctx, bool loadWholeArchive,
|
||||
bool upwardDylib, raw_ostream &diag) {
|
||||
std::vector<std::unique_ptr<File>> files =
|
||||
loadFiles(ctx, path, diag, loadWholeArchive, upwardDylib);
|
||||
for (std::unique_ptr<File> &file : files)
|
||||
inputGraph->addInputElement(
|
||||
llvm::make_unique<WrapperNode>(std::move(file)));
|
||||
bool upwardDylib) {
|
||||
auto node = llvm::make_unique<MachOFileNode>(path, ctx);
|
||||
if (loadWholeArchive)
|
||||
node->setLoadWholeArchive();
|
||||
if (upwardDylib)
|
||||
node->setUpwardDylib();
|
||||
inputGraph->addInputElement(std::move(node));
|
||||
}
|
||||
|
||||
// Export lists are one symbol per line. Blank lines are ignored.
|
||||
|
@ -231,10 +184,10 @@ static std::error_code parseOrderFile(StringRef orderFilePath,
|
|||
// In this variant, the path is to a text file which contains a partial path
|
||||
// per line. The <dir> prefix is prepended to each partial path.
|
||||
//
|
||||
static std::error_code loadFileList(StringRef fileListPath,
|
||||
std::unique_ptr<InputGraph> &inputGraph,
|
||||
MachOLinkingContext &ctx, bool forceLoad,
|
||||
raw_ostream &diagnostics) {
|
||||
static std::error_code parseFileList(StringRef fileListPath,
|
||||
std::unique_ptr<InputGraph> &inputGraph,
|
||||
MachOLinkingContext &ctx, bool forceLoad,
|
||||
raw_ostream &diagnostics) {
|
||||
// If there is a comma, split off <dir>.
|
||||
std::pair<StringRef, StringRef> opt = fileListPath.split(',');
|
||||
StringRef filePath = opt.first;
|
||||
|
@ -269,7 +222,7 @@ static std::error_code loadFileList(StringRef fileListPath,
|
|||
if (ctx.testingFileUsage()) {
|
||||
diagnostics << "Found filelist entry " << canonicalizePath(path) << '\n';
|
||||
}
|
||||
addFile(path, inputGraph, ctx, forceLoad, false, diagnostics);
|
||||
addFile(path, inputGraph, ctx, forceLoad, false);
|
||||
buffer = lineAndRest.second;
|
||||
}
|
||||
return std::error_code();
|
||||
|
@ -291,6 +244,13 @@ bool DarwinLdDriver::linkMachO(int argc, const char *argv[],
|
|||
return false;
|
||||
if (ctx.doNothing())
|
||||
return true;
|
||||
|
||||
// Register possible input file parsers.
|
||||
ctx.registry().addSupportMachOObjects(ctx);
|
||||
ctx.registry().addSupportArchives(ctx.logInputFiles());
|
||||
ctx.registry().addSupportNativeObjects();
|
||||
ctx.registry().addSupportYamlFiles();
|
||||
|
||||
return link(ctx, diagnostics);
|
||||
}
|
||||
|
||||
|
@ -350,15 +310,15 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
|
|||
}
|
||||
}
|
||||
// If no -arch specified, scan input files to find first non-fat .o file.
|
||||
if (arch == MachOLinkingContext::arch_unknown) {
|
||||
if ((arch == MachOLinkingContext::arch_unknown)
|
||||
&& !parsedArgs->getLastArg(OPT_test_file_usage)) {
|
||||
for (auto &inFile: parsedArgs->filtered(OPT_INPUT)) {
|
||||
// This is expensive because it opens and maps the file. But that is
|
||||
// ok because no -arch is rare.
|
||||
if (MachOLinkingContext::isThinObjectFile(inFile->getValue(), arch))
|
||||
break;
|
||||
}
|
||||
if (arch == MachOLinkingContext::arch_unknown
|
||||
&& !parsedArgs->getLastArg(OPT_test_file_usage)) {
|
||||
if (arch == MachOLinkingContext::arch_unknown) {
|
||||
// If no -arch and no options at all, print usage message.
|
||||
if (parsedArgs->size() == 0)
|
||||
table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false);
|
||||
|
@ -561,13 +521,6 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
|
|||
}
|
||||
}
|
||||
|
||||
// Register possible input file parsers.
|
||||
if (!ctx.doNothing()) {
|
||||
ctx.registry().addSupportMachOObjects(ctx);
|
||||
ctx.registry().addSupportArchives(ctx.logInputFiles());
|
||||
ctx.registry().addSupportNativeObjects();
|
||||
ctx.registry().addSupportYamlFiles();
|
||||
}
|
||||
std::unique_ptr<InputGraph> inputGraph(new InputGraph());
|
||||
|
||||
// Now construct the set of library search directories, following ld64's
|
||||
|
@ -792,13 +745,13 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
|
|||
default:
|
||||
continue;
|
||||
case OPT_INPUT:
|
||||
addFile(arg->getValue(), inputGraph, ctx, globalWholeArchive, false, diagnostics);
|
||||
addFile(arg->getValue(), inputGraph, ctx, globalWholeArchive, false);
|
||||
break;
|
||||
case OPT_upward_library:
|
||||
addFile(arg->getValue(), inputGraph, ctx, false, true, diagnostics);
|
||||
addFile(arg->getValue(), inputGraph, ctx, false, true);
|
||||
break;
|
||||
case OPT_force_load:
|
||||
addFile(arg->getValue(), inputGraph, ctx, true, false, diagnostics);
|
||||
addFile(arg->getValue(), inputGraph, ctx, true, false);
|
||||
break;
|
||||
case OPT_l:
|
||||
case OPT_upward_l:
|
||||
|
@ -812,7 +765,7 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
|
|||
diagnostics << "Found " << (upward ? "upward " : " ") << "library "
|
||||
<< canonicalizePath(resolvedPath.get()) << '\n';
|
||||
}
|
||||
addFile(resolvedPath.get(), inputGraph, ctx, globalWholeArchive, upward, diagnostics);
|
||||
addFile(resolvedPath.get(), inputGraph, ctx, globalWholeArchive, upward);
|
||||
break;
|
||||
case OPT_framework:
|
||||
case OPT_upward_framework:
|
||||
|
@ -826,12 +779,12 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
|
|||
diagnostics << "Found " << (upward ? "upward " : " ") << "framework "
|
||||
<< canonicalizePath(resolvedPath.get()) << '\n';
|
||||
}
|
||||
addFile(resolvedPath.get(), inputGraph, ctx, globalWholeArchive, upward, diagnostics);
|
||||
addFile(resolvedPath.get(), inputGraph, ctx, globalWholeArchive, upward);
|
||||
break;
|
||||
case OPT_filelist:
|
||||
if (std::error_code ec = loadFileList(arg->getValue(), inputGraph,
|
||||
ctx, globalWholeArchive,
|
||||
diagnostics)) {
|
||||
if (std::error_code ec = parseFileList(arg->getValue(), inputGraph,
|
||||
ctx, globalWholeArchive,
|
||||
diagnostics)) {
|
||||
diagnostics << "error: " << ec.message()
|
||||
<< ", processing '-filelist " << arg->getValue()
|
||||
<< "'\n";
|
||||
|
|
|
@ -49,13 +49,13 @@ FileVector parseMemberFiles(FileVector &files) {
|
|||
return members;
|
||||
}
|
||||
|
||||
FileVector loadFile(LinkingContext &ctx, StringRef path, bool wholeArchive) {
|
||||
FileVector parseFile(LinkingContext &ctx, StringRef path, bool wholeArchive) {
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> mb
|
||||
= MemoryBuffer::getFileOrSTDIN(path);
|
||||
if (std::error_code ec = mb.getError())
|
||||
return makeErrorFile(path, ec);
|
||||
std::vector<std::unique_ptr<File>> files;
|
||||
if (std::error_code ec = ctx.registry().loadFile(std::move(mb.get()), files))
|
||||
if (std::error_code ec = ctx.registry().parseFile(std::move(mb.get()), files))
|
||||
return makeErrorFile(path, ec);
|
||||
if (wholeArchive)
|
||||
return parseMemberFiles(files);
|
||||
|
@ -77,6 +77,7 @@ bool Driver::link(LinkingContext &context, raw_ostream &diagnostics) {
|
|||
InputGraph &inputGraph = context.getInputGraph();
|
||||
if (!inputGraph.size())
|
||||
return false;
|
||||
inputGraph.normalize();
|
||||
|
||||
bool fail = false;
|
||||
|
||||
|
|
|
@ -14,8 +14,7 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "lld/Driver/Driver.h"
|
||||
#include "lld/Driver/WrapperInputGraph.h"
|
||||
#include "lld/ReaderWriter/ELFLinkingContext.h"
|
||||
#include "lld/Driver/GnuLdInputGraph.h"
|
||||
#include "lld/ReaderWriter/LinkerScript.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
|
@ -173,6 +172,16 @@ bool GnuLdDriver::linkELF(int argc, const char *argv[],
|
|||
return false;
|
||||
if (!options)
|
||||
return true;
|
||||
|
||||
// Register possible input file parsers.
|
||||
options->registry().addSupportELFObjects(options->mergeCommonStrings(),
|
||||
options->targetHandler());
|
||||
options->registry().addSupportArchives(options->logInputFiles());
|
||||
options->registry().addSupportYamlFiles();
|
||||
options->registry().addSupportNativeObjects();
|
||||
if (options->allowLinkWithDynamicLibraries())
|
||||
options->registry().addSupportELFDynamicSharedObjects(
|
||||
options->useShlibUndefines(), options->targetHandler());
|
||||
return link(*options, diagnostics);
|
||||
}
|
||||
|
||||
|
@ -209,23 +218,6 @@ static bool isLinkerScript(StringRef path, raw_ostream &diag) {
|
|||
return magic == llvm::sys::fs::file_magic::unknown;
|
||||
}
|
||||
|
||||
static ErrorOr<StringRef>
|
||||
findFile(ELFLinkingContext &ctx, StringRef path, bool dashL) {
|
||||
// If the path was referred to by using a -l argument, let's search
|
||||
// for the file in the search path.
|
||||
if (dashL) {
|
||||
ErrorOr<StringRef> pathOrErr = ctx.searchLibrary(path);
|
||||
if (std::error_code ec = pathOrErr.getError())
|
||||
return make_dynamic_error_code(
|
||||
Twine("Unable to find library -l") + path + ": " + ec.message());
|
||||
path = pathOrErr->str();
|
||||
}
|
||||
if (!llvm::sys::fs::exists(path))
|
||||
return make_dynamic_error_code(
|
||||
Twine("lld: cannot find file ") + path);
|
||||
return path;
|
||||
}
|
||||
|
||||
static bool isPathUnderSysroot(StringRef sysroot, StringRef path) {
|
||||
if (sysroot.empty())
|
||||
return false;
|
||||
|
@ -242,6 +234,8 @@ evaluateLinkerScript(ELFLinkingContext &ctx, InputGraph *inputGraph,
|
|||
MemoryBuffer::getFileOrSTDIN(path);
|
||||
if (std::error_code ec = mb.getError())
|
||||
return ec;
|
||||
if (ctx.logInputFiles())
|
||||
diag << path << "\n";
|
||||
auto lexer = llvm::make_unique<script::Lexer>(std::move(mb.get()));
|
||||
auto parser = llvm::make_unique<script::Parser>(*lexer);
|
||||
script::LinkerScript *script = parser->parse();
|
||||
|
@ -259,26 +253,13 @@ evaluateLinkerScript(ELFLinkingContext &ctx, InputGraph *inputGraph,
|
|||
int numfiles = 0;
|
||||
for (const script::Path &path : group->getPaths()) {
|
||||
// TODO : Propagate Set WholeArchive/dashlPrefix
|
||||
ELFLinkingContext::Attributes attr;
|
||||
ELFFileNode::Attributes attr;
|
||||
attr.setSysRooted(sysroot);
|
||||
attr.setAsNeeded(path._asNeeded);
|
||||
attr.setDashlPrefix(path._isDashlPrefix);
|
||||
|
||||
ErrorOr<StringRef> pathOrErr = path._isDashlPrefix
|
||||
? ctx.searchLibrary(path._path) : ctx.searchFile(path._path, sysroot);
|
||||
if (std::error_code ec = pathOrErr.getError())
|
||||
return make_dynamic_error_code(
|
||||
Twine("Unable to find file ") + path._path + ": " + ec.message());
|
||||
|
||||
std::vector<std::unique_ptr<File>> files
|
||||
= loadFile(ctx, pathOrErr.get(), false);
|
||||
for (std::unique_ptr<File> &file : files) {
|
||||
if (ctx.logInputFiles())
|
||||
diag << file->path() << "\n";
|
||||
inputGraph->addInputElement(
|
||||
std::unique_ptr<InputElement>(new WrapperNode(std::move(file))));
|
||||
++numfiles;
|
||||
}
|
||||
++numfiles;
|
||||
inputGraph->addInputElement(llvm::make_unique<ELFFileNode>(
|
||||
ctx, ctx.allocateString(path._path), attr));
|
||||
}
|
||||
inputGraph->addInputElement(llvm::make_unique<GroupEnd>(numfiles));
|
||||
}
|
||||
|
@ -360,7 +341,7 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
|
|||
std::stack<int> groupStack;
|
||||
int numfiles = 0;
|
||||
|
||||
ELFLinkingContext::Attributes attributes;
|
||||
ELFFileNode::Attributes attributes;
|
||||
|
||||
bool _outputOptionSet = false;
|
||||
|
||||
|
@ -398,6 +379,7 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
|
|||
ctx->setPrintRemainingUndefines(false);
|
||||
ctx->setAllowRemainingUndefines(true);
|
||||
break;
|
||||
|
||||
case OPT_static:
|
||||
ctx->setOutputELFType(llvm::ELF::ET_EXEC);
|
||||
ctx->setIsStaticExecutable(true);
|
||||
|
@ -433,37 +415,6 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
|
|||
}
|
||||
}
|
||||
|
||||
for (auto inputArg : *parsedArgs) {
|
||||
switch (inputArg->getOption().getID()) {
|
||||
case OPT_merge_strings:
|
||||
ctx->setMergeCommonStrings(true);
|
||||
break;
|
||||
case OPT_t:
|
||||
ctx->setLogInputFiles(true);
|
||||
break;
|
||||
case OPT_use_shlib_undefs:
|
||||
ctx->setUseShlibUndefines(true);
|
||||
break;
|
||||
case OPT_no_allow_shlib_undefs:
|
||||
ctx->setAllowShlibUndefines(false);
|
||||
break;
|
||||
case OPT_allow_shlib_undefs:
|
||||
ctx->setAllowShlibUndefines(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Register possible input file parsers.
|
||||
ctx->registry().addSupportELFObjects(
|
||||
ctx->mergeCommonStrings(),
|
||||
ctx->targetHandler());
|
||||
ctx->registry().addSupportArchives(ctx->logInputFiles());
|
||||
ctx->registry().addSupportYamlFiles();
|
||||
ctx->registry().addSupportNativeObjects();
|
||||
if (ctx->allowLinkWithDynamicLibraries())
|
||||
ctx->registry().addSupportELFDynamicSharedObjects(
|
||||
ctx->useShlibUndefines(), ctx->targetHandler());
|
||||
|
||||
// Process all the arguments and create Input Elements
|
||||
for (auto inputArg : *parsedArgs) {
|
||||
switch (inputArg->getOption().getID()) {
|
||||
|
@ -487,6 +438,26 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
|
|||
ctx->setExportDynamic(true);
|
||||
break;
|
||||
|
||||
case OPT_merge_strings:
|
||||
ctx->setMergeCommonStrings(true);
|
||||
break;
|
||||
|
||||
case OPT_t:
|
||||
ctx->setLogInputFiles(true);
|
||||
break;
|
||||
|
||||
case OPT_no_allow_shlib_undefs:
|
||||
ctx->setAllowShlibUndefines(false);
|
||||
break;
|
||||
|
||||
case OPT_allow_shlib_undefs:
|
||||
ctx->setAllowShlibUndefines(true);
|
||||
break;
|
||||
|
||||
case OPT_use_shlib_undefs:
|
||||
ctx->setUseShlibUndefines(true);
|
||||
break;
|
||||
|
||||
case OPT_allow_multiple_definition:
|
||||
ctx->setAllowDuplicates(true);
|
||||
break;
|
||||
|
@ -589,19 +560,25 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
|
|||
bool dashL = (inputArg->getOption().getID() == OPT_l);
|
||||
attributes.setDashlPrefix(dashL);
|
||||
StringRef path = inputArg->getValue();
|
||||
std::string realpath = path;
|
||||
|
||||
ErrorOr<StringRef> pathOrErr = findFile(*ctx, path, dashL);
|
||||
if (std::error_code ec = pathOrErr.getError()) {
|
||||
diagnostics << ec.message() << "\n";
|
||||
// If the path was referred to by using a -l argument, let's search
|
||||
// for the file in the search path.
|
||||
if (dashL) {
|
||||
ErrorOr<StringRef> pathOrErr = ctx->searchLibrary(path);
|
||||
if (!pathOrErr) {
|
||||
diagnostics << " Unable to find library -l" << path << "\n";
|
||||
return false;
|
||||
}
|
||||
realpath = pathOrErr->str();
|
||||
}
|
||||
if (!llvm::sys::fs::exists(realpath)) {
|
||||
diagnostics << "lld: cannot find file " << path << "\n";
|
||||
return false;
|
||||
}
|
||||
std::string realpath = pathOrErr.get();
|
||||
|
||||
bool isScript =
|
||||
(!path.endswith(".objtxt") && isLinkerScript(realpath, diagnostics));
|
||||
if (isScript) {
|
||||
if (ctx->logInputFiles())
|
||||
diagnostics << path << "\n";
|
||||
std::error_code ec = evaluateLinkerScript(
|
||||
*ctx, inputGraph.get(), realpath, diagnostics);
|
||||
if (ec) {
|
||||
|
@ -611,15 +588,9 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
|
|||
}
|
||||
break;
|
||||
}
|
||||
std::vector<std::unique_ptr<File>> files
|
||||
= loadFile(*ctx, realpath, attributes._isWholeArchive);
|
||||
for (std::unique_ptr<File> &file : files) {
|
||||
if (ctx->logInputFiles())
|
||||
diagnostics << file->path() << "\n";
|
||||
inputGraph->addInputElement(
|
||||
std::unique_ptr<InputElement>(new WrapperNode(std::move(file))));
|
||||
}
|
||||
numfiles += files.size();
|
||||
++numfiles;
|
||||
inputGraph->addInputElement(
|
||||
llvm::make_unique<ELFFileNode>(*ctx, path, attributes));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -689,6 +660,9 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
|
|||
}
|
||||
}
|
||||
|
||||
if (ctx->outputFileType() == LinkingContext::OutputFileType::YAML)
|
||||
inputGraph->dump(diagnostics);
|
||||
|
||||
// Validate the combination of options used.
|
||||
if (!ctx->validate(diagnostics))
|
||||
return false;
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
//===- lib/Driver/GnuLdInputGraph.cpp -------------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "lld/Driver/GnuLdInputGraph.h"
|
||||
#include "lld/ReaderWriter/LinkerScript.h"
|
||||
#include "llvm/Support/Errc.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
|
||||
using namespace lld;
|
||||
|
||||
llvm::ErrorOr<StringRef> ELFFileNode::getPath(const LinkingContext &) const {
|
||||
if (_attributes._isDashlPrefix)
|
||||
return _elfLinkingContext.searchLibrary(_path);
|
||||
return _elfLinkingContext.searchFile(_path, _attributes._isSysRooted);
|
||||
}
|
||||
|
||||
std::string ELFFileNode::errStr(std::error_code errc) {
|
||||
if (errc == llvm::errc::no_such_file_or_directory) {
|
||||
if (_attributes._isDashlPrefix)
|
||||
return (Twine("Unable to find library -l") + _path).str();
|
||||
return (Twine("Unable to find file ") + _path).str();
|
||||
}
|
||||
return FileNode::errStr(errc);
|
||||
}
|
||||
|
||||
/// \brief Parse the input file to lld::File.
|
||||
std::error_code ELFFileNode::parse(const LinkingContext &ctx,
|
||||
raw_ostream &diagnostics) {
|
||||
ErrorOr<StringRef> filePath = getPath(ctx);
|
||||
if (std::error_code ec = filePath.getError())
|
||||
return ec;
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
|
||||
MemoryBuffer::getFileOrSTDIN(*filePath);
|
||||
if (std::error_code ec = mb.getError())
|
||||
return ec;
|
||||
if (ctx.logInputFiles())
|
||||
diagnostics << *filePath << "\n";
|
||||
|
||||
if (_attributes._isWholeArchive) {
|
||||
std::vector<std::unique_ptr<File>> parsedFiles;
|
||||
if (std::error_code ec = ctx.registry().parseFile(
|
||||
std::move(mb.get()), parsedFiles))
|
||||
return ec;
|
||||
assert(parsedFiles.size() == 1);
|
||||
std::unique_ptr<File> f(parsedFiles[0].release());
|
||||
if (const auto *archive = dyn_cast<ArchiveLibraryFile>(f.get())) {
|
||||
// Have this node own the FileArchive object.
|
||||
_archiveFile.reset(archive);
|
||||
f.release();
|
||||
// Add all members to _files vector
|
||||
return archive->parseAllMembers(_files);
|
||||
}
|
||||
// if --whole-archive is around non-archive, just use it as normal.
|
||||
_files.push_back(std::move(f));
|
||||
return std::error_code();
|
||||
}
|
||||
return ctx.registry().parseFile(std::move(mb.get()), _files);
|
||||
}
|
|
@ -14,8 +14,8 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "lld/Driver/Driver.h"
|
||||
#include "lld/Driver/WinLinkInputGraph.h"
|
||||
#include "lld/Driver/WinLinkModuleDef.h"
|
||||
#include "lld/Driver/WrapperInputGraph.h"
|
||||
#include "lld/ReaderWriter/PECOFFLinkingContext.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
|
@ -800,11 +800,13 @@ parseArgs(int argc, const char **argv, PECOFFLinkingContext &ctx,
|
|||
|
||||
// Returns true if the given file node has already been added to the input
|
||||
// graph.
|
||||
static bool hasLibrary(const PECOFFLinkingContext &ctx, File *file) {
|
||||
StringRef path = file->path();
|
||||
static bool hasLibrary(const PECOFFLinkingContext &ctx, FileNode *fileNode) {
|
||||
ErrorOr<StringRef> path = fileNode->getPath(ctx);
|
||||
if (!path)
|
||||
return false;
|
||||
for (std::unique_ptr<InputElement> &p : ctx.getInputGraph().inputElements())
|
||||
if (auto *f = dyn_cast<FileNode>(p.get()))
|
||||
if (*f->getPath(ctx) == path)
|
||||
if (*path == *f->getPath(ctx))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
@ -836,17 +838,6 @@ static bool maybeRunLibCommand(int argc, const char **argv, raw_ostream &diag) {
|
|||
return true;
|
||||
}
|
||||
|
||||
/// \brief Parse the input file to lld::File.
|
||||
void addFiles(PECOFFLinkingContext &ctx, StringRef path, raw_ostream &diag,
|
||||
std::vector<std::unique_ptr<File>> &files) {
|
||||
for (std::unique_ptr<File> &file : loadFile(ctx, path, false)) {
|
||||
if (ctx.logInputFiles())
|
||||
diag << file->path() << "\n";
|
||||
ctx.getResolvableSymsFile()->add(file.get());
|
||||
files.push_back(std::move(file));
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Main driver
|
||||
//
|
||||
|
@ -856,12 +847,6 @@ bool WinLinkDriver::linkPECOFF(int argc, const char **argv, raw_ostream &diag) {
|
|||
return true;
|
||||
|
||||
PECOFFLinkingContext ctx;
|
||||
ctx.registry().addSupportCOFFObjects(ctx);
|
||||
ctx.registry().addSupportCOFFImportLibraries(ctx);
|
||||
ctx.registry().addSupportArchives(ctx.logInputFiles());
|
||||
ctx.registry().addSupportNativeObjects();
|
||||
ctx.registry().addSupportYamlFiles();
|
||||
|
||||
std::vector<const char *> newargv = processLinkEnv(ctx, argc, argv);
|
||||
processLibEnv(ctx);
|
||||
if (!parse(newargv.size() - 1, &newargv[0], ctx, diag))
|
||||
|
@ -872,6 +857,13 @@ bool WinLinkDriver::linkPECOFF(int argc, const char **argv, raw_ostream &diag) {
|
|||
if (!createSideBySideManifestFile(ctx, diag))
|
||||
return false;
|
||||
|
||||
// Register possible input file parsers.
|
||||
ctx.registry().addSupportCOFFObjects(ctx);
|
||||
ctx.registry().addSupportCOFFImportLibraries(ctx);
|
||||
ctx.registry().addSupportArchives(ctx.logInputFiles());
|
||||
ctx.registry().addSupportNativeObjects();
|
||||
ctx.registry().addSupportYamlFiles();
|
||||
|
||||
return link(ctx, diag);
|
||||
}
|
||||
|
||||
|
@ -892,8 +884,8 @@ bool WinLinkDriver::parse(int argc, const char *argv[],
|
|||
return false;
|
||||
|
||||
// The list of input files.
|
||||
std::vector<std::unique_ptr<File>> files;
|
||||
std::vector<std::unique_ptr<File>> libraries;
|
||||
std::vector<std::unique_ptr<FileNode> > files;
|
||||
std::vector<std::unique_ptr<FileNode> > libraries;
|
||||
|
||||
// Handle /help
|
||||
if (parsedArgs->getLastArg(OPT_help)) {
|
||||
|
@ -1371,9 +1363,11 @@ bool WinLinkDriver::parse(int argc, const char *argv[],
|
|||
for (StringRef path : inputFiles) {
|
||||
path = ctx.allocate(path);
|
||||
if (isLibraryFile(path)) {
|
||||
addFiles(ctx, getLibraryPath(ctx, path), diag, libraries);
|
||||
libraries.push_back(std::unique_ptr<FileNode>(
|
||||
new PECOFFFileNode(ctx, getLibraryPath(ctx, path))));
|
||||
} else {
|
||||
addFiles(ctx, getObjectPath(ctx, path), diag, files);
|
||||
files.push_back(std::unique_ptr<FileNode>(
|
||||
new PECOFFFileNode(ctx, getObjectPath(ctx, path))));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1395,7 +1389,8 @@ bool WinLinkDriver::parse(int argc, const char *argv[],
|
|||
if (!ctx.getNoDefaultLibAll())
|
||||
for (const StringRef path : defaultLibs)
|
||||
if (!ctx.hasNoDefaultLib(path))
|
||||
addFiles(ctx, getLibraryPath(ctx, path.lower()), diag, libraries);
|
||||
libraries.push_back(std::unique_ptr<FileNode>(
|
||||
new PECOFFFileNode(ctx, getLibraryPath(ctx, path.lower()))));
|
||||
|
||||
if (files.empty() && !isReadingDirectiveSection) {
|
||||
diag << "No input files\n";
|
||||
|
@ -1406,19 +1401,18 @@ bool WinLinkDriver::parse(int argc, const char *argv[],
|
|||
// constructed by replacing an extension of the first input file
|
||||
// with ".exe".
|
||||
if (ctx.outputPath().empty()) {
|
||||
StringRef path = files[0]->path();
|
||||
StringRef path = *cast<FileNode>(&*files[0])->getPath(ctx);
|
||||
ctx.setOutputPath(replaceExtension(ctx, path, ".exe"));
|
||||
}
|
||||
|
||||
// Add the input files to the input graph.
|
||||
if (!ctx.hasInputGraph())
|
||||
ctx.setInputGraph(std::unique_ptr<InputGraph>(new InputGraph()));
|
||||
for (std::unique_ptr<File> &file : files) {
|
||||
for (std::unique_ptr<FileNode> &file : files) {
|
||||
if (isReadingDirectiveSection)
|
||||
if (file->parse())
|
||||
if (file->parse(ctx, diag))
|
||||
return false;
|
||||
ctx.getInputGraph().addInputElement(
|
||||
std::unique_ptr<InputElement>(new WrapperNode(std::move(file))));
|
||||
ctx.getInputGraph().addInputElement(std::move(file));
|
||||
}
|
||||
|
||||
// Add the library group to the input graph.
|
||||
|
@ -1433,13 +1427,12 @@ bool WinLinkDriver::parse(int argc, const char *argv[],
|
|||
}
|
||||
|
||||
// Add the library files to the library group.
|
||||
for (std::unique_ptr<File> &file : libraries) {
|
||||
if (!hasLibrary(ctx, file.get())) {
|
||||
for (std::unique_ptr<FileNode> &lib : libraries) {
|
||||
if (!hasLibrary(ctx, lib.get())) {
|
||||
if (isReadingDirectiveSection)
|
||||
if (file->parse())
|
||||
if (lib->parse(ctx, diag))
|
||||
return false;
|
||||
ctx.addLibraryFile(
|
||||
std::unique_ptr<FileNode>(new WrapperNode(std::move(file))));
|
||||
ctx.addLibraryFile(std::move(lib));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
//===- lib/Driver/WinLinkInputGraph.cpp -----------------------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "lld/Driver/WinLinkInputGraph.h"
|
||||
|
||||
namespace lld {
|
||||
|
||||
/// \brief Parse the input file to lld::File.
|
||||
std::error_code PECOFFFileNode::parse(const LinkingContext &ctx,
|
||||
raw_ostream &diagnostics) {
|
||||
if (_parsed)
|
||||
return std::error_code();
|
||||
_parsed = true;
|
||||
ErrorOr<StringRef> filePath = getPath(ctx);
|
||||
if (std::error_code ec = filePath.getError()) {
|
||||
diagnostics << "File not found: " << _path << "\n";
|
||||
return ec;
|
||||
}
|
||||
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> mb =
|
||||
MemoryBuffer::getFileOrSTDIN(*filePath);
|
||||
if (std::error_code ec = mb.getError()) {
|
||||
diagnostics << "Cannot open file: " << *filePath << "\n";
|
||||
return ec;
|
||||
}
|
||||
|
||||
if (ctx.logInputFiles())
|
||||
diagnostics << *filePath << "\n";
|
||||
|
||||
return ctx.registry().parseFile(std::move(mb.get()), _files);
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
|
@ -40,15 +40,13 @@ void RoundTripNativePass::perform(std::unique_ptr<MutableFile> &mergedFile) {
|
|||
if (!mb)
|
||||
return;
|
||||
|
||||
std::error_code ec = _context.registry().loadFile(
|
||||
std::error_code ec = _context.registry().parseFile(
|
||||
std::move(mb.get()), _nativeFile);
|
||||
if (ec) {
|
||||
// Note: we need a way for Passes to report errors.
|
||||
llvm_unreachable("native reader not registered or read error");
|
||||
}
|
||||
File *objFile = _nativeFile[0].get();
|
||||
if (objFile->parse())
|
||||
llvm_unreachable("native reader parse error");
|
||||
mergedFile.reset(new SimpleFileWrapper(_context, *objFile));
|
||||
|
||||
llvm::sys::fs::remove(tmpNativeFile.str());
|
||||
|
|
|
@ -40,15 +40,13 @@ void RoundTripYAMLPass::perform(std::unique_ptr<MutableFile> &mergedFile) {
|
|||
if (!mb)
|
||||
return;
|
||||
|
||||
std::error_code ec = _context.registry().loadFile(
|
||||
std::error_code ec = _context.registry().parseFile(
|
||||
std::move(mb.get()), _yamlFile);
|
||||
if (ec) {
|
||||
// Note: we need a way for Passes to report errors.
|
||||
llvm_unreachable("yaml reader not registered or read error");
|
||||
}
|
||||
File *objFile = _yamlFile[0].get();
|
||||
if (objFile->parse())
|
||||
llvm_unreachable("native reader parse error");
|
||||
mergedFile.reset(new SimpleFileWrapper(_context, *objFile));
|
||||
llvm::sys::fs::remove(tmpYAMLFile.str());
|
||||
}
|
||||
|
|
|
@ -33,8 +33,8 @@ public:
|
|||
}
|
||||
|
||||
std::error_code
|
||||
loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
|
||||
std::vector<std::unique_ptr<File>> &result) const override {
|
||||
parseFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
|
||||
std::vector<std::unique_ptr<File>> &result) const override {
|
||||
std::size_t maxAlignment =
|
||||
1ULL << llvm::countTrailingZeros(uintptr_t(mb->getBufferStart()));
|
||||
auto f =
|
||||
|
@ -72,8 +72,8 @@ public:
|
|||
}
|
||||
|
||||
std::error_code
|
||||
loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
|
||||
std::vector<std::unique_ptr<File>> &result) const override {
|
||||
parseFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
|
||||
std::vector<std::unique_ptr<File>> &result) const override {
|
||||
std::size_t maxAlignment =
|
||||
1ULL << llvm::countTrailingZeros(uintptr_t(mb->getBufferStart()));
|
||||
auto f =
|
||||
|
|
|
@ -49,12 +49,12 @@ public:
|
|||
_flagMerger(flagMerger) {}
|
||||
|
||||
std::error_code
|
||||
loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry ®istry,
|
||||
std::vector<std::unique_ptr<File>> &result) const override {
|
||||
parseFile(std::unique_ptr<MemoryBuffer> mb, const Registry ®istry,
|
||||
std::vector<std::unique_ptr<File>> &result) const override {
|
||||
auto &hdr = *elfHeader(*mb);
|
||||
if (std::error_code ec = _flagMerger.merge(hdr.getFileClass(), hdr.e_flags))
|
||||
return ec;
|
||||
return BaseReaderType::loadFile(std::move(mb), registry, result);
|
||||
return BaseReaderType::parseFile(std::move(mb), registry, result);
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -72,12 +72,12 @@ public:
|
|||
_flagMerger(flagMerger) {}
|
||||
|
||||
std::error_code
|
||||
loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry ®istry,
|
||||
std::vector<std::unique_ptr<File>> &result) const override {
|
||||
parseFile(std::unique_ptr<MemoryBuffer> mb, const Registry ®istry,
|
||||
std::vector<std::unique_ptr<File>> &result) const override {
|
||||
auto &hdr = *elfHeader(*mb);
|
||||
if (std::error_code ec = _flagMerger.merge(hdr.getFileClass(), hdr.e_flags))
|
||||
return ec;
|
||||
return BaseReaderType::loadFile(std::move(mb), registry, result);
|
||||
return BaseReaderType::parseFile(std::move(mb), registry, result);
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -67,9 +67,7 @@ public:
|
|||
|
||||
/// \brief parse each member
|
||||
std::error_code
|
||||
parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
|
||||
if (std::error_code ec = parse())
|
||||
return ec;
|
||||
parseAllMembers(std::vector<std::unique_ptr<File>> &result) const override {
|
||||
for (auto mf = _archive->child_begin(), me = _archive->child_end();
|
||||
mf != me; ++mf) {
|
||||
std::unique_ptr<File> file;
|
||||
|
@ -154,12 +152,9 @@ private:
|
|||
mb.getBuffer(), memberPath, false));
|
||||
|
||||
std::vector<std::unique_ptr<File>> files;
|
||||
if (std::error_code ec = _registry.loadFile(std::move(memberMB), files))
|
||||
return ec;
|
||||
_registry.parseFile(std::move(memberMB), files);
|
||||
assert(files.size() == 1);
|
||||
result = std::move(files[0]);
|
||||
if (std::error_code ec = result->parse())
|
||||
return ec;
|
||||
|
||||
// The memory buffer is co-owned by the archive file and the children,
|
||||
// so that the bufffer is deallocated when all the members are destructed.
|
||||
|
@ -237,8 +232,8 @@ public:
|
|||
}
|
||||
|
||||
std::error_code
|
||||
loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry ®,
|
||||
std::vector<std::unique_ptr<File>> &result) const override {
|
||||
parseFile(std::unique_ptr<MemoryBuffer> mb, const Registry ®,
|
||||
std::vector<std::unique_ptr<File>> &result) const override {
|
||||
StringRef path = mb->getBufferIdentifier();
|
||||
std::unique_ptr<FileArchive> file(
|
||||
new FileArchive(std::move(mb), reg, path, _logLoading));
|
||||
|
|
|
@ -91,7 +91,7 @@ public:
|
|||
}
|
||||
|
||||
std::error_code
|
||||
parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
|
||||
parseAllMembers(std::vector<std::unique_ptr<File>> &result) const override {
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
#include "File.h"
|
||||
#include "MachONormalizedFile.h"
|
||||
#include "MachOPasses.h"
|
||||
#include "lld/Core/ArchiveLibraryFile.h"
|
||||
#include "lld/Core/PassManager.h"
|
||||
#include "lld/Driver/DarwinInputGraph.h"
|
||||
#include "lld/Passes/LayoutPass.h"
|
||||
#include "lld/Passes/RoundTripYAMLPass.h"
|
||||
#include "lld/ReaderWriter/Reader.h"
|
||||
|
@ -605,18 +605,20 @@ Writer &MachOLinkingContext::writer() const {
|
|||
}
|
||||
|
||||
MachODylibFile* MachOLinkingContext::loadIndirectDylib(StringRef path) {
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr
|
||||
= MemoryBuffer::getFileOrSTDIN(path);
|
||||
if (mbOrErr.getError())
|
||||
std::unique_ptr<MachOFileNode> node(new MachOFileNode(path, *this));
|
||||
std::error_code ec = node->parse(*this, llvm::errs());
|
||||
if (ec)
|
||||
return nullptr;
|
||||
|
||||
std::vector<std::unique_ptr<File>> files;
|
||||
if (registry().loadFile(std::move(mbOrErr.get()), files))
|
||||
return nullptr;
|
||||
assert(files.size() == 1 && "expected one file in dylib");
|
||||
MachODylibFile* result = reinterpret_cast<MachODylibFile*>(files[0].get());
|
||||
assert(node->files().size() == 1 && "expected one file in dylib");
|
||||
// lld::File object is owned by MachOFileNode object. This method returns
|
||||
// an unowned pointer to the lld::File object.
|
||||
MachODylibFile* result = reinterpret_cast<MachODylibFile*>(
|
||||
node->files().front().get());
|
||||
|
||||
// Node object now owned by _indirectDylibs vector.
|
||||
_indirectDylibs.push_back(std::move(files[0]));
|
||||
_indirectDylibs.push_back(std::move(node));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -928,7 +930,9 @@ bool MachOLinkingContext::customAtomOrderer(const DefinedAtom *left,
|
|||
|
||||
static File *getFirstFile(const std::unique_ptr<InputElement> &elem) {
|
||||
FileNode *e = dyn_cast<FileNode>(const_cast<InputElement *>(elem.get()));
|
||||
return e ? e->getFile() : nullptr;
|
||||
if (!e || e->files().empty())
|
||||
return nullptr;
|
||||
return e->files()[0].get();
|
||||
}
|
||||
|
||||
static bool isLibrary(const std::unique_ptr<InputElement> &elem) {
|
||||
|
|
|
@ -527,8 +527,8 @@ public:
|
|||
}
|
||||
|
||||
std::error_code
|
||||
loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry ®istry,
|
||||
std::vector<std::unique_ptr<File>> &result) const override {
|
||||
parseFile(std::unique_ptr<MemoryBuffer> mb, const Registry ®istry,
|
||||
std::vector<std::unique_ptr<File>> &result) const override {
|
||||
auto *file = new MachOFile(std::move(mb), &_ctx);
|
||||
result.push_back(std::unique_ptr<MachOFile>(file));
|
||||
return std::error_code();
|
||||
|
@ -554,8 +554,8 @@ public:
|
|||
}
|
||||
|
||||
std::error_code
|
||||
loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry ®istry,
|
||||
std::vector<std::unique_ptr<File>> &result) const override {
|
||||
parseFile(std::unique_ptr<MemoryBuffer> mb, const Registry ®istry,
|
||||
std::vector<std::unique_ptr<File>> &result) const override {
|
||||
auto *file = new MachODylibFile(std::move(mb), &_ctx);
|
||||
result.push_back(std::unique_ptr<MachODylibFile>(file));
|
||||
return std::error_code();
|
||||
|
@ -580,3 +580,4 @@ void Registry::addSupportMachOObjects(MachOLinkingContext &ctx) {
|
|||
|
||||
|
||||
} // namespace lld
|
||||
|
||||
|
|
|
@ -999,8 +999,8 @@ public:
|
|||
}
|
||||
|
||||
virtual std::error_code
|
||||
loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
|
||||
std::vector<std::unique_ptr<File>> &result) const override {
|
||||
parseFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
|
||||
std::vector<std::unique_ptr<File>> &result) const override {
|
||||
auto *file = new lld::native::File(std::move(mb));
|
||||
result.push_back(std::unique_ptr<File>(file));
|
||||
return std::error_code();
|
||||
|
|
|
@ -88,7 +88,7 @@ public:
|
|||
}
|
||||
|
||||
std::error_code
|
||||
parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
|
||||
parseAllMembers(std::vector<std::unique_ptr<File>> &result) const override {
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
|
@ -174,6 +174,45 @@ private:
|
|||
mutable llvm::BumpPtrAllocator _alloc;
|
||||
};
|
||||
|
||||
class ResolvableSymbols {
|
||||
public:
|
||||
void add(File *file) {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
if (_seen.count(file) > 0)
|
||||
return;
|
||||
_seen.insert(file);
|
||||
_queue.insert(file);
|
||||
}
|
||||
|
||||
const std::set<std::string> &defined() {
|
||||
readAllSymbols();
|
||||
return _defined;
|
||||
}
|
||||
|
||||
private:
|
||||
// Files are read lazily, so that it has no runtime overhead if
|
||||
// no one accesses this class.
|
||||
void readAllSymbols() {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
for (File *file : _queue) {
|
||||
if (auto *archive = dyn_cast<ArchiveLibraryFile>(file)) {
|
||||
for (const std::string &sym : archive->getDefinedSymbols())
|
||||
_defined.insert(sym);
|
||||
continue;
|
||||
}
|
||||
for (const DefinedAtom *atom : file->defined())
|
||||
if (!atom->name().empty())
|
||||
_defined.insert(atom->name());
|
||||
}
|
||||
_queue.clear();
|
||||
}
|
||||
|
||||
std::set<std::string> _defined;
|
||||
std::set<File *> _seen;
|
||||
std::set<File *> _queue;
|
||||
std::mutex _mutex;
|
||||
};
|
||||
|
||||
// A ExportedSymbolRenameFile is a virtual archive file for dllexported symbols.
|
||||
//
|
||||
// One usually has to specify the exact symbol name to resolve it. That's true
|
||||
|
@ -207,7 +246,7 @@ private:
|
|||
class ExportedSymbolRenameFile : public impl::VirtualArchiveLibraryFile {
|
||||
public:
|
||||
ExportedSymbolRenameFile(const PECOFFLinkingContext &ctx,
|
||||
ResolvableSymbols *syms)
|
||||
std::shared_ptr<ResolvableSymbols> syms)
|
||||
: VirtualArchiveLibraryFile("<export>"), _syms(syms),
|
||||
_ctx(const_cast<PECOFFLinkingContext *>(&ctx)) {
|
||||
for (PECOFFLinkingContext::ExportDesc &desc : _ctx->getDllExports())
|
||||
|
@ -219,7 +258,7 @@ public:
|
|||
if (_exportedSyms.count(sym) == 0)
|
||||
return nullptr;
|
||||
std::string replace;
|
||||
if (!findDecoratedSymbol(_ctx, _syms, sym.str(), replace))
|
||||
if (!findDecoratedSymbol(_ctx, _syms.get(), sym.str(), replace))
|
||||
return nullptr;
|
||||
|
||||
for (ExportDesc &exp : _ctx->getDllExports())
|
||||
|
@ -232,7 +271,7 @@ public:
|
|||
|
||||
private:
|
||||
std::set<std::string> _exportedSyms;
|
||||
ResolvableSymbols *_syms;
|
||||
std::shared_ptr<ResolvableSymbols> _syms;
|
||||
mutable llvm::BumpPtrAllocator _alloc;
|
||||
mutable PECOFFLinkingContext *_ctx;
|
||||
};
|
||||
|
@ -245,7 +284,7 @@ private:
|
|||
class EntryPointFile : public SimpleFile {
|
||||
public:
|
||||
EntryPointFile(const PECOFFLinkingContext &ctx,
|
||||
ResolvableSymbols *syms)
|
||||
std::shared_ptr<ResolvableSymbols> syms)
|
||||
: SimpleFile("<entry>"), _ctx(const_cast<PECOFFLinkingContext *>(&ctx)),
|
||||
_syms(syms), _firstTime(true) {}
|
||||
|
||||
|
@ -277,7 +316,7 @@ private:
|
|||
StringRef opt = _ctx->getEntrySymbolName();
|
||||
if (!opt.empty()) {
|
||||
std::string mangled;
|
||||
if (findDecoratedSymbol(_ctx, _syms, opt, mangled))
|
||||
if (findDecoratedSymbol(_ctx, _syms.get(), opt, mangled))
|
||||
return mangled;
|
||||
return _ctx->decorateSymbol(opt);
|
||||
}
|
||||
|
@ -302,7 +341,7 @@ private:
|
|||
if (_syms->defined().count(sym))
|
||||
return true;
|
||||
std::string ignore;
|
||||
return findDecoratedSymbol(_ctx, _syms, sym, ignore);
|
||||
return findDecoratedSymbol(_ctx, _syms.get(), sym, ignore);
|
||||
};
|
||||
|
||||
switch (_ctx->getSubsystem()) {
|
||||
|
@ -333,7 +372,7 @@ private:
|
|||
PECOFFLinkingContext *_ctx;
|
||||
atom_collection_vector<UndefinedAtom> _undefinedAtoms;
|
||||
std::mutex _mutex;
|
||||
ResolvableSymbols *_syms;
|
||||
std::shared_ptr<ResolvableSymbols> _syms;
|
||||
llvm::BumpPtrAllocator _alloc;
|
||||
bool _firstTime;
|
||||
};
|
||||
|
|
|
@ -118,7 +118,9 @@ bool PECOFFLinkingContext::createImplicitFiles(
|
|||
llvm::make_unique<pecoff::LocallyImportedSymbolFile>(*this));
|
||||
getInputGraph().addInputElement(std::move(impFileNode));
|
||||
|
||||
pecoff::ResolvableSymbols* syms = getResolvableSymsFile();
|
||||
std::shared_ptr<pecoff::ResolvableSymbols> syms(
|
||||
new pecoff::ResolvableSymbols());
|
||||
getInputGraph().registerObserver([=](File *file) { syms->add(file); });
|
||||
|
||||
// Create a file for dllexported symbols.
|
||||
auto exportNode = llvm::make_unique<SimpleFileNode>("<export>");
|
||||
|
@ -329,27 +331,4 @@ void PECOFFLinkingContext::addPasses(PassManager &pm) {
|
|||
pm.add(std::unique_ptr<Pass>(new pecoff::InferSubsystemPass(*this)));
|
||||
}
|
||||
|
||||
void pecoff::ResolvableSymbols::add(File *file) {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
if (_seen.count(file) > 0)
|
||||
return;
|
||||
_seen.insert(file);
|
||||
_queue.insert(file);
|
||||
}
|
||||
|
||||
void pecoff::ResolvableSymbols::readAllSymbols() {
|
||||
std::lock_guard<std::mutex> lock(_mutex);
|
||||
for (File *file : _queue) {
|
||||
if (auto *archive = dyn_cast<ArchiveLibraryFile>(file)) {
|
||||
for (const std::string &sym : archive->getDefinedSymbols())
|
||||
_defined.insert(sym);
|
||||
continue;
|
||||
}
|
||||
for (const DefinedAtom *atom : file->defined())
|
||||
if (!atom->name().empty())
|
||||
_defined.insert(atom->name());
|
||||
}
|
||||
_queue.clear();
|
||||
}
|
||||
|
||||
} // end namespace lld
|
||||
|
|
|
@ -1077,8 +1077,8 @@ public:
|
|||
}
|
||||
|
||||
std::error_code
|
||||
loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &,
|
||||
std::vector<std::unique_ptr<File>> &result) const override {
|
||||
parseFile(std::unique_ptr<MemoryBuffer> mb, const Registry &,
|
||||
std::vector<std::unique_ptr<File>> &result) const override {
|
||||
// Parse the memory buffer as PECOFF file.
|
||||
auto *file = new FileCOFF(std::move(mb), _ctx);
|
||||
result.push_back(std::unique_ptr<File>(file));
|
||||
|
|
|
@ -364,8 +364,8 @@ public:
|
|||
}
|
||||
|
||||
std::error_code
|
||||
loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
|
||||
std::vector<std::unique_ptr<File> > &result) const override {
|
||||
parseFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
|
||||
std::vector<std::unique_ptr<File> > &result) const override {
|
||||
auto *file = new FileImportLibrary(std::move(mb), _machine);
|
||||
result.push_back(std::unique_ptr<File>(file));
|
||||
return std::error_code();
|
||||
|
|
|
@ -30,8 +30,8 @@ void Registry::add(std::unique_ptr<YamlIOTaggedDocumentHandler> handler) {
|
|||
}
|
||||
|
||||
std::error_code
|
||||
Registry::loadFile(std::unique_ptr<MemoryBuffer> mb,
|
||||
std::vector<std::unique_ptr<File>> &result) const {
|
||||
Registry::parseFile(std::unique_ptr<MemoryBuffer> mb,
|
||||
std::vector<std::unique_ptr<File>> &result) const {
|
||||
// Get file type.
|
||||
StringRef content(mb->getBufferStart(), mb->getBufferSize());
|
||||
llvm::sys::fs::file_magic fileType = llvm::sys::fs::identify_magic(content);
|
||||
|
@ -42,8 +42,11 @@ Registry::loadFile(std::unique_ptr<MemoryBuffer> mb,
|
|||
for (const std::unique_ptr<Reader> &reader : _readers) {
|
||||
if (!reader->canParse(fileType, extension, *mb))
|
||||
continue;
|
||||
if (std::error_code ec = reader->loadFile(std::move(mb), *this, result))
|
||||
if (std::error_code ec = reader->parseFile(std::move(mb), *this, result))
|
||||
return ec;
|
||||
for (std::unique_ptr<File> &file : result)
|
||||
if (std::error_code ec = file->parse())
|
||||
return ec;
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
|
|
|
@ -648,7 +648,7 @@ template <> struct MappingTraits<const lld::File *> {
|
|||
}
|
||||
|
||||
virtual std::error_code
|
||||
parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
|
||||
parseAllMembers(std::vector<std::unique_ptr<File>> &result) const override {
|
||||
return std::error_code();
|
||||
}
|
||||
|
||||
|
@ -1325,8 +1325,8 @@ public:
|
|||
}
|
||||
|
||||
std::error_code
|
||||
loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
|
||||
std::vector<std::unique_ptr<File>> &result) const override {
|
||||
parseFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
|
||||
std::vector<std::unique_ptr<File>> &result) const override {
|
||||
// Create YAML Input Reader.
|
||||
YamlContext yamlContext;
|
||||
yamlContext._registry = &_registry;
|
||||
|
@ -1343,7 +1343,7 @@ public:
|
|||
|
||||
std::shared_ptr<MemoryBuffer> smb(mb.release());
|
||||
for (const File *file : createdFiles) {
|
||||
// Note: loadFile() should return vector of *const* File
|
||||
// Note: parseFile() should return vector of *const* File
|
||||
File *f = const_cast<File *>(file);
|
||||
f->setLastError(std::error_code());
|
||||
f->setSharedMemoryBuffer(smb);
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
RUN: lld -flavor gnu -target x86_64-linux -L%p/../elf/Inputs -lfnarchive \
|
||||
RUN: --output-filetype=yaml --noinhibit-exec 2> %t.err
|
||||
RUN: FileCheck %s < %t.err
|
||||
|
||||
RUN: lld -flavor gnu -target x86_64-linux -L%p/../elf/Inputs --whole-archive \
|
||||
RUN: -lfnarchive --output-filetype=yaml --noinhibit-exec 2> %t1.err
|
||||
RUN: FileCheck %s -check-prefix="WHOLEARCHIVE" < %t1.err
|
||||
|
||||
RUN: lld -flavor gnu -target x86_64-linux -L%p/../elf/Inputs --whole-archive \
|
||||
RUN: --as-needed -lfnarchive --output-filetype=yaml --noinhibit-exec 2> %t2.err
|
||||
RUN: FileCheck %s -check-prefix="ASNEEDED" < %t2.err
|
||||
|
||||
RUN: lld -flavor gnu -target x86_64-linux --sysroot=%p/../elf -L=/Inputs \
|
||||
RUN: -lfnarchive --output-filetype=yaml --noinhibit-exec 2> %t3.err
|
||||
RUN: FileCheck -check-prefix="SYSROOT" %s < %t3.err
|
||||
|
||||
CHECK: Name : {{[^ ]+}}elf/Inputs{{[\\/]}}libfnarchive.a
|
||||
CHECK: Type : ELF File
|
||||
CHECK: Attributes :
|
||||
CHECK: - wholeArchive : false
|
||||
CHECK: - asNeeded : false
|
||||
|
||||
WHOLEARCHIVE: Name : {{[^ ]+}}elf/Inputs{{[\\/]}}libfnarchive.a
|
||||
WHOLEARCHIVE: Type : ELF File
|
||||
WHOLEARCHIVE: Attributes :
|
||||
WHOLEARCHIVE: - wholeArchive : true
|
||||
WHOLEARCHIVE: - asNeeded : false
|
||||
|
||||
ASNEEDED: Name : {{[^ ]+}}elf/Inputs{{[\\/]}}libfnarchive.a
|
||||
ASNEEDED: Type : ELF File
|
||||
ASNEEDED: Attributes :
|
||||
ASNEEDED: - wholeArchive : true
|
||||
ASNEEDED: - asNeeded : true
|
||||
|
||||
SYSROOT: Name : {{[^ ]+}}elf/Inputs{{[\\/]}}libfnarchive.a
|
||||
SYSROOT: Type : ELF File
|
||||
SYSROOT: Attributes :
|
||||
SYSROOT: - wholeArchive : false
|
||||
SYSROOT: - asNeeded : false
|
|
@ -12,9 +12,9 @@ CHECK: 6019: 41 b9 00 00 00 00 movl $0, %r9d
|
|||
CHECK: 601f: e8 0a 00 00 00 callq 10
|
||||
CHECK: 6024: b9 00 00 00 00 movl $0, %ecx
|
||||
CHECK: 6029: e8 08 00 00 00 callq 8
|
||||
CHECK: 602e: ff 25 d2 cf ff ff jmpq *-12334(%rip)
|
||||
CHECK: 602e: ff 25 d4 cf ff ff jmpq *-12332(%rip)
|
||||
CHECK: 6034: cc int3
|
||||
CHECK: 6035: cc int3
|
||||
CHECK: 6036: ff 25 c2 cf ff ff jmpq *-12350(%rip)
|
||||
CHECK: 6036: ff 25 c4 cf ff ff jmpq *-12348(%rip)
|
||||
CHECK: 603c: cc int3
|
||||
CHECK: 603d: cc int3
|
||||
|
|
|
@ -4,6 +4,7 @@ add_lld_unittest(DriverTests
|
|||
DarwinLdDriverTest.cpp
|
||||
WinLinkDriverTest.cpp
|
||||
WinLinkModuleDefTest.cpp
|
||||
InputGraphTest.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(DriverTests
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
//===- lld/unittest/InputGraphTest.cpp -----------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief InputGraph Tests
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "lld/Core/InputGraph.h"
|
||||
#include "lld/Core/Resolver.h"
|
||||
#include "lld/Core/Simple.h"
|
||||
|
||||
using namespace lld;
|
||||
|
||||
namespace {
|
||||
|
||||
class TestLinkingContext : public LinkingContext {
|
||||
public:
|
||||
Writer &writer() const override { llvm_unreachable("no writer!"); }
|
||||
bool validateImpl(raw_ostream &) override { return true; }
|
||||
};
|
||||
|
||||
class TestExpandFileNode : public SimpleFileNode {
|
||||
public:
|
||||
TestExpandFileNode(StringRef path) : SimpleFileNode(path) {}
|
||||
|
||||
/// Returns the elements replacing this node
|
||||
bool getReplacements(InputGraph::InputElementVectorT &result) override {
|
||||
for (std::unique_ptr<InputElement> &elt : _expandElements)
|
||||
result.push_back(std::move(elt));
|
||||
return true;
|
||||
}
|
||||
|
||||
void addElement(std::unique_ptr<InputElement> element) {
|
||||
_expandElements.push_back(std::move(element));
|
||||
}
|
||||
|
||||
private:
|
||||
InputGraph::InputElementVectorT _expandElements;
|
||||
};
|
||||
|
||||
class InputGraphTest : public testing::Test {
|
||||
public:
|
||||
InputGraphTest() {
|
||||
_ctx.setInputGraph(std::unique_ptr<InputGraph>(new InputGraph()));
|
||||
_graph = &_ctx.getInputGraph();
|
||||
}
|
||||
|
||||
StringRef getNext() {
|
||||
File *file = _graph->getNextFile();
|
||||
EXPECT_TRUE(file);
|
||||
return file->path();
|
||||
}
|
||||
|
||||
void expectEnd() {
|
||||
File *file = _graph->getNextFile();
|
||||
EXPECT_TRUE(file == nullptr);
|
||||
}
|
||||
|
||||
protected:
|
||||
TestLinkingContext _ctx;
|
||||
InputGraph *_graph;
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
static std::unique_ptr<SimpleFileNode> createFile(StringRef name) {
|
||||
std::vector<std::unique_ptr<File>> files;
|
||||
files.push_back(std::unique_ptr<SimpleFile>(new SimpleFile(name)));
|
||||
std::unique_ptr<SimpleFileNode> file(new SimpleFileNode("filenode"));
|
||||
file->addFiles(std::move(files));
|
||||
return file;
|
||||
}
|
||||
|
||||
TEST_F(InputGraphTest, Empty) {
|
||||
expectEnd();
|
||||
}
|
||||
|
||||
TEST_F(InputGraphTest, File) {
|
||||
_graph->addInputElement(createFile("file1"));
|
||||
EXPECT_EQ("file1", getNext());
|
||||
expectEnd();
|
||||
}
|
||||
|
||||
// Node expansion tests
|
||||
TEST_F(InputGraphTest, Normalize) {
|
||||
_graph->addInputElement(createFile("file1"));
|
||||
|
||||
std::unique_ptr<TestExpandFileNode> expandFile(
|
||||
new TestExpandFileNode("node"));
|
||||
expandFile->addElement(createFile("file2"));
|
||||
expandFile->addElement(createFile("file3"));
|
||||
_graph->addInputElement(std::move(expandFile));
|
||||
_graph->normalize();
|
||||
|
||||
EXPECT_EQ("file1", getNext());
|
||||
EXPECT_EQ("file2", getNext());
|
||||
EXPECT_EQ("file3", getNext());
|
||||
expectEnd();
|
||||
}
|
||||
|
||||
TEST_F(InputGraphTest, Observer) {
|
||||
std::vector<std::string> files;
|
||||
_graph->registerObserver([&](File *file) { files.push_back(file->path()); });
|
||||
|
||||
_graph->addInputElement(createFile("file1"));
|
||||
_graph->addInputElement(createFile("file2"));
|
||||
EXPECT_EQ("file1", getNext());
|
||||
EXPECT_EQ("file2", getNext());
|
||||
expectEnd();
|
||||
|
||||
EXPECT_EQ(2U, files.size());
|
||||
EXPECT_EQ("file1", files[0]);
|
||||
EXPECT_EQ("file2", files[1]);
|
||||
}
|
|
@ -698,9 +698,10 @@ TEST_F(WinLinkParserTest, Ignore) {
|
|||
// compatibility with link.exe.
|
||||
EXPECT_TRUE(parse("link.exe", "/nologo", "/errorreport:prompt",
|
||||
"/incremental", "/incremental:no", "/delay:unload",
|
||||
"/disallowlib:foo", "/pdbaltpath:bar",
|
||||
"/wx", "/wx:no", "/tlbid:1", "/tlbout:foo", "/idlout:foo",
|
||||
"/ignore:4000", "/ignoreidl", "/implib:foo", "/safeseh",
|
||||
"/disallowlib:foo", "/pdbaltpath:bar", "/verbose",
|
||||
"/verbose:icf", "/wx", "/wx:no", "/tlbid:1",
|
||||
"/tlbout:foo", "/idlout:foo", "/ignore:4000",
|
||||
"/ignoreidl", "/implib:foo", "/safeseh",
|
||||
"/safeseh:no", "/functionpadmin", "/maxilksize:1024",
|
||||
"a.obj", nullptr));
|
||||
EXPECT_EQ("", errorMessage());
|
||||
|
|
Loading…
Reference in New Issue