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 | |
Chandler Carruth | b5f3bd9 | 2013-01-19 09:57:51 +0000 | [diff] [blame] | 87 | class LDDriver LLVM_FINAL : public Driver { |
Michael J. Spencer | 9ff4be2 | 2012-12-08 00:47:36 +0000 | [diff] [blame] | 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 | |
Michael J. Spencer | 6047163 | 2013-01-08 22:59:27 +0000 | [diff] [blame] | 106 | for (llvm::opt::arg_iterator it = _inputArgs->filtered_begin(ld::OPT_UNKNOWN), |
| 107 | ie = _inputArgs->filtered_end(); |
| 108 | it != ie; ++it) { |
| 109 | llvm::errs() << "warning: ignoring unknown argument: " |
| 110 | << (*it)->getAsString(*_inputArgs) << "\n"; |
| 111 | } |
| 112 | |
Michael J. Spencer | 9ff4be2 | 2012-12-08 00:47:36 +0000 | [diff] [blame] | 113 | std::unique_ptr<llvm::opt::DerivedArgList> newArgs( |
| 114 | new llvm::opt::DerivedArgList(*_inputArgs)); |
| 115 | |
| 116 | if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_target)) { |
Michael J. Spencer | 9ff4be2 | 2012-12-08 00:47:36 +0000 | [diff] [blame] | 117 | newArgs->AddSeparateArg( A, _core.getOption(core::OPT_target) |
| 118 | , A->getValue()); |
Michael J. Spencer | 9ff4be2 | 2012-12-08 00:47:36 +0000 | [diff] [blame] | 119 | } else { |
| 120 | assert(!_defaultTargetTriple.empty() && "Got empty target triple!"); |
| 121 | newArgs->AddSeparateArg(nullptr, _core.getOption(core::OPT_target) |
| 122 | , _defaultTargetTriple); |
| 123 | } |
| 124 | |
| 125 | if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_entry)) |
| 126 | newArgs->AddJoinedArg(A, _core.getOption(core::OPT_entry), A->getValue()); |
| 127 | else |
Michael J. Spencer | 99b99d2 | 2012-12-09 23:56:37 +0000 | [diff] [blame] | 128 | newArgs->AddJoinedArg(nullptr, _core.getOption(core::OPT_entry), |
| 129 | "_start"); |
Michael J. Spencer | 9ff4be2 | 2012-12-08 00:47:36 +0000 | [diff] [blame] | 130 | |
| 131 | if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_output)) |
| 132 | newArgs->AddJoinedArg(A, _core.getOption(core::OPT_output), |
| 133 | A->getValue()); |
| 134 | else |
| 135 | newArgs->AddJoinedArg(nullptr, _core.getOption(core::OPT_output), |
| 136 | "a.out"); |
| 137 | |
| 138 | if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_relocatable)) |
| 139 | newArgs->AddFlagArg(A, _core.getOption(core::OPT_relocatable)); |
| 140 | |
Michael J. Spencer | 3825760 | 2012-12-09 23:56:26 +0000 | [diff] [blame] | 141 | if (llvm::opt::Arg *A = |
| 142 | _inputArgs->getLastArg(ld::OPT_OCTOTHORPE_OCTOTHORPE_OCTOTHORPE)) |
| 143 | newArgs->AddFlagArg(A, _core.getOption( |
| 144 | core::OPT_OCTOTHORPE_OCTOTHORPE_OCTOTHORPE)); |
| 145 | |
Michael J. Spencer | 956b036 | 2013-01-07 08:00:25 +0000 | [diff] [blame] | 146 | if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_emit_yaml)) |
| 147 | newArgs->AddFlagArg(A, _core.getOption(core::OPT_emit_yaml)); |
| 148 | |
Shankar Easwaran | 7381db0 | 2013-01-11 15:11:47 +0000 | [diff] [blame] | 149 | if (llvm::opt::Arg *A = _inputArgs->getLastArg(ld::OPT_noinhibit_exec)) |
| 150 | newArgs->AddFlagArg(A, _core.getOption(core::OPT_noinhibit_exec)); |
| 151 | |
Michael J. Spencer | 9ff4be2 | 2012-12-08 00:47:36 +0000 | [diff] [blame] | 152 | // Copy input args. |
| 153 | for (llvm::opt::arg_iterator it = _inputArgs->filtered_begin(ld::OPT_INPUT), |
| 154 | ie = _inputArgs->filtered_end(); |
| 155 | it != ie; ++it) { |
| 156 | newArgs->AddPositionalArg(*it, _core.getOption(core::OPT_INPUT), |
| 157 | (*it)->getValue()); |
| 158 | } |
| 159 | |
Michael J. Spencer | 6047163 | 2013-01-08 22:59:27 +0000 | [diff] [blame] | 160 | // Copy mllvm |
| 161 | for (llvm::opt::arg_iterator it = _inputArgs->filtered_begin(ld::OPT_mllvm), |
| 162 | ie = _inputArgs->filtered_end(); |
| 163 | it != ie; ++it) { |
| 164 | newArgs->AddPositionalArg(*it, _core.getOption(core::OPT_mllvm), |
| 165 | (*it)->getValue()); |
| 166 | } |
| 167 | |
Michael J. Spencer | 9ff4be2 | 2012-12-08 00:47:36 +0000 | [diff] [blame] | 168 | return std::move(newArgs); |
| 169 | } |
| 170 | |
| 171 | private: |
| 172 | std::unique_ptr<llvm::opt::InputArgList> _inputArgs; |
| 173 | core::CoreOptTable _core; |
| 174 | ld::LDOptTable _opt; |
| 175 | }; |
| 176 | |
| 177 | std::unique_ptr<Driver> Driver::create( Driver::Flavor flavor |
| 178 | , StringRef defaultTargetTriple) { |
| 179 | switch (flavor) { |
| 180 | case Flavor::ld: |
| 181 | return std::unique_ptr<Driver>(new LDDriver(defaultTargetTriple)); |
| 182 | case Flavor::core: |
| 183 | case Flavor::ld64: |
| 184 | case Flavor::link: |
| 185 | case Flavor::invalid: |
| 186 | llvm_unreachable("Unsupported flavor"); |
| 187 | } |
| 188 | } |
| 189 | |
Michael J. Spencer | 18225e7 | 2013-01-05 00:46:45 +0000 | [diff] [blame] | 190 | std::unique_ptr<llvm::opt::ArgList> |
| 191 | lld::parseCoreArgs(llvm::ArrayRef<const char *> args) { |
| 192 | core::CoreOptTable core; |
| 193 | unsigned missingIndex, missingCount; |
| 194 | std::unique_ptr<llvm::opt::ArgList> list( |
| 195 | core.ParseArgs( args.begin(), args.end(), missingIndex, missingCount)); |
| 196 | |
| 197 | if (missingCount) { |
| 198 | llvm::errs() << "error: missing arg value for '" |
| 199 | << list->getArgString(missingIndex) |
| 200 | << "' expected " << missingCount << " argument(s).\n"; |
| 201 | return std::unique_ptr<llvm::opt::ArgList>(); |
| 202 | } |
| 203 | |
Michael J. Spencer | 6047163 | 2013-01-08 22:59:27 +0000 | [diff] [blame] | 204 | bool hasUnknown = false; |
| 205 | for (llvm::opt::arg_iterator it = list->filtered_begin(ld::OPT_UNKNOWN), |
| 206 | ie = list->filtered_end(); |
| 207 | it != ie; ++it) { |
| 208 | llvm::errs() << "error: ignoring unknown argument: " |
| 209 | << (*it)->getAsString(*list) << "\n"; |
| 210 | hasUnknown = true; |
| 211 | } |
| 212 | if (hasUnknown) |
| 213 | return std::unique_ptr<llvm::opt::ArgList>(); |
| 214 | |
Michael J. Spencer | 18225e7 | 2013-01-05 00:46:45 +0000 | [diff] [blame] | 215 | return list; |
| 216 | } |
| 217 | |
Michael J. Spencer | 9ff4be2 | 2012-12-08 00:47:36 +0000 | [diff] [blame] | 218 | LinkerOptions lld::generateOptions(const llvm::opt::ArgList &args) { |
| 219 | LinkerOptions ret; |
| 220 | |
| 221 | for (llvm::opt::arg_iterator it = args.filtered_begin(ld::OPT_INPUT), |
| 222 | ie = args.filtered_end(); |
| 223 | it != ie; ++it) { |
| 224 | ret._input.push_back(LinkerInput((*it)->getValue(), InputKind::Object)); |
| 225 | } |
| 226 | |
Michael J. Spencer | 6047163 | 2013-01-08 22:59:27 +0000 | [diff] [blame] | 227 | ret._llvmArgs = args.getAllArgValues(core::OPT_mllvm); |
Michael J. Spencer | 9ff4be2 | 2012-12-08 00:47:36 +0000 | [diff] [blame] | 228 | ret._target = llvm::Triple::normalize(args.getLastArgValue(core::OPT_target)); |
| 229 | ret._outputPath = args.getLastArgValue(core::OPT_output); |
| 230 | ret._entrySymbol = args.getLastArgValue(core::OPT_entry); |
| 231 | ret._relocatable = args.hasArg(core::OPT_relocatable); |
Michael J. Spencer | 3825760 | 2012-12-09 23:56:26 +0000 | [diff] [blame] | 232 | ret._outputCommands = args.hasArg(core::OPT_OCTOTHORPE_OCTOTHORPE_OCTOTHORPE); |
Michael J. Spencer | 956b036 | 2013-01-07 08:00:25 +0000 | [diff] [blame] | 233 | ret._outputYAML = args.hasArg(core::OPT_emit_yaml); |
Shankar Easwaran | 7381db0 | 2013-01-11 15:11:47 +0000 | [diff] [blame] | 234 | ret._noInhibitExec = args.hasArg(core::OPT_noinhibit_exec); |
Michael J. Spencer | 9ff4be2 | 2012-12-08 00:47:36 +0000 | [diff] [blame] | 235 | |
| 236 | return std::move(ret); |
| 237 | } |