cling/lib/Interpreter/InvocationOptions.cpp
2016-12-19 13:59:11 +01:00

185 lines
6.3 KiB
C++

//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author: Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------
#include "cling/Interpreter/InvocationOptions.h"
#include "cling/Interpreter/ClingOptions.h"
#include "cling/Utils/Output.h"
#include "clang/Driver/Options.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Option/OptTable.h"
#include <memory>
using namespace clang;
using namespace clang::driver;
using namespace llvm;
using namespace llvm::opt;
using namespace cling;
using namespace cling::driver::clingoptions;
namespace {
#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR)
#include "cling/Interpreter/ClingOptions.inc"
#undef OPTION
#undef PREFIX
static const OptTable::Info ClingInfoTable[] = {
#define PREFIX(NAME, VALUE)
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR) \
{ PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \
FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS },
#include "cling/Interpreter/ClingOptions.inc"
#undef OPTION
#undef PREFIX
};
class ClingOptTable : public OptTable {
public:
ClingOptTable()
: OptTable(ClingInfoTable) {}
};
static OptTable* CreateClingOptTable() {
return new ClingOptTable();
}
static void ParseStartupOpts(cling::InvocationOptions& Opts,
InputArgList& Args) {
Opts.ErrorOut = Args.hasArg(OPT__errorout);
Opts.NoLogo = Args.hasArg(OPT__nologo);
Opts.ShowVersion = Args.hasArg(OPT_version);
Opts.Help = Args.hasArg(OPT_help);
if (Arg* MetaStringArg = Args.getLastArg(OPT__metastr, OPT__metastr_EQ)) {
Opts.MetaString = MetaStringArg->getValue();
if (Opts.MetaString.empty()) {
cling::errs() << "ERROR: meta string must be non-empty! Defaulting to '.'.\n";
Opts.MetaString = ".";
}
}
}
static void Extend(std::vector<std::string>& A, std::vector<std::string> B) {
A.reserve(A.size()+B.size());
for (std::string& Val: B)
A.push_back(std::move(Val));
}
static void ParseLinkerOpts(cling::InvocationOptions& Opts,
InputArgList& Args /* , Diags */) {
Extend(Opts.LibsToLoad, Args.getAllArgValues(OPT_l));
Extend(Opts.LibSearchPath, Args.getAllArgValues(OPT_L));
}
}
CompilerOptions::CompilerOptions(int argc, const char* const* argv) :
Language(false), ResourceDir(false), SysRoot(false), NoBuiltinInc(false),
NoCXXInc(false), StdVersion(false), StdLib(false), Verbose(false) {
if (argc && argv) {
// Preserve what's already in Remaining, the user might want to push args
// to clang while still using main's argc, argv
// insert should/usually does call reserve, but its not part of the standard
Remaining.reserve(Remaining.size() + argc);
Remaining.insert(Remaining.end(), argv, argv+argc);
Parse(argc, argv);
}
}
void CompilerOptions::Parse(int argc, const char* const argv[],
std::vector<std::string>* Inputs) {
unsigned MissingArgIndex, MissingArgCount;
std::unique_ptr<OptTable> OptsC1(createDriverOptTable());
ArrayRef<const char *> ArgStrings(argv+1, argv + argc);
InputArgList Args(OptsC1->ParseArgs(ArgStrings, MissingArgIndex,
MissingArgCount, 0,
options::NoDriverOption | options::CLOption));
for (const Arg* arg : Args) {
switch (arg->getOption().getID()) {
// case options::OPT_d_Flag:
// case options::OPT_E:
// case options::OPT_o: HasOuptut = true; break;
case options::OPT_x: Language = true; break;
case options::OPT_resource_dir: ResourceDir = true; break;
case options::OPT_isysroot: SysRoot = true; break;
case options::OPT_std_EQ: StdVersion = true; break;
case options::OPT_stdlib_EQ: StdLib = true; break;
// case options::OPT_nostdlib:
case options::OPT_nobuiltininc: NoBuiltinInc = true; break;
// case options::OPT_nostdinc:
case options::OPT_nostdincxx: NoCXXInc = true; break;
case options::OPT_v: Verbose = true; break;
default:
if (Inputs && arg->getOption().getKind() == Option::InputClass)
Inputs->push_back(arg->getValue());
break;
}
}
}
InvocationOptions::InvocationOptions(int argc, const char* const* argv) :
MetaString("."), ErrorOut(false), NoLogo(false), ShowVersion(false),
Help(false) {
ArrayRef<const char *> ArgStrings(argv, argv + argc);
unsigned MissingArgIndex, MissingArgCount;
std::unique_ptr<OptTable> Opts(CreateClingOptTable());
InputArgList Args(Opts->ParseArgs(ArgStrings, MissingArgIndex,
MissingArgCount, 0,
options::NoDriverOption | options::CLOption));
// Forward unknown arguments.
for (const Arg* arg : Args) {
switch (arg->getOption().getKind()) {
case Option::FlagClass:
// pass -v to clang as well
if (arg->getOption().getID() != OPT_v)
break;
case Option::UnknownClass:
case Option::InputClass:
// prune "-" we need to control where it appears when invoking clang
if (!arg->getSpelling().equals("-"))
CompilerOpts.Remaining.push_back(argv[arg->getIndex()]);
default:
break;
}
}
// Get Input list and any compiler specific flags we're interested in
CompilerOpts.Parse(argc, argv, &Inputs);
ParseStartupOpts(*this, Args);
ParseLinkerOpts(*this, Args);
}
void InvocationOptions::PrintHelp() {
std::unique_ptr<OptTable> Opts(CreateClingOptTable());
Opts->PrintHelp(cling::outs(), "cling",
"cling: LLVM/clang C++ Interpreter: http://cern.ch/cling");
cling::outs() << "\n\n";
std::unique_ptr<OptTable> OptsC1(createDriverOptTable());
OptsC1->PrintHelp(cling::outs(), "clang -cc1",
"LLVM 'Clang' Compiler: http://clang.llvm.org");
}