Re-commit r225674: Convert other drivers to use WrapperNode.

The original commit had an issue with Mac OS dylib files. It didn't
handle fat binary dylib files correctly. This patch includes a fix.
A test for that case has already been committed in r225764.

llvm-svn: 226123
This commit is contained in:
Rui Ueyama 2015-01-15 04:34:31 +00:00
parent 6725a83e84
commit df230b21e3
35 changed files with 304 additions and 604 deletions

View File

@ -66,7 +66,7 @@ Readers are factories
--------------------- ---------------------
The linker will usually only instantiate your Reader once. That one Reader will The linker will usually only instantiate your Reader once. That one Reader will
have its parseFile() method called many times with different input files. have its loadFile() method called many times with different input files.
To support multithreaded linking, the Reader may be parsing multiple input To support multithreaded linking, the Reader may be parsing multiple input
files in parallel. Therefore, there should be no parsing state in you Reader 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 object. Any parsing state should be in ivars of your File subclass or in
@ -74,7 +74,7 @@ some temporary object.
The key method to implement in a reader is:: The key method to implement in a reader is::
virtual error_code parseFile(LinkerInput &input, virtual error_code loadFile(LinkerInput &input,
std::vector<std::unique_ptr<File>> &result); std::vector<std::unique_ptr<File>> &result);
It takes a memory buffer (which contains the contents of the object file It takes a memory buffer (which contains the contents of the object file

View File

@ -35,7 +35,7 @@ public:
virtual const File *find(StringRef name, bool dataSymbolOnly) const = 0; virtual const File *find(StringRef name, bool dataSymbolOnly) const = 0;
virtual std::error_code virtual std::error_code
parseAllMembers(std::vector<std::unique_ptr<File>> &result) const = 0; parseAllMembers(std::vector<std::unique_ptr<File>> &result) = 0;
/// Returns a set of all defined symbols in the archive, i.e. all /// Returns a set of all defined symbols in the archive, i.e. all
/// resolvable symbol using this file. /// resolvable symbol using this file.

View File

@ -274,7 +274,8 @@ protected:
/// can do unit testing a driver using non-existing file paths. /// can do unit testing a driver using non-existing file paths.
class ErrorFile : public File { class ErrorFile : public File {
public: public:
ErrorFile(StringRef p, std::error_code ec) : File(p, kindObject), _ec(ec) {} ErrorFile(StringRef path, std::error_code ec)
: File(path, kindObject), _ec(ec) {}
std::error_code doParse() override { return _ec; } std::error_code doParse() override { return _ec; }

View File

@ -1,56 +0,0 @@
//===- 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

View File

@ -36,7 +36,7 @@ typedef std::vector<std::unique_ptr<File>> FileVector;
FileVector makeErrorFile(StringRef path, std::error_code ec); FileVector makeErrorFile(StringRef path, std::error_code ec);
FileVector parseMemberFiles(FileVector &files); FileVector parseMemberFiles(FileVector &files);
FileVector parseFile(LinkingContext &ctx, StringRef path, bool wholeArchive); FileVector loadFile(LinkingContext &ctx, StringRef path, bool wholeArchive);
/// Base class for all Drivers. /// Base class for all Drivers.
class Driver { class Driver {
@ -101,6 +101,11 @@ public:
static bool parse(int argc, const char *argv[], MachOLinkingContext &info, static bool parse(int argc, const char *argv[], MachOLinkingContext &info,
raw_ostream &diagnostics = llvm::errs()); raw_ostream &diagnostics = llvm::errs());
// Reads a file from disk to memory. Returns only a needed chunk
// if a fat binary.
static ErrorOr<std::unique_ptr<MemoryBuffer>>
getMemoryBuffer(MachOLinkingContext &ctx, StringRef path);
private: private:
DarwinLdDriver() LLVM_DELETED_FUNCTION; DarwinLdDriver() LLVM_DELETED_FUNCTION;
}; };

View File

@ -1,85 +0,0 @@
//===- 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

View File

@ -1,45 +0,0 @@
//===- 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

View File

@ -290,6 +290,28 @@ public:
bool alignSegments() const { return _alignSegments; } bool alignSegments() const { return _alignSegments; }
void setAlignSegments(bool align) { _alignSegments = align; } 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: private:
ELFLinkingContext() LLVM_DELETED_FUNCTION; ELFLinkingContext() LLVM_DELETED_FUNCTION;

View File

@ -350,7 +350,7 @@ private:
mutable llvm::StringMap<mach_o::MachODylibFile*> _pathToDylibMap; mutable llvm::StringMap<mach_o::MachODylibFile*> _pathToDylibMap;
mutable std::set<mach_o::MachODylibFile*> _allDylibs; mutable std::set<mach_o::MachODylibFile*> _allDylibs;
mutable std::set<mach_o::MachODylibFile*> _upwardDylibs; mutable std::set<mach_o::MachODylibFile*> _upwardDylibs;
mutable std::vector<std::unique_ptr<class MachOFileNode>> _indirectDylibs; mutable std::vector<std::unique_ptr<File>> _indirectDylibs;
ExportMode _exportMode; ExportMode _exportMode;
llvm::StringSet<> _exportedSymbols; llvm::StringSet<> _exportedSymbols;
DebugInfoMode _debugInfoMode; DebugInfoMode _debugInfoMode;

View File

@ -55,7 +55,7 @@ public:
/// file) and create a File object. /// file) and create a File object.
/// The resulting File object takes ownership of the MemoryBuffer. /// The resulting File object takes ownership of the MemoryBuffer.
virtual std::error_code virtual std::error_code
parseFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &, loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
std::vector<std::unique_ptr<File>> &result) const = 0; std::vector<std::unique_ptr<File>> &result) const = 0;
}; };
@ -93,7 +93,7 @@ public:
/// Walk the list of registered Readers and find one that can parse the /// Walk the list of registered Readers and find one that can parse the
/// supplied file and parse it. /// supplied file and parse it.
std::error_code parseFile(std::unique_ptr<MemoryBuffer> mb, std::error_code loadFile(std::unique_ptr<MemoryBuffer> mb,
std::vector<std::unique_ptr<File>> &result) const; std::vector<std::unique_ptr<File>> &result) const;
/// Walk the list of registered kind tables to convert a Reference Kind /// Walk the list of registered kind tables to convert a Reference Kind

