forked from OSchip/llvm-project
239 lines
8.1 KiB
C++
239 lines
8.1 KiB
C++
//===- 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/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);
|
|
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);
|
|
|
|
return std::move(ret);
|
|
}
|