summaryrefslogtreecommitdiffstats
path: root/lld/lib/Driver
diff options
context:
space:
mode:
Diffstat (limited to 'lld/lib/Driver')
-rw-r--r--lld/lib/Driver/CMakeLists.txt8
-rw-r--r--lld/lib/Driver/CoreDriver.cpp158
-rw-r--r--lld/lib/Driver/CoreOptions.td25
-rw-r--r--lld/lib/Driver/DarwinLdDriver.cpp197
-rw-r--r--lld/lib/Driver/DarwinOptions.td30
-rw-r--r--lld/lib/Driver/Driver.cpp78
-rw-r--r--lld/lib/Driver/Drivers.cpp303
-rw-r--r--lld/lib/Driver/GnuLdDriver.cpp241
-rw-r--r--lld/lib/Driver/LDOptions.td39
-rw-r--r--lld/lib/Driver/LinkerInvocation.cpp98
-rw-r--r--lld/lib/Driver/UniversalDriver.cpp109
11 files changed, 853 insertions, 433 deletions
diff --git a/lld/lib/Driver/CMakeLists.txt b/lld/lib/Driver/CMakeLists.txt
index 13e6298b9a2..30aa26aa9f1 100644
--- a/lld/lib/Driver/CMakeLists.txt
+++ b/lld/lib/Driver/CMakeLists.txt
@@ -2,12 +2,16 @@ set(LLVM_TARGET_DEFINITIONS LDOptions.td)
tablegen(LLVM LDOptions.inc -gen-opt-parser-defs)
set(LLVM_TARGET_DEFINITIONS CoreOptions.td)
tablegen(LLVM CoreOptions.inc -gen-opt-parser-defs)
+set(LLVM_TARGET_DEFINITIONS DarwinOptions.td)
+tablegen(LLVM DarwinOptions.inc -gen-opt-parser-defs)
add_public_tablegen_target(DriverOptionsTableGen)
add_lld_library(lldDriver
+ CoreDriver.cpp
+ DarwinLdDriver.cpp
Driver.cpp
- Drivers.cpp
- LinkerInvocation.cpp
+ GnuLdDriver.cpp
+ UniversalDriver.cpp
)
add_dependencies(lldDriver DriverOptionsTableGen)
diff --git a/lld/lib/Driver/CoreDriver.cpp b/lld/lib/Driver/CoreDriver.cpp
new file mode 100644
index 00000000000..a4fb2166a4b
--- /dev/null
+++ b/lld/lib/Driver/CoreDriver.cpp
@@ -0,0 +1,158 @@
+//===- lib/Driver/CoreDriver.cpp ------------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lld/Driver/Driver.h"
+#include "lld/ReaderWriter/CoreTargetInfo.h"
+#include "lld/ReaderWriter/Reader.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Signals.h"
+
+using namespace lld;
+
+namespace {
+
+// Create enum with OPT_xxx values for each option in DarwinOptions.td
+enum CoreOpt {
+ OPT_INVALID = 0,
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, HELP, META) \
+ OPT_##ID,
+#include "CoreOptions.inc"
+ LastOption
+#undef OPTION
+};
+
+// Create prefix string literals used in CoreOptions.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "CoreOptions.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in CoreOptions.td
+static const llvm::opt::OptTable::Info infoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR) \
+ { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS },
+#include "CoreOptions.inc"
+#undef OPTION
+};
+
+// Create OptTable class for parsing actual command line arguments
+class CoreOptTable : public llvm::opt::OptTable {
+public:
+ CoreOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){}
+};
+
+
+
+} // namespace anonymous
+
+
+namespace lld {
+
+bool CoreDriver::link(int argc, const char *argv[], raw_ostream &diagnostics) {
+ CoreTargetInfo info;
+ if (parse(argc, argv, info))
+ return true;
+
+ return Driver::link(info);
+}
+
+
+bool CoreDriver::parse(int argc, const char *argv[],
+ CoreTargetInfo &info, raw_ostream &diagnostics) {
+ // Parse command line options using CoreOptions.td
+ std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
+ CoreOptTable table;
+ unsigned missingIndex;
+ unsigned missingCount;
+ parsedArgs.reset(table.ParseArgs(&argv[1], &argv[argc],
+ missingIndex, missingCount));
+ if (missingCount) {
+ diagnostics << "error: missing arg value for '"
+ << parsedArgs->getArgString(missingIndex)
+ << "' expected " << missingCount << " argument(s).\n";
+ return true;
+ }
+
+ for (auto it = parsedArgs->filtered_begin(OPT_UNKNOWN),
+ ie = parsedArgs->filtered_end(); it != ie; ++it) {
+ diagnostics << "warning: ignoring unknown argument: "
+ << (*it)->getAsString(*parsedArgs) << "\n";
+ }
+
+
+ // Handle -e xxx
+ if (llvm::opt::Arg *entry = parsedArgs->getLastArg(OPT_entry))
+ info.setEntrySymbolName(entry->getValue());
+
+ // Handle -o xxx
+ if (llvm::opt::Arg *outpath = parsedArgs->getLastArg(OPT_output))
+ info.setOutputPath(outpath->getValue());
+ else
+ info.setOutputPath("-");
+
+ // Handle --dead_strip
+ if (parsedArgs->getLastArg(OPT_dead_strip))
+ info.setDeadStripping(true);
+ else
+ info.setDeadStripping(false);
+
+ // Handle --keep-globals
+ if (parsedArgs->getLastArg(OPT_keep_globals))
+ info.setGlobalsAreDeadStripRoots(true);
+ else
+ info.setGlobalsAreDeadStripRoots(false);
+
+ // Handle --undefines-are-errors
+ if (parsedArgs->getLastArg(OPT_undefines_are_errors)) {
+ info.setPrintRemainingUndefines(true);
+ info.setAllowRemainingUndefines(false);
+ }
+ else {
+ info.setPrintRemainingUndefines(false);
+ info.setAllowRemainingUndefines(true);
+ }
+
+ // Handle --commons-search-archives
+ if (parsedArgs->getLastArg(OPT_commons_search_archives))
+ info.setSearchArchivesToOverrideTentativeDefinitions(true);
+ else
+ info.setSearchArchivesToOverrideTentativeDefinitions(false);
+
+ // Handle --add-pass xxx option
+ for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_add_pass),
+ ie = parsedArgs->filtered_end();
+ it != ie; ++it) {
+ info.addPassNamed((*it)->getValue());
+ }
+
+ // Handle input files
+ for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_INPUT),
+ ie = parsedArgs->filtered_end();
+ it != ie; ++it) {
+ info.appendInputFile((*it)->getValue());
+ }
+
+ return false;
+}
+
+} // namespace lld
+
diff --git a/lld/lib/Driver/CoreOptions.td b/lld/lib/Driver/CoreOptions.td
index 8a53fd35cbe..df7cb41737d 100644
--- a/lld/lib/Driver/CoreOptions.td
+++ b/lld/lib/Driver/CoreOptions.td
@@ -1,22 +1,15 @@
include "llvm/Option/OptParser.td"
-def core : Flag<["-"], "core">;
-def flavor : Separate<["-"], "flavor">;
-def target : Separate<["-"], "target">, HelpText<"Target triple to link for">;
-def mllvm : Separate<["-"], "mllvm">, HelpText<"Options to pass to LLVM">;
-
-def output : Joined<["-"], "output=">;
-def entry : Joined<["-"], "entry=">;
-def input_search_path : Joined<["-"], "input-search-path=">;
-def output_type : Joined<["-"], "output-type=">;
-def relocatable : Flag<["-"], "relocatable">;
+def output : Separate<["-"], "o">;
+def entry : Separate<["-"], "e">;
-def OCTOTHORPE_OCTOTHORPE_OCTOTHORPE : Flag<["-"], "###">;
+def dead_strip : Flag<["--"], "dead-strip">;
+def undefines_are_errors : Flag<["--"], "undefines-are-errors">;
+def keep_globals : Flag<["--"], "keep-globals">;
+def commons_search_archives : Flag<["--"], "commons-search-archives">;
-def emit_yaml : Flag<["-"], "emit-yaml">;
+def add_pass : Separate<["--"], "add-pass">;
-def noinhibit_exec : Flag<["-"], "noinhibit-exec">,
- HelpText<"Retain the executable output file whenever it is still usable">;
+def target : Separate<["-"], "target">, HelpText<"Target triple to link for">;
+def mllvm : Separate<["-"], "mllvm">, HelpText<"Options to pass to LLVM">;
-def merge_strings : Flag<["-"], "merge-strings">,
- HelpText<"Merge common strings across mergeable sections">;
diff --git a/lld/lib/Driver/DarwinLdDriver.cpp b/lld/lib/Driver/DarwinLdDriver.cpp
new file mode 100644
index 00000000000..1dbe5dfec0d
--- /dev/null
+++ b/lld/lib/Driver/DarwinLdDriver.cpp
@@ -0,0 +1,197 @@
+//===- lib/Driver/DarwinLdDriver.cpp --------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// Concrete instance of the Driver for darwin's ld.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/Driver/Driver.h"
+#include "lld/ReaderWriter/MachOTargetInfo.h"
+#include "../ReaderWriter/MachO/MachOFormat.hpp"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Signals.h"
+
+
+namespace {
+
+// Create enum with OPT_xxx values for each option in DarwinOptions.td
+enum DarwinOpt {
+ OPT_INVALID = 0,
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, HELP, META) \
+ OPT_##ID,
+#include "DarwinOptions.inc"
+ LastOption
+#undef OPTION
+};
+
+// Create prefix string literals used in DarwinOptions.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "DarwinOptions.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in DarwinOptions.td
+static const llvm::opt::OptTable::Info infoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR) \
+ { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS },
+#include "DarwinOptions.inc"
+#undef OPTION
+};
+
+// Create OptTable class for parsing actual command line arguments
+class DarwinLdOptTable : public llvm::opt::OptTable {
+public:
+ DarwinLdOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){}
+};
+
+
+} // namespace anonymous
+
+namespace lld {
+
+bool DarwinLdDriver::linkMachO(int argc, const char *argv[],
+ raw_ostream &diagnostics) {
+ MachOTargetInfo info;
+ if (parse(argc, argv, info, diagnostics))
+ return true;
+
+ return link(info, diagnostics);
+}
+
+
+
+bool DarwinLdDriver::parse(int argc, const char *argv[],
+ MachOTargetInfo &info, raw_ostream &diagnostics) {
+ // Parse command line options using DarwinOptions.td
+ std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
+ DarwinLdOptTable table;
+ unsigned missingIndex;
+ unsigned missingCount;
+ parsedArgs.reset(table.ParseArgs(&argv[1], &argv[argc],
+ missingIndex, missingCount));
+ if (missingCount) {
+ diagnostics << "error: missing arg value for '"
+ << parsedArgs->getArgString(missingIndex)
+ << "' expected " << missingCount << " argument(s).\n";
+ return true;
+ }
+
+ for (auto it = parsedArgs->filtered_begin(OPT_UNKNOWN),
+ ie = parsedArgs->filtered_end(); it != ie; ++it) {
+ diagnostics << "warning: ignoring unknown argument: "
+ << (*it)->getAsString(*parsedArgs) << "\n";
+ }
+
+ // Figure out output kind ( -dylib, -r, -bundle, -preload, or -static )
+ if ( llvm::opt::Arg *kind = parsedArgs->getLastArg(OPT_dylib, OPT_relocatable,
+ OPT_bundle, OPT_static, OPT_preload)) {
+ switch (kind->getOption().getID()) {
+ case OPT_dylib:
+ info.setOutputFileType(mach_o::MH_DYLIB);
+ break;
+ case OPT_relocatable:
+ info.setPrintRemainingUndefines(false);
+ info.setAllowRemainingUndefines(true);
+ info.setOutputFileType(mach_o::MH_OBJECT);
+ break;
+ case OPT_bundle:
+ info.setOutputFileType(mach_o::MH_BUNDLE);
+ break;
+ case OPT_static:
+ info.setOutputFileType(mach_o::MH_EXECUTE);
+ break;
+ case OPT_preload:
+ info.setOutputFileType(mach_o::MH_PRELOAD);
+ break;
+ }
+ }
+
+ // Handle -e xxx
+ if (llvm::opt::Arg *entry = parsedArgs->getLastArg(OPT_entry))
+ info.setEntrySymbolName(entry->getValue());
+
+ // Handle -o xxx
+ if (llvm::opt::Arg *outpath = parsedArgs->getLastArg(OPT_output))
+ info.setOutputPath(outpath->getValue());
+
+ // Handle -dead_strip
+ if (parsedArgs->getLastArg(OPT_dead_strip))
+ info.setDeadStripping(true);
+
+ // Handle -arch xxx
+ if (llvm::opt::Arg *archStr = parsedArgs->getLastArg(OPT_arch)) {
+ info.setArch(llvm::StringSwitch<MachOTargetInfo::Arch>(archStr->getValue())
+ .Case("x86_64", MachOTargetInfo::arch_x86_64)
+ .Case("i386", MachOTargetInfo::arch_x86)
+ .Case("armv6", MachOTargetInfo::arch_armv6)
+ .Case("armv7", MachOTargetInfo::arch_armv7)
+ .Case("armv7s", MachOTargetInfo::arch_armv7s)
+ .Default(MachOTargetInfo::arch_unknown));
+ }
+
+ // Handle -macosx_version_min or -ios_version_min
+ if (llvm::opt::Arg *minOS = parsedArgs->getLastArg(
+ OPT_macosx_version_min,
+ OPT_ios_version_min,
+ OPT_ios_simulator_version_min)) {
+ switch (minOS->getOption().getID()) {
+ case OPT_macosx_version_min:
+ if (info.setOS(MachOTargetInfo::OS::macOSX, minOS->getValue())) {
+ diagnostics << "error: malformed macosx_version_min value\n";
+ return true;
+ }
+ break;
+ case OPT_ios_version_min:
+ if (info.setOS(MachOTargetInfo::OS::iOS, minOS->getValue())) {
+ diagnostics << "error: malformed ios_version_min value\n";
+ return true;
+ }
+ break;
+ case OPT_ios_simulator_version_min:
+ if (info.setOS(MachOTargetInfo::OS::iOS_simulator, minOS->getValue())) {
+ diagnostics << "error: malformed ios_simulator_version_min value\n";
+ return true;
+ }
+ break;
+ }
+ }
+ else {
+ // No min-os version on command line, check environment variables
+
+ }
+
+ // Handle input files
+ for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_INPUT),
+ ie = parsedArgs->filtered_end();
+ it != ie; ++it) {
+ info.appendInputFile((*it)->getValue());
+ }
+
+ return false;
+}
+
+
+} // namespace lld
+
+
diff --git a/lld/lib/Driver/DarwinOptions.td b/lld/lib/Driver/DarwinOptions.td
new file mode 100644
index 00000000000..b51d97d5602
--- /dev/null
+++ b/lld/lib/Driver/DarwinOptions.td
@@ -0,0 +1,30 @@
+include "llvm/Option/OptParser.td"
+
+// output kinds
+def relocatable : Flag<["-"], "r">, HelpText<"create relocatable output">;
+def static : Flag<["-"], "static">;
+def dynamic : Flag<["-"], "dynamic">;
+def dylib : Flag<["-"], "dylib">;
+def bundle : Flag<["-"], "bundle">;
+def execute : Flag<["-"], "execute">;
+def preload : Flag<["-"], "preload">;
+
+// linking options
+def dead_strip : Flag<["-"], "dead_strip">;
+def entry : Separate<["-"], "e">, HelpText<"entry symbol name">;
+def mllvm : Separate<["-"], "mllvm">, HelpText<"Options to pass to LLVM">;
+def arch : Separate<["-"], "arch">, HelpText<"architecture">;
+def macosx_version_min : Separate<["-"], "macosx_version_min">,
+ HelpText<"min Mac OS X version">;
+def ios_version_min : Separate<["-"], "ios_version_min">,
+ HelpText<"min iOS version">;
+def ios_simulator_version_min : Separate<["-"], "ios_simulator_version_min">,
+ HelpText<"min iOS simulator version">;
+
+// search options
+def L : Joined<["-"], "L">;
+
+// inputs and outputs
+def output : Separate<["-"], "o">, HelpText<"output file name">;
+
+
diff --git a/lld/lib/Driver/Driver.cpp b/lld/lib/Driver/Driver.cpp
index 5f7f4e6f555..cb3c611c2ce 100644
--- a/lld/lib/Driver/Driver.cpp
+++ b/lld/lib/Driver/Driver.cpp
@@ -8,7 +8,81 @@
//===----------------------------------------------------------------------===//
#include "lld/Driver/Driver.h"
+#include "lld/Core/LLVM.h"
+#include "lld/Core/InputFiles.h"
+#include "lld/Core/Resolver.h"
+#include "lld/Core/PassManager.h"
+#include "lld/ReaderWriter/Reader.h"
+#include "lld/ReaderWriter/Writer.h"
-using namespace lld;
+#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/raw_ostream.h"
+
+namespace lld {
+
+/// This is where the link is actually performed.
+bool Driver::link(const TargetInfo &targetInfo, raw_ostream &diagnostics) {
+ // Honor -mllvm
+ if (!targetInfo.llvmOptions().empty()) {
+ unsigned numArgs = targetInfo.llvmOptions().size();
+ const char **args = new const char*[numArgs + 2];
+ args[0] = "lld (LLVM option parsing)";
+ for (unsigned i = 0; i != numArgs; ++i)
+ args[i + 1] = targetInfo.llvmOptions()[i];
+ args[numArgs + 1] = 0;
+ llvm::cl::ParseCommandLineOptions(numArgs + 1, args);
+ }
+
+ // Read inputs
+ InputFiles inputs;
+ for (const auto &input : targetInfo.inputFiles()) {
+ std::vector<std::unique_ptr<File>> files;
+ if (targetInfo.logInputFiles())
+ llvm::outs() << input.getPath() << "\n";
+
+ error_code ec = targetInfo.readFile(input.getPath(), files);
+ if (ec) {
+ diagnostics << "Failed to read file: " << input.getPath() << ": "
+ << ec.message() << "\n";
+ return true;
+ }
+ inputs.appendFiles(files);
+ }
+
+ // Give target a chance to add files.
+ targetInfo.addImplicitFiles(inputs);
+
+ // assign an ordinal to each file so sort() can preserve command line order
+ inputs.assignFileOrdinals();
+
+ // Do core linking.
+ Resolver resolver(targetInfo, inputs);
+ if (resolver.resolve()) {
+ if (!targetInfo.allowRemainingUndefines())
+ return true;
+ }
+ MutableFile &merged = resolver.resultFile();
+
+ // Run passes on linked atoms.
+ PassManager pm;
+ targetInfo.addPasses(pm);
+ pm.runOnFile(merged);
+
+ // Give linked atoms to Writer to generate output file.
+ if (error_code ec = targetInfo.writeFile(merged)) {
+ diagnostics << "Failed to write file '" << targetInfo.outputPath()
+ << "': " << ec.message() << "\n";
+ return true;
+ }
+
+ return false;
+}
+
+
+} // namespace
-Driver::~Driver() {}
diff --git a/lld/lib/Driver/Drivers.cpp b/lld/lib/Driver/Drivers.cpp
deleted file mode 100644
index d2c1b732046..00000000000
--- a/lld/lib/Driver/Drivers.cpp
+++ /dev/null
@@ -1,303 +0,0 @@
-//===- lib/Driver/Drivers.cpp - Linker Driver Emulators -------------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-///
-/// Concrete instances of the Driver interface.
-///
-//===----------------------------------------------------------------------===//
-
-#include "lld/Driver/Driver.h"
-
-#include "lld/Core/LinkerOptions.h"
-
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/Option/Arg.h"
-#include "llvm/Option/Option.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace lld;
-
-namespace core {
-enum ID {
- OPT_INVALID = 0,
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, HELP, META) \
- OPT_##ID,
-#include "CoreOptions.inc"
- LastOption
-#undef OPTION
-};
-
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
-#include "CoreOptions.inc"
-#undef PREFIX
-
-static const llvm::opt::OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
- HELPTEXT, METAVAR) \
- { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS },
-#include "CoreOptions.inc"
-#undef OPTION
-};
-
-class CoreOptTable : public llvm::opt::OptTable {
-public:
- CoreOptTable() : OptTable(InfoTable, llvm::array_lengthof(InfoTable)){}
-};
-}
-
-namespace ld {
-enum LDOpt {
- OPT_INVALID = 0,
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, HELP, META) \
- OPT_##ID,
-#include "LDOptions.inc"
- LastOption
-#undef OPTION
-};
-
-#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
-#include "LDOptions.inc"
-#undef PREFIX
-
-static const llvm::opt::OptTable::Info InfoTable[] = {
-#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
- HELPTEXT, METAVAR) \
- { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
- PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS },
-#include "LDOptions.inc"
-#undef OPTION
-};
-
-class LDOptTable : public llvm::opt::OptTable {
-public:
- LDOptTable() : OptTable(InfoTable, llvm::array_lengthof(InfoTable)){}
-};
-}
-
-class LDDriver LLVM_FINAL : public Driver {
-public:
- LDDriver(StringRef defaultTargetTriple) : Driver(defaultTargetTriple) {}
-
- virtual std::unique_ptr<llvm::opt::DerivedArgList>
- transform(llvm::ArrayRef<const char *> args) {
- assert(!_inputArgs && "transform may only be called once!");
-
- unsigned missingIndex, missingCount;
- _inputArgs.reset(_opt.ParseArgs( args.begin(), args.end()
- , missingIndex, missingCount));
-
- if (missingCount) {
- llvm::errs() << "error: missing arg value for '"
- << _inputArgs->getArgString(missingIndex)
- << "' expected " << missingCount << " argument(s).\n";
- return std::unique_ptr<llvm::opt::DerivedArgList>();
- }
-
- for (llvm::opt::arg_iterator it = _inputArgs->filtered_begin(ld::OPT_UNKNOWN),
- ie = _inputArgs->filtered_end();
- it != ie; ++it) {
- llvm::errs() << "warning: ignoring unknown argument: "
- << (*it)->getAsString(*_inputArgs) << "\n";
- }
-
- std::unique_ptr<llvm::opt::DerivedArgList> newArgs(
- new llvm::opt::DerivedArgList(*_inputArgs));
-
- bool isOutputDynamic = false;
-
- if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_target)) {
- newArgs->AddSeparateArg( A, _core.getOption(core::OPT_target)
- , A->getValue());
- } else {
- assert(!_defaultTargetTriple.empty() && "Got empty target triple!");
- newArgs->AddSeparateArg(nullptr, _core.getOption(core::OPT_target)
- , _defaultTargetTriple);
- }
-
- if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_entry))
- newArgs->AddJoinedArg(A, _core.getOption(core::OPT_entry), A->getValue());
-
- if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_output))
- newArgs->AddJoinedArg(A, _core.getOption(core::OPT_output),
- A->getValue());
- else
- newArgs->AddJoinedArg(nullptr, _core.getOption(core::OPT_output),
- "a.out");
-
- if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_static))
- newArgs->AddJoinedArg(A, _core.getOption(core::OPT_output_type),
- newArgs->MakeArgString("static"));
- else {
- newArgs->AddJoinedArg(nullptr, _core.getOption(core::OPT_output_type),
- newArgs->MakeArgString("dynamic"));
- isOutputDynamic = true;
- }
-
- if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_relocatable))
- newArgs->AddFlagArg(A, _core.getOption(core::OPT_relocatable));
-
- if (llvm::opt::Arg *A =
- _inputArgs->getLastArg(ld::OPT_OCTOTHORPE_OCTOTHORPE_OCTOTHORPE))
- newArgs->AddFlagArg(A, _core.getOption(
- core::OPT_OCTOTHORPE_OCTOTHORPE_OCTOTHORPE));
-
- if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_emit_yaml))
- newArgs->AddFlagArg(A, _core.getOption(core::OPT_emit_yaml));
-
- if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_noinhibit_exec))
- newArgs->AddFlagArg(A, _core.getOption(core::OPT_noinhibit_exec));
-
- if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_merge_strings))
- newArgs->AddFlagArg(A, _core.getOption(core::OPT_merge_strings));
-
- // Copy search paths.
- for (llvm::opt::arg_iterator it = _inputArgs->filtered_begin(ld::OPT_L),
- ie = _inputArgs->filtered_end();
- it != ie; ++it) {
- newArgs->AddPositionalArg(
- *it, _core.getOption(core::OPT_input_search_path), (*it)->getValue());
- _inputSearchPaths.push_back((*it)->getValue());
- }
-
- // Copy input args.
- for (llvm::opt::arg_iterator it = _inputArgs->filtered_begin(ld::OPT_INPUT,
- ld::OPT_l),
- ie = _inputArgs->filtered_end();
- it != ie; ++it) {
- StringRef inputPath;
- if ((*it)->getOption().getID() == ld::OPT_l) {
- StringRef libName = (*it)->getValue();
- SmallString<128> p;
- for (const auto &path : _inputSearchPaths) {
- if (isOutputDynamic) {
- p = path;
- llvm::sys::path::append(p, Twine("lib") + libName + ".so");
- if (llvm::sys::fs::exists(p.str())) {
- inputPath = newArgs->MakeArgString(p);
- break;
- }
- }
- p = path;
- llvm::sys::path::append(p, Twine("lib") + libName + ".a");
- if (llvm::sys::fs::exists(p.str())) {
- inputPath = newArgs->MakeArgString(p);
- break;
- }
- }
- if (inputPath.empty())
- llvm_unreachable("Failed to lookup library!");
- } else
- inputPath = (*it)->getValue();
- newArgs->AddPositionalArg(*it, _core.getOption(core::OPT_INPUT),
- inputPath);
- }
-
- // Copy mllvm
- for (llvm::opt::arg_iterator it = _inputArgs->filtered_begin(ld::OPT_mllvm),
- ie = _inputArgs->filtered_end();
- it != ie; ++it) {
- newArgs->AddPositionalArg(*it, _core.getOption(core::OPT_mllvm),
- (*it)->getValue());
- }
-
- return std::move(newArgs);
- }
-
-private:
- std::unique_ptr<llvm::opt::InputArgList> _inputArgs;
- core::CoreOptTable _core;
- ld::LDOptTable _opt;
- // Local cache of search paths so we can do lookups on -l.
- std::vector<std::string> _inputSearchPaths;
-};
-
-std::unique_ptr<Driver> Driver::create( Driver::Flavor flavor
- , StringRef defaultTargetTriple) {
- switch (flavor) {
- case Flavor::ld:
- return std::unique_ptr<Driver>(new LDDriver(defaultTargetTriple));
- case Flavor::core:
- case Flavor::ld64:
- case Flavor::link:
- case Flavor::invalid:
- break;
- }
- llvm_unreachable("Unsupported flavor");
-}
-
-std::unique_ptr<llvm::opt::ArgList>
-lld::parseCoreArgs(llvm::ArrayRef<const char *> args) {
- core::CoreOptTable core;
- unsigned missingIndex, missingCount;
- std::unique_ptr<llvm::opt::ArgList> list(
- core.ParseArgs( args.begin(), args.end(), missingIndex, missingCount));
-
- if (missingCount) {
- llvm::errs() << "error: missing arg value for '"
- << list->getArgString(missingIndex)
- << "' expected " << missingCount << " argument(s).\n";
- return std::unique_ptr<llvm::opt::ArgList>();
- }
-
- bool hasUnknown = false;
- for (llvm::opt::arg_iterator it = list->filtered_begin(ld::OPT_UNKNOWN),
- ie = list->filtered_end();
- it != ie; ++it) {
- llvm::errs() << "error: ignoring unknown argument: "
- << (*it)->getAsString(*list) << "\n";
- hasUnknown = true;
- }
- if (hasUnknown)
- return std::unique_ptr<llvm::opt::ArgList>();
-
- return list;
-}
-
-LinkerOptions lld::generateOptions(const llvm::opt::ArgList &args) {
- LinkerOptions ret;
-
- for (llvm::opt::arg_iterator it = args.filtered_begin(ld::OPT_INPUT),
- ie = args.filtered_end();
- it != ie; ++it) {
- ret._input.push_back(LinkerInput((*it)->getValue()));
- }
-
- StringRef outputType = args.getLastArgValue(core::OPT_output_type);
- ret._outputKind = llvm::StringSwitch<OutputKind>(outputType)
- .Case("static", OutputKind::StaticExecutable)
- .Case("dynamic", OutputKind::DynamicExecutable)
- .Case("relocatable", OutputKind::Relocatable)
- .Case("shared", OutputKind::Shared)
- .Case("stubs", OutputKind::SharedStubs)
- .Case("core", OutputKind::Core)
- .Case("debug-symbols", OutputKind::DebugSymbols)
- .Case("bundle", OutputKind::Bundle)
- .Case("preload", OutputKind::Preload)
- .Default(OutputKind::Invalid);
-
- ret._inputSearchPaths = args.getAllArgValues(core::OPT_input_search_path);
- ret._llvmArgs = args.getAllArgValues(core::OPT_mllvm);
- ret._target = llvm::Triple::normalize(args.getLastArgValue(core::OPT_target));
- ret._outputPath = args.getLastArgValue(core::OPT_output);
- ret._entrySymbol = args.getLastArgValue(core::OPT_entry);
- if (args.hasArg(core::OPT_relocatable))
- ret._outputKind = OutputKind::Relocatable;
- ret._outputCommands = args.hasArg(core::OPT_OCTOTHORPE_OCTOTHORPE_OCTOTHORPE);
- ret._outputYAML = args.hasArg(core::OPT_emit_yaml);
- ret._noInhibitExec = args.hasArg(core::OPT_noinhibit_exec);
- ret._mergeCommonStrings = args.hasArg(core::OPT_merge_strings);
-
- return std::move(ret);
-}
diff --git a/lld/lib/Driver/GnuLdDriver.cpp b/lld/lib/Driver/GnuLdDriver.cpp
new file mode 100644
index 00000000000..55e38580029
--- /dev/null
+++ b/lld/lib/Driver/GnuLdDriver.cpp
@@ -0,0 +1,241 @@
+//===- lib/Driver/GnuLdDriver.cpp -----------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// Concrete instance of the Driver for GNU's ld.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/Driver/Driver.h"
+#include "lld/ReaderWriter/ELFTargetInfo.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Signals.h"
+
+using namespace lld;
+
+
+namespace {
+
+// Create enum with OPT_xxx values for each option in LDOptions.td
+enum LDOpt {
+ OPT_INVALID = 0,
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, HELP, META) \
+ OPT_##ID,
+#include "LDOptions.inc"
+ LastOption
+#undef OPTION
+};
+
+// Create prefix string literals used in LDOptions.td
+#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
+#include "LDOptions.inc"
+#undef PREFIX
+
+// Create table mapping all options defined in LDOptions.td
+static const llvm::opt::OptTable::Info infoTable[] = {
+#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \
+ HELPTEXT, METAVAR) \
+ { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \
+ PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS },
+#include "LDOptions.inc"
+#undef OPTION
+};
+
+
+// Create OptTable class for parsing actual command line arguments
+class GnuLdOptTable : public llvm::opt::OptTable {
+public:
+ GnuLdOptTable() : OptTable(infoTable, llvm::array_lengthof(infoTable)){}
+};
+
+} // namespace
+
+
+
+bool GnuLdDriver::linkELF(int argc, const char *argv[],
+ raw_ostream &diagnostics) {
+ std::unique_ptr<ELFTargetInfo> options(parse(argc, argv, diagnostics));
+ if (!options)
+ return true;
+
+ return link(*options, diagnostics);
+}
+
+
+std::unique_ptr<ELFTargetInfo> GnuLdDriver::parse(int argc, const char *argv[],
+ raw_ostream &diagnostics) {
+ // Parse command line options using LDOptions.td
+ std::unique_ptr<llvm::opt::InputArgList> parsedArgs;
+ GnuLdOptTable table;
+ unsigned missingIndex;
+ unsigned missingCount;
+ parsedArgs.reset(table.ParseArgs(&argv[1], &argv[argc],
+ missingIndex, missingCount));
+ if (missingCount) {
+ diagnostics << "error: missing arg value for '"
+ << parsedArgs->getArgString(missingIndex)
+ << "' expected " << missingCount << " argument(s).\n";
+ return nullptr;
+ }
+
+ for (auto it = parsedArgs->filtered_begin(OPT_UNKNOWN),
+ ie = parsedArgs->filtered_end(); it != ie; ++it) {
+ diagnostics << "warning: ignoring unknown argument: "
+ << (*it)->getAsString(*parsedArgs) << "\n";
+ }
+
+ // Handle --help
+ if (parsedArgs->getLastArg(OPT_help)) {
+ table.PrintHelp(llvm::outs(), argv[0], "LLVM Linker", false);
+ return nullptr;
+ }
+
+ // Use -target or use default target triple to instantiate TargetInfo
+ llvm::Triple triple;
+ if (llvm::opt::Arg *trip = parsedArgs->getLastArg(OPT_target))
+ triple = llvm::Triple(trip->getValue());
+ else
+ triple = getDefaultTarget(argv[0]);
+ std::unique_ptr<ELFTargetInfo> options(ELFTargetInfo::create(triple));
+
+ if (!options) {
+ diagnostics << "unknown target triple\n";
+ return nullptr;
+ }
+
+ // Handle -e xxx
+ if (llvm::opt::Arg *entry = parsedArgs->getLastArg(OPT_entry))
+ options->setEntrySymbolName(entry->getValue());
+
+ // Handle -emit-yaml
+ if (parsedArgs->getLastArg(OPT_emit_yaml))
+ options->setOutputYAML(true);
+
+ // Handle -o xxx
+ if (llvm::opt::Arg *output = parsedArgs->getLastArg(OPT_output))
+ options->setOutputPath(output->getValue());
+ else if (options->outputYAML())
+ options->setOutputPath("-"); // yaml writes to stdout by default
+ else
+ options->setOutputPath("a.out");
+
+ // Handle -r, -shared, or -static
+ if ( llvm::opt::Arg *kind = parsedArgs->getLastArg(OPT_relocatable,
+ OPT_shared,
+ OPT_static)) {
+ switch (kind->getOption().getID()) {
+ case OPT_relocatable:
+ options->setOutputFileType(llvm::ELF::ET_REL);
+ options->setPrintRemainingUndefines(false);
+ options->setAllowRemainingUndefines(true);
+ break;
+ case OPT_shared:
+ options->setOutputFileType(llvm::ELF::ET_DYN);
+ break;
+ case OPT_static:
+ options->setOutputFileType(llvm::ELF::ET_EXEC);
+ options->setIsStaticExecutable(true);
+ break;
+ }
+ }
+ else {
+ options->setOutputFileType(llvm::ELF::ET_EXEC);
+ options->setIsStaticExecutable(false);
+ }
+
+ // Handle --noinhibit-exec
+ if (parsedArgs->getLastArg(OPT_noinhibit_exec))
+ options->setAllowRemainingUndefines(true);
+
+ // Handle --force-load
+ if (parsedArgs->getLastArg(OPT_force_load))
+ options->setForceLoadAllArchives(true);
+
+ // Handle --merge-strings
+ if (parsedArgs->getLastArg(OPT_merge_strings))
+ options->setMergeCommonStrings(true);
+
+ // Handle -t
+ if (parsedArgs->getLastArg(OPT_t))
+ options->setLogInputFiles(true);
+
+ // Handle -Lxxx
+ for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_L),
+ ie = parsedArgs->filtered_end();
+ it != ie; ++it) {
+ options->appendSearchPath((*it)->getValue());
+ }
+
+ // Copy mllvm
+ for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_mllvm),
+ ie = parsedArgs->filtered_end();
+ it != ie; ++it) {
+ options->appendLLVMOption((*it)->getValue());
+ }
+
+ // Handle input files (full paths and -lxxx)
+ for (llvm::opt::arg_iterator it = parsedArgs->filtered_begin(OPT_INPUT,OPT_l),
+ ie = parsedArgs->filtered_end();
+ it != ie; ++it) {
+ switch ((*it)->getOption().getID()) {
+ case OPT_INPUT:
+ options->appendInputFile((*it)->getValue());
+ break;
+ case OPT_l:
+ if (options->appendLibrary((*it)->getValue())) {
+ diagnostics << "Failed to find library for "
+ << (*it)->getValue() << "\n";
+ return nullptr;
+ }
+ break;
+ default:
+ llvm_unreachable("input option type not handled");
+ }
+ }
+
+ // Validate the combination of options used.
+ if (options->validate(diagnostics))
+ return nullptr;
+
+ return options;
+}
+
+
+/// Get the default target triple based on either the program name
+/// (e.g. "x86-ibm-linux-lld") or the primary target llvm was configured for.
+llvm::Triple GnuLdDriver::getDefaultTarget(const char *progName) {
+ SmallVector<StringRef, 4> components;
+ llvm::SplitString(llvm::sys::path::stem(progName), components, "-");
+ // If has enough parts to be start with a triple.
+ if (components.size() >= 4) {
+ llvm::Triple triple(components[0], components[1], components[2],
+ components[3]);
+ // If first component looks like an arch.
+ if (triple.getArch() != llvm::Triple::UnknownArch)
+ return triple;
+ }
+
+ // Fallback to use whatever default triple llvm was configured for.
+ return llvm::Triple(llvm::sys::getDefaultTargetTriple());
+}
+
diff --git a/lld/lib/Driver/LDOptions.td b/lld/lib/Driver/LDOptions.td
index 516d487b41a..47e8a3cf78a 100644
--- a/lld/lib/Driver/LDOptions.td
+++ b/lld/lib/Driver/LDOptions.td
@@ -1,27 +1,29 @@
include "llvm/Option/OptParser.td"
-def flavor : Separate<["-"], "flavor">;
-def target : Separate<["-"], "target">, HelpText<"Target triple to link for">;
+def target : Separate<["-"], "target">,
+ MetaVarName<"<triple>">,
+ HelpText<"Target triple to link for">;
+
def mllvm : Separate<["-"], "mllvm">, HelpText<"Options to pass to LLVM">;
-def entry : Joined<["--"], "entry=">;
+def entry : Joined<["--"], "entry=">,
+ HelpText<"Name of entry point symbol">;
def entry_e : Separate<["-"], "e">, Alias<entry>;
-def output : Joined<["--"], "output=">;
-def output_e : Separate<["-"], "o">, Alias<output>;
-
+def output : Separate<["-"], "o">,
+ MetaVarName<"<path>">,
+ HelpText<"Path to file to write output">;
+
def relocatable : Flag<["--"], "relocatable">;
def relocatable_r : Flag<["-"], "r">, Alias<relocatable>;
def dynamic_linker : Separate<["-"], "dynamic-linker">;
-def OCTOTHORPE_OCTOTHORPE_OCTOTHORPE : Flag<["-"], "###">;
-
-def emit_yaml : Flag<["-"], "emit-yaml">;
def m : Separate<["-"], "m">;
def z : Separate<["-"], "z">;
+def t : Flag<["-"], "t">;
def rpath : Separate<["-"], "rpath">;
def soname : Separate<["-"], "soname">;
@@ -32,12 +34,25 @@ def end_group : Flag<["--"], "end-group">;
def build_id : Flag<["--"], "build-id">;
def eh_frame_hdr : Flag<["--"], "eh-frame-hdr">;
-def L : Joined<["-"], "L">;
-def l : Joined<["-"], "l">;
+def help : Flag<["--"], "help">;
+
+def L : Joined<["-"], "L">,
+ MetaVarName<"<dir>">,
+ HelpText<"Directory to search for libraries">;
+def l : Joined<["-"], "l">,
+ MetaVarName<"<libName>">,
+ HelpText<"Root name of library to use">;
def hash_style : Joined <["--"], "hash-style=">;
def noinhibit_exec : Flag<["--"], "noinhibit-exec">,
HelpText<"Retain the executable output file whenever it is still usable">;
-def merge_strings : Flag<["-"], "merge-strings">,
+def merge_strings : Flag<["--"], "merge-strings">,
HelpText<"Merge common strings across mergeable sections">;
+
+
+// extensions
+def emit_yaml : Flag<["-"], "emit-yaml">,
+ HelpText<"Write YAML instead of ELF">;
+def force_load : Flag<["--"], "force-load">,
+ HelpText<"Force load of all members in all static libraries">;
diff --git a/lld/lib/Driver/LinkerInvocation.cpp b/lld/lib/Driver/LinkerInvocation.cpp
deleted file mode 100644
index 21662774bd9..00000000000
--- a/lld/lib/Driver/LinkerInvocation.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-//===- lib/Driver/LinkerInvocation.cpp - Linker Invocation ----------------===//
-//
-// The LLVM Linker
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "lld/Driver/LinkerInvocation.h"
-
-#include "lld/Core/InputFiles.h"
-#include "lld/Core/PassManager.h"
-#include "lld/Core/Resolver.h"
-#include "lld/ReaderWriter/ELFTargetInfo.h"
-#include "lld/ReaderWriter/Reader.h"
-#include "lld/ReaderWriter/Writer.h"
-
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace lld;
-
-namespace {
-std::unique_ptr<TargetInfo> createTargetInfo(const LinkerOptions &lo) {
- return ELFTargetInfo::create(lo);
-}
-}
-
-void LinkerInvocation::operator()() {
- // Honor -mllvm
- if (!_options._llvmArgs.empty()) {
- unsigned NumArgs = _options._llvmArgs.size();
- const char **Args = new const char*[NumArgs + 2];
- Args[0] = "lld (LLVM option parsing)";
- for (unsigned i = 0; i != NumArgs; ++i)
- Args[i + 1] = _options._llvmArgs[i].c_str();
- Args[NumArgs + 1] = 0;
- llvm::cl::ParseCommandLineOptions(NumArgs + 1, Args);
- }
-
- // Create target.
- std::unique_ptr<TargetInfo> targetInfo(createTargetInfo(_options));
-
- if (!targetInfo) {
- llvm::errs() << "Failed to create target for " << _options._target
- << "\n";
- return;
- }
-
- // Read inputs
- InputFiles inputs;
- for (const auto &input : _options._input) {
- auto reader = targetInfo->getReader(input);
- if (error_code ec = reader) {
- llvm::errs() << "Failed to get reader for: " << input.getPath() << ": "
- << ec.message() << "\n";
- return;
- }
-
- auto buffer = input.getBuffer();
- if (error_code ec = buffer) {
- llvm::errs() << "Failed to read file: " << input.getPath() << ": "
- << ec.message() << "\n";
- return;
- }
-
- std::vector<std::unique_ptr<File>> files;
- if (llvm::error_code ec = reader->parseFile(std::unique_ptr<MemoryBuffer>(MemoryBuffer::getMemBuffer(buffer->getBuffer(), buffer->getBufferIdentifier())), files)) {
- llvm::errs() << "Failed to read file: " << input.getPath() << ": "
- << ec.message() << "\n";
- return;
- }
- inputs.appendFiles(files);
- }
- inputs.assignFileOrdinals();
-
- auto writer = targetInfo->getWriter();
-
- // Give writer a chance to add files
- writer->addFiles(inputs);
-
- Resolver resolver(*targetInfo, inputs);
- resolver.resolve();
- MutableFile &merged = resolver.resultFile();
-
- PassManager pm;
- targetInfo->addPasses(pm);
- pm.runOnFile(merged);
-
- if (error_code ec = writer) {
- llvm::errs() << "Failed to get writer: " << ec.message() << ".\n";
- return;
- }
-
- if (error_code ec = writer->writeFile(merged, _options._outputPath))
- llvm::errs() << "Failed to write file: " << ec.message() << "\n";
-}
diff --git a/lld/lib/Driver/UniversalDriver.cpp b/lld/lib/Driver/UniversalDriver.cpp
new file mode 100644
index 00000000000..5164f9da69c
--- /dev/null
+++ b/lld/lib/Driver/UniversalDriver.cpp
@@ -0,0 +1,109 @@
+//===- lib/Driver/UniversalDriver.cpp -------------------------------------===//
+//
+// The LLVM Linker
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+///
+/// Concrete instance of the Driver for darwin's ld.
+///
+//===----------------------------------------------------------------------===//
+
+#include "lld/Driver/Driver.h"
+#include "lld/ReaderWriter/MachOTargetInfo.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Option/Arg.h"
+#include "llvm/Option/Option.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/Signals.h"
+
+#include <memory>
+
+namespace lld {
+
+
+bool UniversalDriver::link(int argc, const char *argv[]) {
+ // Convert argv[] C-array to vector.
+ std::vector<const char *> args;
+ args.assign(&argv[0], &argv[argc]);
+
+ // Determine flavor of link based on command name or -flavor argument.
+ // Note: 'args' is modified to remove -flavor option.
+ Flavor flavor = selectFlavor(args);
+
+ // Switch to appropriate driver.
+ switch (flavor) {
+ case Flavor::gnu_ld:
+ return GnuLdDriver::linkELF(args.size(), &args[0]);
+ case Flavor::darwin_ld:
+ return DarwinLdDriver::linkMachO(args.size(), &args[0]);
+ case Flavor::core:
+ return CoreDriver::link(args.size(), &args[0]);
+ case Flavor::win_link:
+ llvm_unreachable("Unsupported flavor");
+ case Flavor::invalid:
+ return true;
+ }
+}
+
+
+
+
+
+/// Pick the flavor of driver to use based on the command line and
+/// host environment.
+UniversalDriver::Flavor UniversalDriver::selectFlavor(
+ std::vector<const char*> &args) {
+ // -core as first arg is shorthand for -flavor core.
+ if (args.size() >= 1 && StringRef(args[1]) == "-core") {
+ args.erase(args.begin() + 1);
+ return Flavor::core;
+ }
+ // Handle -flavor as first arg.
+ if (args.size() >= 2 && StringRef(args[1]) == "-flavor") {
+ Flavor flavor = strToFlavor(args[2]);
+ args.erase(args.begin() + 1);
+ args.erase(args.begin() + 1);
+ if (flavor == Flavor::invalid)
+ llvm::errs() << "error: '" << args[2] << "' invalid value for -flavor.\n";
+ return flavor;
+ }
+
+ // Check if flavor is at end of program name (e.g. "lld-gnu");
+ SmallVector<StringRef, 3> components;
+ llvm::SplitString(args[0], components, "-");
+ Flavor flavor = strToFlavor(components.back());
+
+ // If flavor still undetermined, then error out.
+ if (flavor == Flavor::invalid)
+ llvm::errs() << "error: failed to determine driver flavor from program name"
+ " '" << args[0] << "'.\n";
+ return flavor;
+}
+
+/// Maps flavor strings to Flavor enum values.
+UniversalDriver::Flavor UniversalDriver::strToFlavor(StringRef str) {
+ return llvm::StringSwitch<Flavor>(str)
+ .Case("gnu", Flavor::gnu_ld)
+ .Case("darwin", Flavor::darwin_ld)
+ .Case("link", Flavor::win_link)
+ .Case("core", Flavor::core)
+ .Case("ld", Flavor::gnu_ld) // deprecated
+ .Default(Flavor::invalid);
+}
+
+
+} // namespace lld
OpenPOWER on IntegriCloud