Index: COFF/Driver.h =================================================================== --- COFF/Driver.h +++ COFF/Driver.h @@ -34,9 +34,6 @@ using llvm::Optional; class InputFile; -// Entry point of the COFF linker. -bool link(llvm::ArrayRef Args); - // Implemented in MarkLive.cpp. void markLive(const std::vector &Chunks); Index: COFF/Driver.cpp =================================================================== --- COFF/Driver.cpp +++ COFF/Driver.cpp @@ -14,6 +14,7 @@ #include "SymbolTable.h" #include "Symbols.h" #include "Writer.h" +#include "lld/Driver/Driver.h" #include "llvm/ADT/Optional.h" #include "llvm/LibDriver/LibDriver.h" #include "llvm/Option/Arg.h" Index: ELF/Driver.h =================================================================== --- ELF/Driver.h +++ ELF/Driver.h @@ -21,9 +21,6 @@ extern class LinkerDriver *Driver; -// Entry point of the ELF linker. Returns true on success. -bool link(ArrayRef Args, llvm::raw_ostream &Error = llvm::errs()); - class LinkerDriver { public: void main(ArrayRef Args); Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -16,6 +16,7 @@ #include "SymbolTable.h" #include "Target.h" #include "Writer.h" +#include "lld/Driver/Driver.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/raw_ostream.h" Index: include/lld/Driver/Driver.h =================================================================== --- include/lld/Driver/Driver.h +++ include/lld/Driver/Driver.h @@ -6,71 +6,27 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// -/// -/// \file -/// -/// Interface for Drivers which convert command line arguments into -/// LinkingContext objects, then perform the link. -/// -//===----------------------------------------------------------------------===// #ifndef LLD_DRIVER_DRIVER_H #define LLD_DRIVER_DRIVER_H -#include "lld/Core/LLVM.h" -#include "lld/Core/Node.h" -#include "llvm/ADT/Triple.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/Support/raw_ostream.h" -#include -#include -#include namespace lld { -class LinkingContext; -class MachOLinkingContext; - -/// Base class for all Drivers. -class Driver { -protected: - - /// Performs link using specified options - static bool link(LinkingContext &context, - raw_ostream &diag = llvm::errs()); - - /// Parses the LLVM options from the context. - static void parseLLVMOptions(const LinkingContext &context); - -private: - Driver() = delete; -}; - -/// Driver for darwin/ld64 'ld' command line options. -class DarwinLdDriver : public Driver { -public: - /// Parses command line arguments same as darwin's ld and performs link. - /// Returns true iff there was an error. - static bool linkMachO(llvm::ArrayRef args, - raw_ostream &diag = llvm::errs()); - - /// Uses darwin style ld command line options to update LinkingContext object. - /// Returns true iff there was an error. - static bool parse(llvm::ArrayRef args, - MachOLinkingContext &info, - raw_ostream &diag = llvm::errs()); - -private: - DarwinLdDriver() = delete; -}; - -/// Driver for Windows 'link.exe' command line options namespace coff { -bool link(llvm::ArrayRef args); +bool link(llvm::ArrayRef Args); } namespace elf { -bool link(llvm::ArrayRef args, raw_ostream &diag = llvm::errs()); +bool link(llvm::ArrayRef Args, + llvm::raw_ostream &Diag = llvm::errs()); } -} // end namespace lld +namespace mach_o { +bool link(llvm::ArrayRef Args, + llvm::raw_ostream &Diag = llvm::errs()); +} +} #endif Index: lib/Driver/CMakeLists.txt =================================================================== --- lib/Driver/CMakeLists.txt +++ lib/Driver/CMakeLists.txt @@ -4,7 +4,6 @@ add_lld_library(lldDriver DarwinLdDriver.cpp - Driver.cpp ADDITIONAL_HEADER_DIRS ${LLD_INCLUDE_DIR}/lld/Driver Index: lib/Driver/DarwinLdDriver.cpp =================================================================== --- lib/Driver/DarwinLdDriver.cpp +++ lib/Driver/DarwinLdDriver.cpp @@ -13,8 +13,11 @@ /// //===----------------------------------------------------------------------===// -#include "lld/Core/File.h" #include "lld/Core/ArchiveLibraryFile.h" +#include "lld/Core/File.h" +#include "lld/Core/Instrumentation.h" +#include "lld/Core/PassManager.h" +#include "lld/Core/Resolver.h" #include "lld/Core/SharedLibraryFile.h" #include "lld/Driver/Driver.h" #include "lld/ReaderWriter/MachOLinkingContext.h" @@ -284,20 +287,24 @@ return numStr.getAsInteger(16, baseAddress); } -namespace lld { - -bool DarwinLdDriver::linkMachO(llvm::ArrayRef args, - raw_ostream &diagnostics) { - MachOLinkingContext ctx; - if (!parse(args, ctx, diagnostics)) - return false; - if (ctx.doNothing()) - return true; - return link(ctx, diagnostics); +static void parseLLVMOptions(const LinkingContext &ctx) { + // Honor -mllvm + if (!ctx.llvmOptions().empty()) { + unsigned numArgs = ctx.llvmOptions().size(); + auto **args = new const char *[numArgs + 2]; + args[0] = "lld (LLVM option parsing)"; + for (unsigned i = 0; i != numArgs; ++i) + args[i + 1] = ctx.llvmOptions()[i]; + args[numArgs + 1] = nullptr; + llvm::cl::ParseCommandLineOptions(numArgs + 1, args); + } } -bool DarwinLdDriver::parse(llvm::ArrayRef args, - MachOLinkingContext &ctx, raw_ostream &diagnostics) { +namespace lld { +namespace mach_o { + +bool parse(llvm::ArrayRef args, MachOLinkingContext &ctx, + raw_ostream &diagnostics) { // Parse command line options using DarwinLdOptions.td DarwinLdOptTable table; unsigned missingIndex; @@ -1132,5 +1139,68 @@ return ctx.validate(diagnostics); } +/// This is where the link is actually performed. +bool link(llvm::ArrayRef args, raw_ostream &diagnostics) { + MachOLinkingContext ctx; + if (!parse(args, ctx, diagnostics)) + return false; + if (ctx.doNothing()) + return true; + if (ctx.getNodes().empty()) + return false; + + for (std::unique_ptr &ie : ctx.getNodes()) + if (FileNode *node = dyn_cast(ie.get())) + node->getFile()->parse(); + + std::vector> internalFiles; + ctx.createInternalFiles(internalFiles); + for (auto i = internalFiles.rbegin(), e = internalFiles.rend(); i != e; ++i) { + auto &members = ctx.getNodes(); + members.insert(members.begin(), llvm::make_unique(std::move(*i))); + } + + // Give target a chance to add files. + std::vector> implicitFiles; + ctx.createImplicitFiles(implicitFiles); + for (auto i = implicitFiles.rbegin(), e = implicitFiles.rend(); i != e; ++i) { + auto &members = ctx.getNodes(); + members.insert(members.begin(), llvm::make_unique(std::move(*i))); + } + + // Give target a chance to postprocess input files. + // Mach-O uses this chance to move all object files before library files. + ctx.finalizeInputFiles(); + + // Do core linking. + ScopedTask resolveTask(getDefaultDomain(), "Resolve"); + Resolver resolver(ctx); + if (!resolver.resolve()) + return false; + std::unique_ptr merged = resolver.resultFile(); + resolveTask.end(); + + // Run passes on linked atoms. + ScopedTask passTask(getDefaultDomain(), "Passes"); + PassManager pm; + ctx.addPasses(pm); + if (std::error_code ec = pm.runOnFile(*merged)) { + diagnostics << "Failed to write file '" << ctx.outputPath() + << "': " << ec.message() << "\n"; + return false; + } + + passTask.end(); + // Give linked atoms to Writer to generate output file. + ScopedTask writeTask(getDefaultDomain(), "Write"); + if (std::error_code ec = ctx.writeFile(*merged)) { + diagnostics << "Failed to write file '" << ctx.outputPath() + << "': " << ec.message() << "\n"; + return false; + } + + return true; +} +} // namespace mach_o } // namespace lld Index: lib/Driver/Driver.cpp =================================================================== --- lib/Driver/Driver.cpp +++ /dev/null @@ -1,104 +0,0 @@ -//===- lib/Driver/Driver.cpp - Linker Driver Emulator -----------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lld/Core/ArchiveLibraryFile.h" -#include "lld/Core/File.h" -#include "lld/Core/Instrumentation.h" -#include "lld/Core/LLVM.h" -#include "lld/Core/PassManager.h" -#include "lld/Core/Reader.h" -#include "lld/Core/Resolver.h" -#include "lld/Core/Writer.h" -#include "lld/Driver/Driver.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Option/Arg.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/Process.h" -#include "llvm/Support/raw_ostream.h" -#include - -namespace lld { - -void Driver::parseLLVMOptions(const LinkingContext &ctx) { - // Honor -mllvm - if (!ctx.llvmOptions().empty()) { - unsigned numArgs = ctx.llvmOptions().size(); - auto **args = new const char *[numArgs + 2]; - args[0] = "lld (LLVM option parsing)"; - for (unsigned i = 0; i != numArgs; ++i) - args[i + 1] = ctx.llvmOptions()[i]; - args[numArgs + 1] = nullptr; - llvm::cl::ParseCommandLineOptions(numArgs + 1, args); - } -} - -/// This is where the link is actually performed. -bool Driver::link(LinkingContext &ctx, raw_ostream &diagnostics) { - if (ctx.getNodes().empty()) - return false; - - for (std::unique_ptr &ie : ctx.getNodes()) - if (FileNode *node = dyn_cast(ie.get())) - node->getFile()->parse(); - - std::vector> internalFiles; - ctx.createInternalFiles(internalFiles); - for (auto i = internalFiles.rbegin(), e = internalFiles.rend(); i != e; ++i) { - auto &members = ctx.getNodes(); - members.insert(members.begin(), llvm::make_unique(std::move(*i))); - } - - // Give target a chance to add files. - std::vector> implicitFiles; - ctx.createImplicitFiles(implicitFiles); - for (auto i = implicitFiles.rbegin(), e = implicitFiles.rend(); i != e; ++i) { - auto &members = ctx.getNodes(); - members.insert(members.begin(), llvm::make_unique(std::move(*i))); - } - - // Give target a chance to postprocess input files. - // Mach-O uses this chance to move all object files before library files. - ctx.finalizeInputFiles(); - - // Do core linking. - ScopedTask resolveTask(getDefaultDomain(), "Resolve"); - Resolver resolver(ctx); - if (!resolver.resolve()) - return false; - std::unique_ptr merged = resolver.resultFile(); - resolveTask.end(); - - // Run passes on linked atoms. - ScopedTask passTask(getDefaultDomain(), "Passes"); - PassManager pm; - ctx.addPasses(pm); - if (std::error_code ec = pm.runOnFile(*merged)) { - diagnostics << "Failed to write file '" << ctx.outputPath() - << "': " << ec.message() << "\n"; - return false; - } - - passTask.end(); - - // Give linked atoms to Writer to generate output file. - ScopedTask writeTask(getDefaultDomain(), "Write"); - if (std::error_code ec = ctx.writeFile(*merged)) { - diagnostics << "Failed to write file '" << ctx.outputPath() - << "': " << ec.message() << "\n"; - return false; - } - - return true; -} - -} // namespace lld Index: tools/lld/lld.cpp =================================================================== --- tools/lld/lld.cpp +++ tools/lld/lld.cpp @@ -109,7 +109,7 @@ case WinLink: return !coff::link(Args); case Darwin: - return !DarwinLdDriver::linkMachO(Args); + return !mach_o::link(Args); default: die("-flavor option is missing. Available flavors are " "gnu, darwin or link."); Index: unittests/DriverTests/DarwinLdDriverTest.cpp =================================================================== --- unittests/DriverTests/DarwinLdDriverTest.cpp +++ unittests/DriverTests/DarwinLdDriverTest.cpp @@ -21,6 +21,13 @@ using namespace llvm; using namespace lld; +namespace lld { +namespace mach_o { +bool parse(llvm::ArrayRef args, MachOLinkingContext &ctx, + raw_ostream &diagnostics); +} +} + namespace { class DarwinLdParserTest : public testing::Test { protected: @@ -37,7 +44,7 @@ args.insert(args.begin(), "ld"); std::string errorMessage; raw_string_ostream os(errorMessage); - return DarwinLdDriver::parse(args, _ctx, os); + return mach_o::parse(args, _ctx, os); } MachOLinkingContext _ctx;