View File

@ -12,14 +12,11 @@ add_public_tablegen_target(DriverOptionsTableGen)
add_lld_library(lldDriver add_lld_library(lldDriver
CoreDriver.cpp CoreDriver.cpp
DarwinInputGraph.cpp
DarwinLdDriver.cpp DarwinLdDriver.cpp
Driver.cpp Driver.cpp
GnuLdDriver.cpp GnuLdDriver.cpp
GnuLdInputGraph.cpp
UniversalDriver.cpp UniversalDriver.cpp
WinLinkDriver.cpp WinLinkDriver.cpp
WinLinkInputGraph.cpp
WinLinkModuleDef.cpp WinLinkModuleDef.cpp
) )

View File

@ -152,7 +152,7 @@ bool CoreDriver::parse(int argc, const char *argv[], CoreLinkingContext &ctx,
case OPT_INPUT: { case OPT_INPUT: {
std::vector<std::unique_ptr<File>> files std::vector<std::unique_ptr<File>> files
= parseFile(ctx, inputArg->getValue(), false); = loadFile(ctx, inputArg->getValue(), false);
for (std::unique_ptr<File> &file : files) { for (std::unique_ptr<File> &file : files) {
inputGraph->addInputElement(std::unique_ptr<InputElement>( inputGraph->addInputElement(std::unique_ptr<InputElement>(
new WrapperNode(std::move(file)))); new WrapperNode(std::move(file))));

View File

@ -1,83 +0,0 @@
//===- 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

View File

@ -13,8 +13,11 @@
/// ///
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "lld/Core/File.h"
#include "lld/Core/ArchiveLibraryFile.h"
#include "lld/Core/SharedLibraryFile.h"
#include "lld/Driver/Driver.h" #include "lld/Driver/Driver.h"
#include "lld/Driver/DarwinInputGraph.h" #include "lld/Driver/WrapperInputGraph.h"
#include "lld/ReaderWriter/MachOLinkingContext.h" #include "lld/ReaderWriter/MachOLinkingContext.h"
#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
@ -22,6 +25,7 @@
#include "llvm/Option/Arg.h" #include "llvm/Option/Arg.h"
#include "llvm/Option/Option.h" #include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h" #include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h" #include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h" #include "llvm/Support/Format.h"
#include "llvm/Support/Host.h" #include "llvm/Support/Host.h"
@ -68,6 +72,33 @@ public:
DarwinLdOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){} DarwinLdOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){}
}; };
std::vector<std::unique_ptr<File>>
loadFile(MachOLinkingContext &ctx, StringRef path,
raw_ostream &diag, bool wholeArchive, bool upwardDylib) {
if (ctx.logInputFiles())
diag << path << "\n";
ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr =
DarwinLdDriver::getMemoryBuffer(ctx, path);
if (std::error_code ec = mbOrErr.getError())
return makeErrorFile(path, ec);
std::vector<std::unique_ptr<File>> files;
if (std::error_code ec = ctx.registry().loadFile(std::move(mbOrErr.get()), 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 } // anonymous namespace
// Test may be running on Windows. Canonicalize the path // Test may be running on Windows. Canonicalize the path
@ -85,13 +116,12 @@ static std::string canonicalizePath(StringRef path) {
static void addFile(StringRef path, std::unique_ptr<InputGraph> &inputGraph, static void addFile(StringRef path, std::unique_ptr<InputGraph> &inputGraph,
MachOLinkingContext &ctx, bool loadWholeArchive, MachOLinkingContext &ctx, bool loadWholeArchive,
bool upwardDylib) { bool upwardDylib, raw_ostream &diag) {
auto node = llvm::make_unique<MachOFileNode>(path, ctx); std::vector<std::unique_ptr<File>> files =
if (loadWholeArchive) loadFile(ctx, path, diag, loadWholeArchive, upwardDylib);
node->setLoadWholeArchive(); for (std::unique_ptr<File> &file : files)
if (upwardDylib) inputGraph->addInputElement(
node->setUpwardDylib(); llvm::make_unique<WrapperNode>(std::move(file)));
inputGraph->addInputElement(std::move(node));
} }
// Export lists are one symbol per line. Blank lines are ignored. // Export lists are one symbol per line. Blank lines are ignored.
@ -184,7 +214,7 @@ static std::error_code parseOrderFile(StringRef orderFilePath,
// In this variant, the path is to a text file which contains a partial path // 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. // per line. The <dir> prefix is prepended to each partial path.
// //
static std::error_code parseFileList(StringRef fileListPath, static std::error_code loadFileList(StringRef fileListPath,
std::unique_ptr<InputGraph> &inputGraph, std::unique_ptr<InputGraph> &inputGraph,
MachOLinkingContext &ctx, bool forceLoad, MachOLinkingContext &ctx, bool forceLoad,
raw_ostream &diagnostics) { raw_ostream &diagnostics) {
@ -222,7 +252,7 @@ static std::error_code parseFileList(StringRef fileListPath,
if (ctx.testingFileUsage()) { if (ctx.testingFileUsage()) {
diagnostics << "Found filelist entry " << canonicalizePath(path) << '\n'; diagnostics << "Found filelist entry " << canonicalizePath(path) << '\n';
} }
addFile(path, inputGraph, ctx, forceLoad, false); addFile(path, inputGraph, ctx, forceLoad, false, diagnostics);
buffer = lineAndRest.second; buffer = lineAndRest.second;
} }
return std::error_code(); return std::error_code();
@ -237,6 +267,25 @@ static bool parseNumberBase16(StringRef numStr, uint64_t &baseAddress) {
namespace lld { namespace lld {
ErrorOr<std::unique_ptr<MemoryBuffer>>
DarwinLdDriver::getMemoryBuffer(MachOLinkingContext &ctx, StringRef path) {
ctx.addInputFileDependency(path);
ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr =
MemoryBuffer::getFileOrSTDIN(path);
if (std::error_code ec = mbOrErr.getError())
return ec;
std::unique_ptr<MemoryBuffer> mb = std::move(mbOrErr.get());
// If buffer contains a fat file, find required arch in fat buffer
// and switch buffer to point to just that required slice.
uint32_t offset;
uint32_t size;
if (ctx.sliceFromFatFile(*mb, offset, size))
return MemoryBuffer::getFileSlice(path, size, offset);
return std::move(mb);
}
bool DarwinLdDriver::linkMachO(int argc, const char *argv[], bool DarwinLdDriver::linkMachO(int argc, const char *argv[],
raw_ostream &diagnostics) { raw_ostream &diagnostics) {
MachOLinkingContext ctx; MachOLinkingContext ctx;
@ -244,13 +293,6 @@ bool DarwinLdDriver::linkMachO(int argc, const char *argv[],
return false; return false;
if (ctx.doNothing()) if (ctx.doNothing())
return true; 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); return link(ctx, diagnostics);
} }
@ -310,15 +352,15 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
} }
} }
// If no -arch specified, scan input files to find first non-fat .o file. // 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)) { for (auto &inFile: parsedArgs->filtered(OPT_INPUT)) {
// This is expensive because it opens and maps the file. But that is // This is expensive because it opens and maps the file. But that is
// ok because no -arch is rare. // ok because no -arch is rare.
if (MachOLinkingContext::isThinObjectFile(inFile->getValue(), arch)) if (MachOLinkingContext::isThinObjectFile(inFile->getValue(), arch))
break; break;
} }
if (arch == MachOLinkingContext::arch_unknown) { if (arch == MachOLinkingContext::arch_unknown
&& !parsedArgs->getLastArg(OPT_test_file_usage)) {
// If no -arch and no options at all, print usage message. // If no -arch and no options at all, print usage message.
if (parsedArgs->size() == 0) if (parsedArgs->size() == 0)
table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false); table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false);
@ -521,6 +563,13 @@ 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()); std::unique_ptr<InputGraph> inputGraph(new InputGraph());
// Now construct the set of library search directories, following ld64's // Now construct the set of library search directories, following ld64's
@ -745,13 +794,13 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
default: default:
continue; continue;
case OPT_INPUT: case OPT_INPUT:
addFile(arg->getValue(), inputGraph, ctx, globalWholeArchive, false); addFile(arg->getValue(), inputGraph, ctx, globalWholeArchive, false, diagnostics);
break; break;
case OPT_upward_library: case OPT_upward_library:
addFile(arg->getValue(), inputGraph, ctx, false, true); addFile(arg->getValue(), inputGraph, ctx, false, true, diagnostics);
break; break;
case OPT_force_load: case OPT_force_load:
addFile(arg->getValue(), inputGraph, ctx, true, false); addFile(arg->getValue(), inputGraph, ctx, true, false, diagnostics);
break; break;
case OPT_l: case OPT_l:
case OPT_upward_l: case OPT_upward_l:
@ -765,7 +814,7 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
diagnostics << "Found " << (upward ? "upward " : " ") << "library " diagnostics << "Found " << (upward ? "upward " : " ") << "library "
<< canonicalizePath(resolvedPath.get()) << '\n'; << canonicalizePath(resolvedPath.get()) << '\n';
} }
addFile(resolvedPath.get(), inputGraph, ctx, globalWholeArchive, upward); addFile(resolvedPath.get(), inputGraph, ctx, globalWholeArchive, upward, diagnostics);
break; break;
case OPT_framework: case OPT_framework:
case OPT_upward_framework: case OPT_upward_framework:
@ -779,10 +828,10 @@ bool DarwinLdDriver::parse(int argc, const char *argv[],
diagnostics << "Found " << (upward ? "upward " : " ") << "framework " diagnostics << "Found " << (upward ? "upward " : " ") << "framework "
<< canonicalizePath(resolvedPath.get()) << '\n'; << canonicalizePath(resolvedPath.get()) << '\n';
} }
addFile(resolvedPath.get(), inputGraph, ctx, globalWholeArchive, upward); addFile(resolvedPath.get(), inputGraph, ctx, globalWholeArchive, upward, diagnostics);
break; break;
case OPT_filelist: case OPT_filelist:
if (std::error_code ec = parseFileList(arg->getValue(), inputGraph, if (std::error_code ec = loadFileList(arg->getValue(), inputGraph,
ctx, globalWholeArchive, ctx, globalWholeArchive,
diagnostics)) { diagnostics)) {
diagnostics << "error: " << ec.message() diagnostics << "error: " << ec.message()

View File

@ -49,13 +49,13 @@ FileVector parseMemberFiles(FileVector &files) {
return members; return members;
} }
FileVector parseFile(LinkingContext &ctx, StringRef path, bool wholeArchive) { FileVector loadFile(LinkingContext &ctx, StringRef path, bool wholeArchive) {
ErrorOr<std::unique_ptr<MemoryBuffer>> mb ErrorOr<std::unique_ptr<MemoryBuffer>> mb
= MemoryBuffer::getFileOrSTDIN(path); = MemoryBuffer::getFileOrSTDIN(path);
if (std::error_code ec = mb.getError()) if (std::error_code ec = mb.getError())
return makeErrorFile(path, ec); return makeErrorFile(path, ec);
std::vector<std::unique_ptr<File>> files; std::vector<std::unique_ptr<File>> files;
if (std::error_code ec = ctx.registry().parseFile(std::move(mb.get()), files)) if (std::error_code ec = ctx.registry().loadFile(std::move(mb.get()), files))
return makeErrorFile(path, ec); return makeErrorFile(path, ec);
if (wholeArchive) if (wholeArchive)
return parseMemberFiles(files); return parseMemberFiles(files);

View File

@ -14,7 +14,8 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "lld/Driver/Driver.h" #include "lld/Driver/Driver.h"
#include "lld/Driver/GnuLdInputGraph.h" #include "lld/Driver/WrapperInputGraph.h"
#include "lld/ReaderWriter/ELFLinkingContext.h"
#include "lld/ReaderWriter/LinkerScript.h" #include "lld/ReaderWriter/LinkerScript.h"
#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h" #include "llvm/ADT/Optional.h"
@ -172,16 +173,6 @@ bool GnuLdDriver::linkELF(int argc, const char *argv[],
return false; return false;
if (!options) if (!options)
return true; 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); return link(*options, diagnostics);
} }
@ -218,6 +209,23 @@ static bool isLinkerScript(StringRef path, raw_ostream &diag) {
return magic == llvm::sys::fs::file_magic::unknown; 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) { static bool isPathUnderSysroot(StringRef sysroot, StringRef path) {
if (sysroot.empty()) if (sysroot.empty())
return false; return false;
@ -234,8 +242,6 @@ evaluateLinkerScript(ELFLinkingContext &ctx, InputGraph *inputGraph,
MemoryBuffer::getFileOrSTDIN(path); MemoryBuffer::getFileOrSTDIN(path);
if (std::error_code ec = mb.getError()) if (std::error_code ec = mb.getError())
return ec; return ec;
if (ctx.logInputFiles())
diag << path << "\n";
auto lexer = llvm::make_unique<script::Lexer>(std::move(mb.get())); auto lexer = llvm::make_unique<script::Lexer>(std::move(mb.get()));
auto parser = llvm::make_unique<script::Parser>(*lexer); auto parser = llvm::make_unique<script::Parser>(*lexer);
script::LinkerScript *script = parser->parse(); script::LinkerScript *script = parser->parse();
@ -253,13 +259,26 @@ evaluateLinkerScript(ELFLinkingContext &ctx, InputGraph *inputGraph,
int numfiles = 0; int numfiles = 0;
for (const script::Path &path : group->getPaths()) { for (const script::Path &path : group->getPaths()) {
// TODO : Propagate Set WholeArchive/dashlPrefix // TODO : Propagate Set WholeArchive/dashlPrefix
ELFFileNode::Attributes attr; ELFLinkingContext::Attributes attr;
attr.setSysRooted(sysroot); attr.setSysRooted(sysroot);
attr.setAsNeeded(path._asNeeded); attr.setAsNeeded(path._asNeeded);
attr.setDashlPrefix(path._isDashlPrefix); 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)); inputGraph->addInputElement(llvm::make_unique<GroupEnd>(numfiles));
} }
@ -341,7 +360,7 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
std::stack<int> groupStack; std::stack<int> groupStack;
int numfiles = 0; int numfiles = 0;
ELFFileNode::Attributes attributes; ELFLinkingContext::Attributes attributes;
bool _outputOptionSet = false; bool _outputOptionSet = false;
@ -379,7 +398,6 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
ctx->setPrintRemainingUndefines(false); ctx->setPrintRemainingUndefines(false);
ctx->setAllowRemainingUndefines(true); ctx->setAllowRemainingUndefines(true);
break; break;
case OPT_static: case OPT_static:
ctx->setOutputELFType(llvm::ELF::ET_EXEC); ctx->setOutputELFType(llvm::ELF::ET_EXEC);
ctx->setIsStaticExecutable(true); ctx->setIsStaticExecutable(true);
@ -415,6 +433,37 @@ 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 // Process all the arguments and create Input Elements
for (auto inputArg : *parsedArgs) { for (auto inputArg : *parsedArgs) {
switch (inputArg->getOption().getID()) { switch (inputArg->getOption().getID()) {
@ -438,26 +487,6 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
ctx->setExportDynamic(true); ctx->setExportDynamic(true);
break; 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: case OPT_allow_multiple_definition:
ctx->setAllowDuplicates(true); ctx->setAllowDuplicates(true);
break; break;
@ -560,25 +589,19 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
bool dashL = (inputArg->getOption().getID() == OPT_l); bool dashL = (inputArg->getOption().getID() == OPT_l);
attributes.setDashlPrefix(dashL); attributes.setDashlPrefix(dashL);
StringRef path = inputArg->getValue(); StringRef path = inputArg->getValue();
std::string realpath = path;
// If the path was referred to by using a -l argument, let's search ErrorOr<StringRef> pathOrErr = findFile(*ctx, path, dashL);
// for the file in the search path. if (std::error_code ec = pathOrErr.getError()) {
if (dashL) { diagnostics << ec.message() << "\n";
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; return false;
} }
std::string realpath = pathOrErr.get();
bool isScript = bool isScript =
(!path.endswith(".objtxt") && isLinkerScript(realpath, diagnostics)); (!path.endswith(".objtxt") && isLinkerScript(realpath, diagnostics));
if (isScript) { if (isScript) {
if (ctx->logInputFiles())
diagnostics << path << "\n";
std::error_code ec = evaluateLinkerScript( std::error_code ec = evaluateLinkerScript(
*ctx, inputGraph.get(), realpath, diagnostics); *ctx, inputGraph.get(), realpath, diagnostics);
if (ec) { if (ec) {
@ -588,9 +611,15 @@ bool GnuLdDriver::parse(int argc, const char *argv[],
} }
break; break;
} }
++numfiles; 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( inputGraph->addInputElement(
llvm::make_unique<ELFFileNode>(*ctx, path, attributes)); std::unique_ptr<InputElement>(new WrapperNode(std::move(file))));
}
numfiles += files.size();
break; break;
} }

View File

@ -1,65 +0,0 @@
//===- 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);
}

View File

@ -14,8 +14,8 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "lld/Driver/Driver.h" #include "lld/Driver/Driver.h"
#include "lld/Driver/WinLinkInputGraph.h"
#include "lld/Driver/WinLinkModuleDef.h" #include "lld/Driver/WinLinkModuleDef.h"
#include "lld/Driver/WrapperInputGraph.h"
#include "lld/ReaderWriter/PECOFFLinkingContext.h" #include "lld/ReaderWriter/PECOFFLinkingContext.h"
#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h" #include "llvm/ADT/Optional.h"
@ -800,13 +800,11 @@ parseArgs(int argc, const char **argv, PECOFFLinkingContext &ctx,
// Returns true if the given file node has already been added to the input // Returns true if the given file node has already been added to the input
// graph. // graph.
static bool hasLibrary(const PECOFFLinkingContext &ctx, FileNode *fileNode) { static bool hasLibrary(const PECOFFLinkingContext &ctx, File *file) {
ErrorOr<StringRef> path = fileNode->getPath(ctx); StringRef path = file->path();
if (!path)
return false;
for (std::unique_ptr<InputElement> &p : ctx.getInputGraph().inputElements()) for (std::unique_ptr<InputElement> &p : ctx.getInputGraph().inputElements())
if (auto *f = dyn_cast<FileNode>(p.get())) if (auto *f = dyn_cast<FileNode>(p.get()))
if (*path == *f->getPath(ctx)) if (*f->getPath(ctx) == path)
return true; return true;
return false; return false;
} }
@ -838,6 +836,16 @@ static bool maybeRunLibCommand(int argc, const char **argv, raw_ostream &diag) {
return true; 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";
files.push_back(std::move(file));
}
}
// //
// Main driver // Main driver
// //
@ -847,6 +855,12 @@ bool WinLinkDriver::linkPECOFF(int argc, const char **argv, raw_ostream &diag) {
return true; return true;
PECOFFLinkingContext ctx; 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); std::vector<const char *> newargv = processLinkEnv(ctx, argc, argv);
processLibEnv(ctx); processLibEnv(ctx);
if (!parse(newargv.size() - 1, &newargv[0], ctx, diag)) if (!parse(newargv.size() - 1, &newargv[0], ctx, diag))
@ -857,13 +871,6 @@ bool WinLinkDriver::linkPECOFF(int argc, const char **argv, raw_ostream &diag) {
if (!createSideBySideManifestFile(ctx, diag)) if (!createSideBySideManifestFile(ctx, diag))
return false; 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); return link(ctx, diag);
} }
@ -884,8 +891,8 @@ bool WinLinkDriver::parse(int argc, const char *argv[],
return false; return false;
// The list of input files. // The list of input files.
std::vector<std::unique_ptr<FileNode> > files; std::vector<std::unique_ptr<File>> files;
std::vector<std::unique_ptr<FileNode> > libraries; std::vector<std::unique_ptr<File>> libraries;
// Handle /help // Handle /help
if (parsedArgs->getLastArg(OPT_help)) { if (parsedArgs->getLastArg(OPT_help)) {
@ -1363,11 +1370,9 @@ bool WinLinkDriver::parse(int argc, const char *argv[],
for (StringRef path : inputFiles) { for (StringRef path : inputFiles) {
path = ctx.allocate(path); path = ctx.allocate(path);
if (isLibraryFile(path)) { if (isLibraryFile(path)) {
libraries.push_back(std::unique_ptr<FileNode>( addFiles(ctx, getLibraryPath(ctx, path), diag, libraries);
new PECOFFFileNode(ctx, getLibraryPath(ctx, path))));
} else { } else {
files.push_back(std::unique_ptr<FileNode>( addFiles(ctx, getObjectPath(ctx, path), diag, files);
new PECOFFFileNode(ctx, getObjectPath(ctx, path))));
} }
} }
@ -1389,8 +1394,7 @@ bool WinLinkDriver::parse(int argc, const char *argv[],
if (!ctx.getNoDefaultLibAll()) if (!ctx.getNoDefaultLibAll())
for (const StringRef path : defaultLibs) for (const StringRef path : defaultLibs)
if (!ctx.hasNoDefaultLib(path)) if (!ctx.hasNoDefaultLib(path))
libraries.push_back(std::unique_ptr<FileNode>( addFiles(ctx, getLibraryPath(ctx, path.lower()), diag, libraries);
new PECOFFFileNode(ctx, getLibraryPath(ctx, path.lower()))));
if (files.empty() && !isReadingDirectiveSection) { if (files.empty() && !isReadingDirectiveSection) {
diag << "No input files\n"; diag << "No input files\n";
@ -1401,18 +1405,19 @@ bool WinLinkDriver::parse(int argc, const char *argv[],
// constructed by replacing an extension of the first input file // constructed by replacing an extension of the first input file
// with ".exe". // with ".exe".
if (ctx.outputPath().empty()) { if (ctx.outputPath().empty()) {
StringRef path = *cast<FileNode>(&*files[0])->getPath(ctx); StringRef path = files[0]->path();
ctx.setOutputPath(replaceExtension(ctx, path, ".exe")); ctx.setOutputPath(replaceExtension(ctx, path, ".exe"));
} }
// Add the input files to the input graph. // Add the input files to the input graph.
if (!ctx.hasInputGraph()) if (!ctx.hasInputGraph())
ctx.setInputGraph(std::unique_ptr<InputGraph>(new InputGraph())); ctx.setInputGraph(std::unique_ptr<InputGraph>(new InputGraph()));
for (std::unique_ptr<FileNode> &file : files) { for (std::unique_ptr<File> &file : files) {
if (isReadingDirectiveSection) if (isReadingDirectiveSection)
if (file->parse(ctx, diag)) if (file->parse())
return false; return false;
ctx.getInputGraph().addInputElement(std::move(file)); ctx.getInputGraph().addInputElement(
std::unique_ptr<InputElement>(new WrapperNode(std::move(file))));
} }
// Add the library group to the input graph. // Add the library group to the input graph.
@ -1427,12 +1432,13 @@ bool WinLinkDriver::parse(int argc, const char *argv[],
} }
// Add the library files to the library group. // Add the library files to the library group.
for (std::unique_ptr<FileNode> &lib : libraries) { for (std::unique_ptr<File> &file : libraries) {
if (!hasLibrary(ctx, lib.get())) { if (!hasLibrary(ctx, file.get())) {
if (isReadingDirectiveSection) if (isReadingDirectiveSection)
if (lib->parse(ctx, diag)) if (file->parse())
return false; return false;
ctx.addLibraryFile(std::move(lib)); ctx.addLibraryFile(
std::unique_ptr<FileNode>(new WrapperNode(std::move(file))));
} }
} }

View File

@ -1,39 +0,0 @@
//===- 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

View File

@ -40,13 +40,15 @@ void RoundTripNativePass::perform(std::unique_ptr<MutableFile> &mergedFile) {
if (!mb) if (!mb)
return; return;
std::error_code ec = _context.registry().parseFile( std::error_code ec = _context.registry().loadFile(
std::move(mb.get()), _nativeFile); std::move(mb.get()), _nativeFile);
if (ec) { if (ec) {
// Note: we need a way for Passes to report errors. // Note: we need a way for Passes to report errors.
llvm_unreachable("native reader not registered or read error"); llvm_unreachable("native reader not registered or read error");
} }
File *objFile = _nativeFile[0].get(); File *objFile = _nativeFile[0].get();
if (objFile->parse())
llvm_unreachable("native reader parse error");
mergedFile.reset(new SimpleFileWrapper(_context, *objFile)); mergedFile.reset(new SimpleFileWrapper(_context, *objFile));
llvm::sys::fs::remove(tmpNativeFile.str()); llvm::sys::fs::remove(tmpNativeFile.str());

View File

@ -40,13 +40,15 @@ void RoundTripYAMLPass::perform(std::unique_ptr<MutableFile> &mergedFile) {
if (!mb) if (!mb)
return; return;
std::error_code ec = _context.registry().parseFile( std::error_code ec = _context.registry().loadFile(
std::move(mb.get()), _yamlFile); std::move(mb.get()), _yamlFile);
if (ec) { if (ec) {
// Note: we need a way for Passes to report errors. // Note: we need a way for Passes to report errors.
llvm_unreachable("yaml reader not registered or read error"); llvm_unreachable("yaml reader not registered or read error");
} }
File *objFile = _yamlFile[0].get(); File *objFile = _yamlFile[0].get();
if (objFile->parse())
llvm_unreachable("native reader parse error");
mergedFile.reset(new SimpleFileWrapper(_context, *objFile)); mergedFile.reset(new SimpleFileWrapper(_context, *objFile));
llvm::sys::fs::remove(tmpYAMLFile.str()); llvm::sys::fs::remove(tmpYAMLFile.str());
} }

View File

@ -33,7 +33,7 @@ public:
} }
std::error_code std::error_code
parseFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &, loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
std::vector<std::unique_ptr<File>> &result) const override { std::vector<std::unique_ptr<File>> &result) const override {
std::size_t maxAlignment = std::size_t maxAlignment =
1ULL << llvm::countTrailingZeros(uintptr_t(mb->getBufferStart())); 1ULL << llvm::countTrailingZeros(uintptr_t(mb->getBufferStart()));
@ -72,7 +72,7 @@ public:
} }
std::error_code std::error_code
parseFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &, loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
std::vector<std::unique_ptr<File>> &result) const override { std::vector<std::unique_ptr<File>> &result) const override {
std::size_t maxAlignment = std::size_t maxAlignment =
1ULL << llvm::countTrailingZeros(uintptr_t(mb->getBufferStart())); 1ULL << llvm::countTrailingZeros(uintptr_t(mb->getBufferStart()));

View File

@ -49,12 +49,12 @@ public:
_flagMerger(flagMerger) {} _flagMerger(flagMerger) {}
std::error_code std::error_code
parseFile(std::unique_ptr<MemoryBuffer> mb, const Registry &registry, loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &registry,
std::vector<std::unique_ptr<File>> &result) const override { std::vector<std::unique_ptr<File>> &result) const override {
auto &hdr = *elfHeader(*mb); auto &hdr = *elfHeader(*mb);
if (std::error_code ec = _flagMerger.merge(hdr.getFileClass(), hdr.e_flags)) if (std::error_code ec = _flagMerger.merge(hdr.getFileClass(), hdr.e_flags))
return ec; return ec;
return BaseReaderType::parseFile(std::move(mb), registry, result); return BaseReaderType::loadFile(std::move(mb), registry, result);
} }
private: private:
@ -72,12 +72,12 @@ public:
_flagMerger(flagMerger) {} _flagMerger(flagMerger) {}
std::error_code std::error_code
parseFile(std::unique_ptr<MemoryBuffer> mb, const Registry &registry, loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &registry,
std::vector<std::unique_ptr<File>> &result) const override { std::vector<std::unique_ptr<File>> &result) const override {
auto &hdr = *elfHeader(*mb); auto &hdr = *elfHeader(*mb);
if (std::error_code ec = _flagMerger.merge(hdr.getFileClass(), hdr.e_flags)) if (std::error_code ec = _flagMerger.merge(hdr.getFileClass(), hdr.e_flags))
return ec; return ec;
return BaseReaderType::parseFile(std::move(mb), registry, result); return BaseReaderType::loadFile(std::move(mb), registry, result);
} }
private: private:

View File

@ -67,7 +67,9 @@ public:
/// \brief parse each member /// \brief parse each member
std::error_code std::error_code
parseAllMembers(std::vector<std::unique_ptr<File>> &result) const override { parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
if (std::error_code ec = parse())
return ec;
for (auto mf = _archive->child_begin(), me = _archive->child_end(); for (auto mf = _archive->child_begin(), me = _archive->child_end();
mf != me; ++mf) { mf != me; ++mf) {
std::unique_ptr<File> file; std::unique_ptr<File> file;
@ -152,9 +154,12 @@ private:
mb.getBuffer(), memberPath, false)); mb.getBuffer(), memberPath, false));
std::vector<std::unique_ptr<File>> files; std::vector<std::unique_ptr<File>> files;
_registry.parseFile(std::move(memberMB), files); if (std::error_code ec = _registry.loadFile(std::move(memberMB), files))
return ec;
assert(files.size() == 1); assert(files.size() == 1);
result = std::move(files[0]); 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, // 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. // so that the bufffer is deallocated when all the members are destructed.
@ -232,7 +237,7 @@ public:
} }
std::error_code std::error_code
parseFile(std::unique_ptr<MemoryBuffer> mb, const Registry &reg, loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &reg,
std::vector<std::unique_ptr<File>> &result) const override { std::vector<std::unique_ptr<File>> &result) const override {
StringRef path = mb->getBufferIdentifier(); StringRef path = mb->getBufferIdentifier();
std::unique_ptr<FileArchive> file( std::unique_ptr<FileArchive> file(

View File

@ -91,7 +91,7 @@ public:
} }
std::error_code std::error_code
parseAllMembers(std::vector<std::unique_ptr<File>> &result) const override { parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
return std::error_code(); return std::error_code();
} }

