| Michael J. Spencer | 9ff4be2 | 2012-12-08 00:47:36 +0000 | [diff] [blame] | 1 | //===- lib/Driver/Drivers.cpp - Linker Driver Emulators -------------------===// |
| 2 | // |
| 3 | // The LLVM Linker |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | /// |
| 10 | /// \file |
| 11 | /// |
| 12 | /// Concrete instances of the Driver interface. |
| 13 | /// |
| 14 | //===----------------------------------------------------------------------===// |
| 15 | |
| 16 | #include "lld/Driver/Driver.h" |
| 17 | |
| 18 | #include "lld/Driver/LinkerOptions.h" |
| 19 | |
| 20 | #include "llvm/ADT/ArrayRef.h" |
| 21 | #include "llvm/ADT/STLExtras.h" |
| 22 | #include "llvm/ADT/Triple.h" |
| 23 | #include "llvm/Option/Arg.h" |
| 24 | #include "llvm/Option/Option.h" |
| 25 | #include "llvm/Support/raw_ostream.h" |
| 26 | |
| 27 | using namespace lld; |
| 28 | |
| 29 | namespace core { |
| 30 | enum ID { |
| 31 | OPT_INVALID = 0, |
| 32 | #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, HELP, META) \ |
| 33 | OPT_##ID, |
| 34 | #include "CoreOptions.inc" |
| 35 | LastOption |
| 36 | #undef OPTION |
| 37 | }; |
| 38 | |
| 39 | #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; |
| 40 | #include "CoreOptions.inc" |
| 41 | #undef PREFIX |
| 42 | |
| 43 | static const llvm::opt::OptTable::Info InfoTable[] = { |
| 44 | #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ |
| 45 | HELPTEXT, METAVAR) \ |
| 46 | { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ |
| 47 | PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS }, |
| 48 | #include "CoreOptions.inc" |
| 49 | #undef OPTION |
| 50 | }; |
| 51 | |
| 52 | class CoreOptTable : public llvm::opt::OptTable { |
| 53 | public: |
| 54 | CoreOptTable() : OptTable(InfoTable, llvm::array_lengthof(InfoTable)){} |
| 55 | }; |
| 56 | } |
| 57 | |
| 58 | namespace ld { |
| 59 | enum LDOpt { |
| 60 | OPT_INVALID = 0, |
| 61 | #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, HELP, META) \ |
| 62 | OPT_##ID, |
| 63 | #include "LDOptions.inc" |
| 64 | LastOption |
| 65 | #undef OPTION |
| 66 | }; |
| 67 | |
| 68 | #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; |
| 69 | #include "LDOptions.inc" |
| 70 | #undef PREFIX |
| 71 | |
| 72 | static const llvm::opt::OptTable::Info InfoTable[] = { |
| 73 | #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ |
| 74 | HELPTEXT, METAVAR) \ |
| 75 | { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, llvm::opt::Option::KIND##Class, \ |
| 76 | PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS }, |
| 77 | #include "LDOptions.inc" |
| 78 | #undef OPTION |
| 79 | }; |
| 80 | |
| 81 | class LDOptTable : public llvm::opt::OptTable { |
| 82 | public: |
| 83 | LDOptTable() : OptTable(InfoTable, llvm::array_lengthof(InfoTable)){} |
| 84 | }; |
| 85 | } |
| 86 | |
| 87 | class LDDriver final : public Driver { |
| 88 | public: |
| 89 | LDDriver(StringRef defaultTargetTriple) : Driver(defaultTargetTriple) {} |
| 90 | |
| 91 | virtual std::unique_ptr<llvm::opt::DerivedArgList> |
| Andy Gibbs | d02bf1d | 2012-12-22 09:46:10 +0000 | [diff] [blame] | 92 | transform(llvm::ArrayRef<const char *> args) { |
| Michael J. Spencer | 9ff4be2 | 2012-12-08 00:47:36 +0000 | [diff] [blame] | 93 | assert(!_inputArgs && "transform may only be called once!"); |
| 94 | |
| 95 | unsigned missingIndex, missingCount; |
| 96 | _inputArgs.reset(_opt.ParseArgs( args.begin(), args.end() |
| 97 | , missingIndex, missingCount)); |
| 98 | |
| 99 | if (missingCount) { |
| 100 | llvm::errs() << "error: missing arg value for '" |
| 101 | << _inputArgs->getArgString(missingIndex) |
| 102 | << "' expected " << missingCount << " argument(s).\n"; |
| 103 | return std::unique_ptr<llvm::opt::DerivedArgList>(); |
| 104 | } |
| 105 | |
| 106 | std::unique_ptr<llvm::opt::DerivedArgList> newArgs( |
| 107 | new llvm::opt::DerivedArgList(*_inputArgs)); |
| 108 | |
| 109 | if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_target)) { |
| Michael J. Spencer | 9ff4be2 | 2012-12-08 00:47:36 +0000 | [diff] [blame] | 110 | newArgs->AddSeparateArg( A, _core.getOption(core::OPT_target) |
| 111 | , A->getValue()); |
| Michael J. Spencer | 9ff4be2 | 2012-12-08 00:47:36 +0000 | [diff] [blame] | 112 | } else { |
| 113 | assert(!_defaultTargetTriple.empty() && "Got empty target triple!"); |
| 114 | newArgs->AddSeparateArg(nullptr, _core.getOption(core::OPT_target) |
| 115 | , _defaultTargetTriple); |
| 116 | } |
| 117 | |
| 118 | if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_entry)) |
| 119 | newArgs->AddJoinedArg(A, _core.getOption(core::OPT_entry), A->getValue()); |
| 120 | else |
| Michael J. Spencer | 99b99d2 | 2012-12-09 23:56:37 +0000 | [diff] [blame] | 121 | newArgs->AddJoinedArg(nullptr, _core.getOption(core::OPT_entry), |
| 122 | "_start"); |
| Michael J. Spencer | 9ff4be2 | 2012-12-08 00:47:36 +0000 | [diff] [blame] | 123 | |
| 124 | if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_output)) |
| 125 | newArgs->AddJoinedArg(A, _core.getOption(core::OPT_output), |
| 126 | A->getValue()); |
| 127 | else |
| 128 | newArgs->AddJoinedArg(nullptr, _core.getOption(core::OPT_output), |
| 129 | "a.out"); |
| 130 | |
| 131 | if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_relocatable)) |
| 132 | newArgs->AddFlagArg(A, _core.getOption(core::OPT_relocatable)); |
| 133 | |
| Michael J. Spencer | 3825760 | 2012-12-09 23:56:26 +0000 | [diff] [blame] | 134 | if (llvm::opt::Arg *A = |
| 135 | _inputArgs->getLastArg(ld::OPT_OCTOTHORPE_OCTOTHORPE_OCTOTHORPE)) |
| 136 | newArgs->AddFlagArg(A, _core.getOption( |
| 137 | core::OPT_OCTOTHORPE_OCTOTHORPE_OCTOTHORPE)); |
| 138 | |
| Michael J. Spencer | 9ff4be2 | 2012-12-08 00:47:36 +0000 | [diff] [blame] | 139 | // Copy input args. |
| 140 | for (llvm::opt::arg_iterator it = _inputArgs->filtered_begin(ld::OPT_INPUT), |
| 141 | ie = _inputArgs->filtered_end(); |
| 142 | it != ie; ++it) { |
| 143 | newArgs->AddPositionalArg(*it, _core.getOption(core::OPT_INPUT), |
| 144 | (*it)->getValue()); |
| 145 | } |
| 146 | |
| 147 | return std::move(newArgs); |
| 148 | } |
| 149 | |
| 150 | private: |
| 151 | std::unique_ptr<llvm::opt::InputArgList> _inputArgs; |
| 152 | core::CoreOptTable _core; |
| 153 | ld::LDOptTable _opt; |
| 154 | }; |
| 155 | |
| 156 | std::unique_ptr<Driver> Driver::create( Driver::Flavor flavor |
| 157 | , StringRef defaultTargetTriple) { |
| 158 | switch (flavor) { |
| 159 | case Flavor::ld: |
| 160 | return std::unique_ptr<Driver>(new LDDriver(defaultTargetTriple)); |
| 161 | case Flavor::core: |
| 162 | case Flavor::ld64: |
| 163 | case Flavor::link: |
| 164 | case Flavor::invalid: |
| 165 | llvm_unreachable("Unsupported flavor"); |
| 166 | } |
| 167 | } |
| 168 | |
| Michael J. Spencer | 18225e7 | 2013-01-05 00:46:45 +0000 | [diff] [blame] | 169 | std::unique_ptr<llvm::opt::ArgList> |
| 170 | lld::parseCoreArgs(llvm::ArrayRef<const char *> args) { |
| 171 | core::CoreOptTable core; |
| 172 | unsigned missingIndex, missingCount; |
| 173 | std::unique_ptr<llvm::opt::ArgList> list( |
| 174 | core.ParseArgs( args.begin(), args.end(), missingIndex, missingCount)); |
| 175 | |
| 176 | if (missingCount) { |
| 177 | llvm::errs() << "error: missing arg value for '" |
| 178 | << list->getArgString(missingIndex) |
| 179 | << "' expected " << missingCount << " argument(s).\n"; |
| 180 | return std::unique_ptr<llvm::opt::ArgList>(); |
| 181 | } |
| 182 | |
| 183 | return list; |
| 184 | } |
| 185 | |
| Michael J. Spencer | 9ff4be2 | 2012-12-08 00:47:36 +0000 | [diff] [blame] | 186 | LinkerOptions lld::generateOptions(const llvm::opt::ArgList &args) { |
| 187 | LinkerOptions ret; |
| 188 | |
| 189 | for (llvm::opt::arg_iterator it = args.filtered_begin(ld::OPT_INPUT), |
| 190 | ie = args.filtered_end(); |
| 191 | it != ie; ++it) { |
| 192 | ret._input.push_back(LinkerInput((*it)->getValue(), InputKind::Object)); |
| 193 | } |
| 194 | |
| 195 | ret._target = llvm::Triple::normalize(args.getLastArgValue(core::OPT_target)); |
| 196 | ret._outputPath = args.getLastArgValue(core::OPT_output); |
| 197 | ret._entrySymbol = args.getLastArgValue(core::OPT_entry); |
| 198 | ret._relocatable = args.hasArg(core::OPT_relocatable); |
| Michael J. Spencer | 3825760 | 2012-12-09 23:56:26 +0000 | [diff] [blame] | 199 | ret._outputCommands = args.hasArg(core::OPT_OCTOTHORPE_OCTOTHORPE_OCTOTHORPE); |
| Michael J. Spencer | 9ff4be2 | 2012-12-08 00:47:36 +0000 | [diff] [blame] | 200 | |
| 201 | return std::move(ret); |
| 202 | } |