Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interpreter and other classes have been modified for support null args #232

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions include/cling/Interpreter/InvocationOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ namespace cling {
///\param [in] argv - arguments
///\param [out] Inputs - save all arguments that are inputs/files here
///
void Parse(int argc, const char* const argv[],
void Parse(int argc,
const char* const * argv,
std::vector<std::string>* Inputs = nullptr);

///\brief By default clang will try to set up an Interpreter with features
Expand Down Expand Up @@ -72,7 +73,7 @@ namespace cling {

class InvocationOptions {
public:
InvocationOptions(int argc, const char* const argv[]);
InvocationOptions(int argc = 0, const char* const * argv = nullptr);

/// \brief A line starting with this string is assumed to contain a
/// directive for the MetaProcessor. Defaults to "."
Expand Down
13 changes: 10 additions & 3 deletions lib/Interpreter/CIFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -828,7 +828,11 @@ static void stringifyPreprocSetting(PreprocessorOptions& PPOpts,

const size_t argc = COpts.Remaining.size();
const char* const* argv = &COpts.Remaining[0];
std::vector<const char*> argvCompile(argv, argv+1);
std::vector<const char*> argvCompile;
if(argc && argv) {
argvCompile = std::vector<const char*>(argv, argv+1);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be better/needed to have a non-empty default for argvCompile?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for replay, this is a first patch, to permit to use it. I'd like to share ideas on the architectural design to follow.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this repo is just a mirror, consider moving your PR here instead: https://github.com/root-project/root/pulls (subdirectory interpreter/cling). Thanks!


argvCompile.reserve(argc+5);

// Variables for storing the memory of the C-string arguments.
Expand Down Expand Up @@ -910,7 +914,10 @@ static void stringifyPreprocSetting(PreprocessorOptions& PPOpts,
argvCompile.insert(argvCompile.end(), argv+1, argv + argc);

// Add host specific includes, -resource-dir if necessary, and -isysroot
std::string ClingBin = GetExecutablePath(argv[0]);
std::string ClingBin;
if(argv) {
ClingBin = GetExecutablePath(argv[0]);
}
AddHostArguments(ClingBin, argvCompile, LLVMDir, COpts);

// Be explicit about the stdlib on OS X
Expand Down Expand Up @@ -948,7 +955,7 @@ static void stringifyPreprocSetting(PreprocessorOptions& PPOpts,
// COFF format currently needs a few changes in LLVM to function properly.
TheTriple.setObjectFormat(llvm::Triple::COFF);
#endif
clang::driver::Driver Drvr(argv[0], TheTriple.getTriple(), *Diags);
clang::driver::Driver Drvr(ClingBin, TheTriple.getTriple(), *Diags);
//Drvr.setWarnMissingInput(false);
Drvr.setCheckInputsExist(false); // think foo.C(12)
llvm::ArrayRef<const char*>RF(&(argvCompile[0]), argvCompile.size());
Expand Down
196 changes: 116 additions & 80 deletions lib/Interpreter/InvocationOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@

#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Option/OptTable.h"
#include "llvm/Option/Option.h"

#include <memory>

Expand All @@ -40,108 +40,141 @@ namespace {
static const char kNoStdInc[] = "-nostdinc";
#endif

#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE;
#define PREFIX(NAME, VALUE) const char* const NAME[] = VALUE;
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES)
#include "cling/Interpreter/ClingOptions.inc"
#undef OPTION
#undef PREFIX

static const OptTable::Info ClingInfoTable[] = {
static const OptTable::Info ClingInfoTable[] = {
#define PREFIX(NAME, VALUE)
#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \
HELPTEXT, METAVAR, VALUES) \
{ PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \
FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS, VALUES },
HELPTEXT, METAVAR, VALUES) \
{PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, \
PARAM, FLAGS, OPT_##GROUP, OPT_##ALIAS, ALIASARGS, VALUES},
#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);
Opts.NoRuntime = Args.hasArg(OPT_noruntime);
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 = ".";
}
};

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);
Opts.NoRuntime = Args.hasArg(OPT_noruntime);
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 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));
}
static void ParseLinkerOpts(cling::InvocationOptions& Opts,
InputArgList& Args /* , Diags */) {
Extend(Opts.LibsToLoad, Args.getAllArgValues(OPT_l));
Extend(Opts.LibSearchPath, Args.getAllArgValues(OPT_L));
}
} // namespace

CompilerOptions::CompilerOptions(int argc, const char* const* argv)
: Language(false), ResourceDir(false), SysRoot(false), NoBuiltinInc(false),
NoCXXInc(false), StdVersion(false), StdLib(false), HasOutput(false),
Verbose(false), CxxModules(false), CUDA(false) {
: Language(false),
ResourceDir(false),
SysRoot(false),
NoBuiltinInc(false),
NoCXXInc(false),
StdVersion(false),
StdLib(false),
HasOutput(false),
Verbose(false),
CxxModules(false),
CUDA(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);
Remaining.insert(Remaining.end(), argv, argv + argc);
Parse(argc, argv);
}
}

void CompilerOptions::Parse(int argc, const char* const 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));
ArrayRef<const char*> ArgStrings;
if (argc && argv) {
ArgStrings = ArrayRef<const char*>(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: HasOutput = true; break;
case options::OPT_x: Language = true;
CUDA = llvm::StringRef(arg->getValue()) == "cuda";
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_o:
HasOutput = true;
break;
case options::OPT_x:
Language = true;
CUDA = llvm::StringRef(arg->getValue()) == "cuda";
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_nobuiltininc:
NoBuiltinInc = true;
break;
// case options::OPT_nostdinc:
case options::OPT_nostdincxx: NoCXXInc = true; break;
case options::OPT_v: Verbose = true; break;
case options::OPT_fmodules: CxxModules = true; break;
case options::OPT_fmodule_name_EQ: LLVM_FALLTHROUGH;
case options::OPT_fmodule_name: ModuleName = arg->getValue(); break;
case options::OPT_fmodules_cache_path: CachePath = arg->getValue(); break;
case options::OPT_nostdincxx:
NoCXXInc = true;
break;
case options::OPT_v:
Verbose = true;
break;
case options::OPT_fmodules:
CxxModules = true;
break;
case options::OPT_fmodule_name_EQ:
LLVM_FALLTHROUGH;
case options::OPT_fmodule_name:
ModuleName = arg->getValue();
break;
case options::OPT_fmodules_cache_path:
CachePath = arg->getValue();
break;

default:
if (Inputs && arg->getOption().getKind() == Option::InputClass)
Expand All @@ -154,8 +187,7 @@ void CompilerOptions::Parse(int argc, const char* const argv[],
bool CompilerOptions::DefaultLanguage(const LangOptions* LangOpts) const {
// When StdVersion is set (-std=c++11, -std=gnu++11, etc.) then definitely
// don't setup the defaults, as they may interfere with what the user is doing
if (StdVersion)
return false;
if (StdVersion) return false;

// Also don't set up the defaults when language is explicitly set; unless
// the language was set to generate a PCH, in which case definitely do.
Expand All @@ -165,33 +197,38 @@ bool CompilerOptions::DefaultLanguage(const LangOptions* LangOpts) const {
return true;
}

InvocationOptions::InvocationOptions(int argc, const char* const* argv) :
MetaString("."), ErrorOut(false), NoLogo(false), ShowVersion(false),
Help(false), NoRuntime(false) {

ArrayRef<const char *> ArgStrings(argv, argv + argc);
InvocationOptions::InvocationOptions(int argc, const char* const* argv)
: MetaString("."),
ErrorOut(false),
NoLogo(false),
ShowVersion(false),
Help(false),
NoRuntime(false) {
ArrayRef<const char*> ArgStrings;
if (argc && argv) {
// fill with arguments
ArgStrings = ArrayRef<const char*>(argv, argv + argc);
}
unsigned MissingArgIndex, MissingArgCount;
std::unique_ptr<OptTable> Opts(CreateClingOptTable());

InputArgList Args(Opts->ParseArgs(ArgStrings, MissingArgIndex,
MissingArgCount, 0,
options::NoDriverOption | options::CLOption));
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;
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("-")) {
if (const char* Arg = argv[arg->getIndex()]) {
#ifdef CLING_TRANSLATE_NOSTDINCxx
if (!::strcmp(Arg, "-nostdinc++"))
Arg = kNoStdInc;
if (!::strcmp(Arg, "-nostdinc++")) Arg = kNoStdInc;
#endif
CompilerOpts.Remaining.push_back(Arg);
}
Expand All @@ -203,7 +240,6 @@ InvocationOptions::InvocationOptions(int argc, const char* const* argv) :

// Get Input list and any compiler specific flags we're interested in
CompilerOpts.Parse(argc, argv, &Inputs);

ParseStartupOpts(*this, Args);
ParseLinkerOpts(*this, Args);
}
Expand Down