View File

@ -12,8 +12,9 @@
#include "File.h" #include "File.h"
#include "MachONormalizedFile.h" #include "MachONormalizedFile.h"
#include "MachOPasses.h" #include "MachOPasses.h"
#include "lld/Core/ArchiveLibraryFile.h"
#include "lld/Core/PassManager.h" #include "lld/Core/PassManager.h"
#include "lld/Driver/DarwinInputGraph.h" #include "lld/Driver/Driver.h"
#include "lld/Passes/LayoutPass.h" #include "lld/Passes/LayoutPass.h"
#include "lld/Passes/RoundTripYAMLPass.h" #include "lld/Passes/RoundTripYAMLPass.h"
#include "lld/ReaderWriter/Reader.h" #include "lld/ReaderWriter/Reader.h"
@ -605,20 +606,19 @@ Writer &MachOLinkingContext::writer() const {
} }
MachODylibFile* MachOLinkingContext::loadIndirectDylib(StringRef path) { MachODylibFile* MachOLinkingContext::loadIndirectDylib(StringRef path) {
std::unique_ptr<MachOFileNode> node(new MachOFileNode(path, *this)); ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr =
std::error_code ec = node->parse(*this, llvm::errs()); DarwinLdDriver::getMemoryBuffer(*this, path);
if (ec) if (mbOrErr.getError())
return nullptr; return nullptr;
assert(node->files().size() == 1 && "expected one file in dylib"); std::vector<std::unique_ptr<File>> files;
// lld::File object is owned by MachOFileNode object. This method returns if (registry().loadFile(std::move(mbOrErr.get()), files))
// an unowned pointer to the lld::File object. return nullptr;
MachODylibFile* result = reinterpret_cast<MachODylibFile*>( assert(files.size() == 1 && "expected one file in dylib");
node->files().front().get()); files[0]->parse();
MachODylibFile* result = reinterpret_cast<MachODylibFile*>(files[0].get());
// Node object now owned by _indirectDylibs vector. // Node object now owned by _indirectDylibs vector.
_indirectDylibs.push_back(std::move(node)); _indirectDylibs.push_back(std::move(files[0]));
return result; return result;
} }

