| //===- lib/Driver/Drivers.cpp - Linker Driver Emulators -------------------===// |
| // |
| // The LLVM Linker |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| /// |
| /// \file |
| /// |
| /// Concrete instances of the Driver interface. |
| /// |
| //===----------------------------------------------------------------------===// |
| |
| #include "lld/Driver/Driver.h" |
| |
| #include "lld/Driver/LinkerOptions.h" |
| |
| #include "llvm/ADT/ArrayRef.h" |
| #include "llvm/ADT/STLExtras.h" |
| #include "llvm/ADT/Triple.h" |
| #include "llvm/Option/Arg.h" |
| #include "llvm/Option/Option.h" |
| #include "llvm/Support/raw_ostream.h" |
| |
| using namespace lld; |
| |
| namespace core { |
| enum ID { |
| OPT_INVALID = 0, |
| #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, HELP, META) \ |
| OPT_##ID, |
| #include "CoreOptions.inc" |
| LastOption |
| #undef OPTION |
| }; |
| |
| #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; |
| #include "CoreOptions.inc" |
| #undef PREFIX |
| |
| static const llvm::opt::OptTable::Info InfoTable[] = { |
| #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ |
| HELPTEXT, METAVAR) \ |
| { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ |
| PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS }, |
| #include "CoreOptions.inc" |
| #undef OPTION |
| }; |
| |
| class CoreOptTable : public llvm::opt::OptTable { |
| public: |
| CoreOptTable() : OptTable(InfoTable, llvm::array_lengthof(InfoTable)){} |
| }; |
| } |
| |
| namespace ld { |
| enum LDOpt { |
| OPT_INVALID = 0, |
| #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, HELP, META) \ |
| OPT_##ID, |
| #include "LDOptions.inc" |
| LastOption |
| #undef OPTION |
| }; |
| |
| #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; |
| #include "LDOptions.inc" |
| #undef PREFIX |
| |
| static const llvm::opt::OptTable::Info InfoTable[] = { |
| #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ |
| HELPTEXT, METAVAR) \ |
| { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ |
| PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS }, |
| #include "LDOptions.inc" |
| #undef OPTION |
| }; |
| |
| class LDOptTable : public llvm::opt::OptTable { |
| public: |
| LDOptTable() : OptTable(InfoTable, llvm::array_lengthof(InfoTable)){} |
| }; |
| } |
| |
| class LDDriver 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)); |
| |
| 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()); |
| else |
| newArgs->AddJoinedArg(nullptr, _core.getOption(core::OPT_entry), |
| "_start"); |
| |
| if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_output)) |
| newArgs->AddJoinedArg(A, _core.getOption(core::OPT_output), |
| A->getValue()); |
| else |
| newArgs->AddJoinedArg(nullptr, _core.getOption(core::OPT_output), |
| "a.out"); |
| |
| if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_relocatable)) |
| newArgs->AddFlagArg(A, _core.getOption(core::OPT_relocatable)); |
| |
| 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)); |
| |
| // Copy input args. |
| for (llvm::opt::arg_iterator it = _inputArgs->filtered_begin(ld::OPT_INPUT), |
| ie = _inputArgs->filtered_end(); |
| it != ie; ++it) { |
| newArgs->AddPositionalArg(*it, _core.getOption(core::OPT_INPUT), |
| (*it)->getValue()); |
| } |
| |
| // 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; |
| }; |
| |
| std::unique_ptr<Driver> Driver::create( Driver::Flavor flavor |
| , StringRef defaultTargetTriple) { |
| switch (flavor) { |
| case Flavor::ld: |
| return std::unique_ptr<Driver>(new LDDriver(defaultTargetTriple)); |
| case Flavor::core: |
| case Flavor::ld64: |
| case Flavor::link: |
| case Flavor::invalid: |
| llvm_unreachable("Unsupported flavor"); |
| } |
| } |
| |
| 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(), InputKind::Object)); |
| } |
| |
| 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); |
| ret._relocatable = args.hasArg(core::OPT_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); |
| |
| return std::move(ret); |
| } |