View File

@ -527,7 +527,7 @@ public:
} }
std::error_code std::error_code
parseFile(std::unique_ptr<MemoryBuffer> mb, const Registry &registry, loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &registry,
std::vector<std::unique_ptr<File>> &result) const override { std::vector<std::unique_ptr<File>> &result) const override {
auto *file = new MachOFile(std::move(mb), &_ctx); auto *file = new MachOFile(std::move(mb), &_ctx);
result.push_back(std::unique_ptr<MachOFile>(file)); result.push_back(std::unique_ptr<MachOFile>(file));
@ -554,7 +554,7 @@ public:
} }
std::error_code std::error_code
parseFile(std::unique_ptr<MemoryBuffer> mb, const Registry &registry, loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &registry,
std::vector<std::unique_ptr<File>> &result) const override { std::vector<std::unique_ptr<File>> &result) const override {
auto *file = new MachODylibFile(std::move(mb), &_ctx); auto *file = new MachODylibFile(std::move(mb), &_ctx);
result.push_back(std::unique_ptr<MachODylibFile>(file)); result.push_back(std::unique_ptr<MachODylibFile>(file));
@ -580,4 +580,3 @@ void Registry::addSupportMachOObjects(MachOLinkingContext &ctx) {
} // namespace lld } // namespace lld

View File

@ -999,7 +999,7 @@ public:
} }
virtual std::error_code virtual std::error_code
parseFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &, loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
std::vector<std::unique_ptr<File>> &result) const override { std::vector<std::unique_ptr<File>> &result) const override {
auto *file = new lld::native::File(std::move(mb)); auto *file = new lld::native::File(std::move(mb));
result.push_back(std::unique_ptr<File>(file)); result.push_back(std::unique_ptr<File>(file));

View File

@ -88,7 +88,7 @@ public:
} }
std::error_code std::error_code
parseAllMembers(std::vector<std::unique_ptr<File>> &result) const override { parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
return std::error_code(); return std::error_code();
} }

View File

@ -1077,7 +1077,7 @@ public:
} }
std::error_code std::error_code
parseFile(std::unique_ptr<MemoryBuffer> mb, const Registry &, loadFile(std::unique_ptr<MemoryBuffer> mb, const Registry &,
std::vector<std::unique_ptr<File>> &result) const override { std::vector<std::unique_ptr<File>> &result) const override {
// Parse the memory buffer as PECOFF file. // Parse the memory buffer as PECOFF file.
auto *file = new FileCOFF(std::move(mb), _ctx); auto *file = new FileCOFF(std::move(mb), _ctx);

View File

@ -354,7 +354,7 @@ private:
class COFFImportLibraryReader : public Reader { class COFFImportLibraryReader : public Reader {
public: public:
COFFImportLibraryReader(MachineTypes machine) : _machine(machine) {} COFFImportLibraryReader(PECOFFLinkingContext &ctx) : _ctx(ctx) {}
bool canParse(file_magic magic, StringRef, bool canParse(file_magic magic, StringRef,
const MemoryBuffer &mb) const override { const MemoryBuffer &mb) const override {
@ -364,22 +364,21 @@ public:
} }
std::error_code std::error_code
parseFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &, loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
std::vector<std::unique_ptr<File> > &result) const override { std::vector<std::unique_ptr<File> > &result) const override {
auto *file = new FileImportLibrary(std::move(mb), _machine); auto *file = new FileImportLibrary(std::move(mb), _ctx.getMachineType());
result.push_back(std::unique_ptr<File>(file)); result.push_back(std::unique_ptr<File>(file));
return std::error_code(); return std::error_code();
} }
private: private:
MachineTypes _machine; PECOFFLinkingContext &_ctx;
}; };
} // end anonymous namespace } // end anonymous namespace
void Registry::addSupportCOFFImportLibraries(PECOFFLinkingContext &ctx) { void Registry::addSupportCOFFImportLibraries(PECOFFLinkingContext &ctx) {
MachineTypes machine = ctx.getMachineType(); add(llvm::make_unique<COFFImportLibraryReader>(ctx));
add(llvm::make_unique<COFFImportLibraryReader>(machine));
} }
} // end namespace lld } // end namespace lld

View File

@ -30,7 +30,7 @@ void Registry::add(std::unique_ptr<YamlIOTaggedDocumentHandler> handler) {
} }
std::error_code std::error_code
Registry::parseFile(std::unique_ptr<MemoryBuffer> mb, Registry::loadFile(std::unique_ptr<MemoryBuffer> mb,
std::vector<std::unique_ptr<File>> &result) const { std::vector<std::unique_ptr<File>> &result) const {
// Get file type. // Get file type.
StringRef content(mb->getBufferStart(), mb->getBufferSize()); StringRef content(mb->getBufferStart(), mb->getBufferSize());
@ -42,10 +42,7 @@ Registry::parseFile(std::unique_ptr<MemoryBuffer> mb,
for (const std::unique_ptr<Reader> &reader : _readers) { for (const std::unique_ptr<Reader> &reader : _readers) {
if (!reader->canParse(fileType, extension, *mb)) if (!reader->canParse(fileType, extension, *mb))
continue; continue;
if (std::error_code ec = reader->parseFile(std::move(mb), *this, result)) if (std::error_code ec = reader->loadFile(std::move(mb), *this, result))
return ec;
for (std::unique_ptr<File> &file : result)
if (std::error_code ec = file->parse())
return ec; return ec;
return std::error_code(); return std::error_code();
} }

View File

@ -648,7 +648,7 @@ template <> struct MappingTraits<const lld::File *> {
} }
virtual std::error_code virtual std::error_code
parseAllMembers(std::vector<std::unique_ptr<File>> &result) const override { parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
return std::error_code(); return std::error_code();
} }
@ -1325,7 +1325,7 @@ public:
} }
std::error_code std::error_code
parseFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &, loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &,
std::vector<std::unique_ptr<File>> &result) const override { std::vector<std::unique_ptr<File>> &result) const override {
// Create YAML Input Reader. // Create YAML Input Reader.
YamlContext yamlContext; YamlContext yamlContext;
@ -1343,7 +1343,7 @@ public:
std::shared_ptr<MemoryBuffer> smb(mb.release()); std::shared_ptr<MemoryBuffer> smb(mb.release());
for (const File *file : createdFiles) { for (const File *file : createdFiles) {
// Note: parseFile() should return vector of *const* File // Note: loadFile() should return vector of *const* File
File *f = const_cast<File *>(file); File *f = const_cast<File *>(file);
f->setLastError(std::error_code()); f->setLastError(std::error_code());
f->setSharedMemoryBuffer(smb); f->setSharedMemoryBuffer(smb);

View File

@ -1,39 +0,0 @@
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

View File

@ -698,10 +698,9 @@ TEST_F(WinLinkParserTest, Ignore) {
// compatibility with link.exe. // compatibility with link.exe.
EXPECT_TRUE(parse("link.exe", "/nologo", "/errorreport:prompt", EXPECT_TRUE(parse("link.exe", "/nologo", "/errorreport:prompt",
"/incremental", "/incremental:no", "/delay:unload", "/incremental", "/incremental:no", "/delay:unload",
"/disallowlib:foo", "/pdbaltpath:bar", "/verbose", "/disallowlib:foo", "/pdbaltpath:bar",
"/verbose:icf", "/wx", "/wx:no", "/tlbid:1", "/wx", "/wx:no", "/tlbid:1", "/tlbout:foo", "/idlout:foo",
"/tlbout:foo", "/idlout:foo", "/ignore:4000", "/ignore:4000", "/ignoreidl", "/implib:foo", "/safeseh",
"/ignoreidl", "/implib:foo", "/safeseh",
"/safeseh:no", "/functionpadmin", "/maxilksize:1024", "/safeseh:no", "/functionpadmin", "/maxilksize:1024",
"a.obj", nullptr)); "a.obj", nullptr));
EXPECT_EQ("", errorMessage()); EXPECT_EQ("", errorMessage());