mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 03:02:36 +01:00
Add support for response files to the CommandLine library.
llvm-svn: 50355
This commit is contained in:
parent
54791c2a43
commit
4c358b3125
@ -52,6 +52,7 @@
|
||||
specified</a></li>
|
||||
<li><a href="#formatting">Controlling other formatting options</a></li>
|
||||
<li><a href="#misc">Miscellaneous option modifiers</a></li>
|
||||
<li><a href="#response">Response files</a></li>
|
||||
</ul></li>
|
||||
|
||||
<li><a href="#toplevel">Top-Level Classes and Functions</a>
|
||||
@ -1442,6 +1443,29 @@ only makes sense with a <a href="#cl::list">cl::list</a> option.</li>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- _______________________________________________________________________ -->
|
||||
<div class="doc_subsubsection">
|
||||
<a name="response">Response files</a>
|
||||
</div>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<p>Some systems, such as certain variants of Microsoft Windows and
|
||||
some older Unices have a relatively low limit on command-line
|
||||
length. It is therefore customary to use the so-called 'response
|
||||
files' to circumvent this restriction. These files are mentioned on
|
||||
the command-line (using the "@file") syntax. The program reads these
|
||||
files and inserts the contents into argv, thereby working around the
|
||||
command-line length limits. Response files are enabled by an optional
|
||||
fourth argument to
|
||||
<a href="#cl::ParseEnvironmentOptions"><tt>cl::ParseEnvironmentOptions</tt></a>
|
||||
and
|
||||
<a href="#cl::ParseCommandLineOptions"><tt>cl::ParseCommandLineOptions</tt></a>.
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<div class="doc_subsection">
|
||||
<a name="toplevel">Top-Level Classes and Functions</a>
|
||||
@ -1475,7 +1499,8 @@ available.</p>
|
||||
<p>The <tt>cl::ParseCommandLineOptions</tt> function requires two parameters
|
||||
(<tt>argc</tt> and <tt>argv</tt>), but may also take an optional third parameter
|
||||
which holds <a href="#description">additional extra text</a> to emit when the
|
||||
<tt>--help</tt> option is invoked.</p>
|
||||
<tt>--help</tt> option is invoked, and a fourth boolean parameter that enables
|
||||
<a href="#response">response files</a>.</p>
|
||||
|
||||
</div>
|
||||
|
||||
@ -1497,11 +1522,13 @@ like <a
|
||||
href="#cl::ParseCommandLineOptions"><tt>cl::ParseCommandLineOptions</tt></a>
|
||||
does.</p>
|
||||
|
||||
<p>It takes three parameters: the name of the program (since <tt>argv</tt> may
|
||||
<p>It takes four parameters: the name of the program (since <tt>argv</tt> may
|
||||
not be available, it can't just look in <tt>argv[0]</tt>), the name of the
|
||||
environment variable to examine, and the optional
|
||||
environment variable to examine, the optional
|
||||
<a href="#description">additional extra text</a> to emit when the
|
||||
<tt>--help</tt> option is invoked.</p>
|
||||
<tt>--help</tt> option is invoked, and the boolean
|
||||
switch that controls whether <a href="#response">reponse files</a>
|
||||
should be read.</p>
|
||||
|
||||
<p><tt>cl::ParseEnvironmentOptions</tt> will break the environment
|
||||
variable's value up into words and then process them using
|
||||
|
@ -41,14 +41,16 @@ namespace cl {
|
||||
// ParseCommandLineOptions - Command line option processing entry point.
|
||||
//
|
||||
void ParseCommandLineOptions(int argc, char **argv,
|
||||
const char *Overview = 0);
|
||||
const char *Overview = 0,
|
||||
bool ReadResponseFiles = false);
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ParseEnvironmentOptions - Environment variable option processing alternate
|
||||
// entry point.
|
||||
//
|
||||
void ParseEnvironmentOptions(const char *progName, const char *envvar,
|
||||
const char *Overview = 0);
|
||||
const char *Overview = 0,
|
||||
bool ReadResponseFiles = false);
|
||||
|
||||
///===---------------------------------------------------------------------===//
|
||||
/// SetVersionPrinter - Override the default (LLVM specific) version printer
|
||||
@ -146,10 +148,10 @@ class Option {
|
||||
virtual enum ValueExpected getValueExpectedFlagDefault() const {
|
||||
return ValueOptional;
|
||||
}
|
||||
|
||||
|
||||
// Out of line virtual function to provide home for the class.
|
||||
virtual void anchor();
|
||||
|
||||
|
||||
int NumOccurrences; // The number of times specified
|
||||
int Flags; // Flags for the argument
|
||||
unsigned Position; // Position of last occurrence of the option
|
||||
@ -213,7 +215,7 @@ public:
|
||||
// addArgument - Register this argument with the commandline system.
|
||||
//
|
||||
void addArgument();
|
||||
|
||||
|
||||
Option *getNextRegisteredOption() const { return NextRegistered; }
|
||||
|
||||
// Return the width of the option tag for printing...
|
||||
@ -225,7 +227,7 @@ public:
|
||||
virtual void printOptionInfo(unsigned GlobalWidth) const = 0;
|
||||
|
||||
virtual void getExtraOptionNames(std::vector<const char*> &OptionNames) {}
|
||||
|
||||
|
||||
// addOccurrence - Wrapper around handleOccurrence that enforces Flags
|
||||
//
|
||||
bool addOccurrence(unsigned pos, const char *ArgName,
|
||||
@ -339,7 +341,7 @@ public:
|
||||
};
|
||||
|
||||
template<class DataType>
|
||||
ValuesClass<DataType> END_WITH_NULL values(const char *Arg, DataType Val,
|
||||
ValuesClass<DataType> END_WITH_NULL values(const char *Arg, DataType Val,
|
||||
const char *Desc, ...) {
|
||||
va_list ValueArgs;
|
||||
va_start(ValueArgs, Desc);
|
||||
@ -389,7 +391,7 @@ struct generic_parser_base {
|
||||
//
|
||||
hasArgStr = O.hasArgStr();
|
||||
}
|
||||
|
||||
|
||||
void getExtraOptionNames(std::vector<const char*> &OptionNames) {
|
||||
// If there has been no argstr specified, that means that we need to add an
|
||||
// argument for every possible option. This ensures that our options are
|
||||
@ -537,7 +539,7 @@ public:
|
||||
|
||||
// getValueName - Do not print =<value> at all.
|
||||
virtual const char *getValueName() const { return 0; }
|
||||
|
||||
|
||||
// An out-of-line virtual method to provide a 'home' for this class.
|
||||
virtual void anchor();
|
||||
};
|
||||
@ -551,7 +553,7 @@ template<>
|
||||
class parser<boolOrDefault> : public basic_parser<boolOrDefault> {
|
||||
public:
|
||||
// parse - Return true on error.
|
||||
bool parse(Option &O, const char *ArgName, const std::string &Arg,
|
||||
bool parse(Option &O, const char *ArgName, const std::string &Arg,
|
||||
boolOrDefault &Val);
|
||||
|
||||
enum ValueExpected getValueExpectedFlagDefault() const {
|
||||
@ -560,7 +562,7 @@ public:
|
||||
|
||||
// getValueName - Do not print =<value> at all.
|
||||
virtual const char *getValueName() const { return 0; }
|
||||
|
||||
|
||||
// An out-of-line virtual method to provide a 'home' for this class.
|
||||
virtual void anchor();
|
||||
};
|
||||
@ -965,7 +967,7 @@ class list : public Option, public list_storage<DataType, Storage> {
|
||||
virtual void getExtraOptionNames(std::vector<const char*> &OptionNames) {
|
||||
return Parser.getExtraOptionNames(OptionNames);
|
||||
}
|
||||
|
||||
|
||||
virtual bool handleOccurrence(unsigned pos, const char *ArgName,
|
||||
const std::string &Arg) {
|
||||
typename ParserClass::parser_data_type Val =
|
||||
@ -1071,7 +1073,7 @@ public:
|
||||
template<class DataType, class StorageClass>
|
||||
class bits_storage {
|
||||
unsigned *Location; // Where to store the bits...
|
||||
|
||||
|
||||
template<class T>
|
||||
static unsigned Bit(const T &V) {
|
||||
unsigned BitPos = reinterpret_cast<unsigned>(V);
|
||||
@ -1096,9 +1098,9 @@ public:
|
||||
"line option with external storage!");
|
||||
*Location |= Bit(V);
|
||||
}
|
||||
|
||||
|
||||
unsigned getBits() { return *Location; }
|
||||
|
||||
|
||||
template<class T>
|
||||
bool isSet(const T &V) {
|
||||
return (*Location & Bit(V)) != 0;
|
||||
@ -1106,13 +1108,13 @@ public:
|
||||
};
|
||||
|
||||
|
||||
// Define how to hold bits. Since we can inherit from a class, we do so.
|
||||
// Define how to hold bits. Since we can inherit from a class, we do so.
|
||||
// This makes us exactly compatible with the bits in all cases that it is used.
|
||||
//
|
||||
template<class DataType>
|
||||
class bits_storage<DataType, bool> {
|
||||
unsigned Bits; // Where to store the bits...
|
||||
|
||||
|
||||
template<class T>
|
||||
static unsigned Bit(const T &V) {
|
||||
unsigned BitPos = reinterpret_cast<unsigned>(V);
|
||||
@ -1120,15 +1122,15 @@ class bits_storage<DataType, bool> {
|
||||
"enum exceeds width of bit vector!");
|
||||
return 1 << BitPos;
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
template<class T>
|
||||
void addValue(const T &V) {
|
||||
Bits |= Bit(V);
|
||||
}
|
||||
|
||||
|
||||
unsigned getBits() { return Bits; }
|
||||
|
||||
|
||||
template<class T>
|
||||
bool isSet(const T &V) {
|
||||
return (Bits & Bit(V)) != 0;
|
||||
@ -1151,7 +1153,7 @@ class bits : public Option, public bits_storage<DataType, Storage> {
|
||||
virtual void getExtraOptionNames(std::vector<const char*> &OptionNames) {
|
||||
return Parser.getExtraOptionNames(OptionNames);
|
||||
}
|
||||
|
||||
|
||||
virtual bool handleOccurrence(unsigned pos, const char *ArgName,
|
||||
const std::string &Arg) {
|
||||
typename ParserClass::parser_data_type Val =
|
||||
|
@ -17,7 +17,9 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Config/config.h"
|
||||
#include "llvm/ADT/OwningPtr.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/Streams.h"
|
||||
#include "llvm/System/Path.h"
|
||||
@ -87,7 +89,7 @@ static Option *RegisteredOptionList = 0;
|
||||
|
||||
void Option::addArgument() {
|
||||
assert(NextRegistered == 0 && "argument multiply registered!");
|
||||
|
||||
|
||||
NextRegistered = RegisteredOptionList;
|
||||
RegisteredOptionList = this;
|
||||
MarkOptionsChanged();
|
||||
@ -111,7 +113,7 @@ static void GetOptionInfo(std::vector<Option*> &PositionalOpts,
|
||||
O->getExtraOptionNames(OptionNames);
|
||||
if (O->ArgStr[0])
|
||||
OptionNames.push_back(O->ArgStr);
|
||||
|
||||
|
||||
// Handle named options.
|
||||
for (unsigned i = 0, e = OptionNames.size(); i != e; ++i) {
|
||||
// Add argument to the argument map!
|
||||
@ -121,9 +123,9 @@ static void GetOptionInfo(std::vector<Option*> &PositionalOpts,
|
||||
<< OptionNames[0] << "' defined more than once!\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
OptionNames.clear();
|
||||
|
||||
|
||||
// Remember information about positional options.
|
||||
if (O->getFormattingFlag() == cl::Positional)
|
||||
PositionalOpts.push_back(O);
|
||||
@ -135,10 +137,10 @@ static void GetOptionInfo(std::vector<Option*> &PositionalOpts,
|
||||
CAOpt = O;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (CAOpt)
|
||||
PositionalOpts.push_back(CAOpt);
|
||||
|
||||
|
||||
// Make sure that they are in order of registration not backwards.
|
||||
std::reverse(PositionalOpts.begin(), PositionalOpts.end());
|
||||
}
|
||||
@ -150,17 +152,17 @@ static void GetOptionInfo(std::vector<Option*> &PositionalOpts,
|
||||
static Option *LookupOption(const char *&Arg, const char *&Value,
|
||||
std::map<std::string, Option*> &OptionsMap) {
|
||||
while (*Arg == '-') ++Arg; // Eat leading dashes
|
||||
|
||||
|
||||
const char *ArgEnd = Arg;
|
||||
while (*ArgEnd && *ArgEnd != '=')
|
||||
++ArgEnd; // Scan till end of argument name.
|
||||
|
||||
|
||||
if (*ArgEnd == '=') // If we have an equals sign...
|
||||
Value = ArgEnd+1; // Get the value, not the equals
|
||||
|
||||
|
||||
|
||||
|
||||
if (*Arg == 0) return 0;
|
||||
|
||||
|
||||
// Look up the option.
|
||||
std::map<std::string, Option*>::iterator I =
|
||||
OptionsMap.find(std::string(Arg, ArgEnd));
|
||||
@ -309,7 +311,7 @@ static void ParseCStringVector(std::vector<char *> &output,
|
||||
/// an environment variable (whose name is given in ENVVAR).
|
||||
///
|
||||
void cl::ParseEnvironmentOptions(const char *progName, const char *envVar,
|
||||
const char *Overview) {
|
||||
const char *Overview, bool ReadResponseFiles) {
|
||||
// Check args.
|
||||
assert(progName && "Program name not specified");
|
||||
assert(envVar && "Environment variable name missing");
|
||||
@ -328,7 +330,7 @@ void cl::ParseEnvironmentOptions(const char *progName, const char *envVar,
|
||||
// and hand it off to ParseCommandLineOptions().
|
||||
ParseCStringVector(newArgv, envValue);
|
||||
int newArgc = newArgv.size();
|
||||
ParseCommandLineOptions(newArgc, &newArgv[0], Overview);
|
||||
ParseCommandLineOptions(newArgc, &newArgv[0], Overview, ReadResponseFiles);
|
||||
|
||||
// Free all the strdup()ed strings.
|
||||
for (std::vector<char*>::iterator i = newArgv.begin(), e = newArgv.end();
|
||||
@ -336,32 +338,78 @@ void cl::ParseEnvironmentOptions(const char *progName, const char *envVar,
|
||||
free (*i);
|
||||
}
|
||||
|
||||
|
||||
/// ExpandResponseFiles - Copy the contents of argv into newArgv,
|
||||
/// substituting the contents of the response files for the arguments
|
||||
/// of type @file.
|
||||
static void ExpandResponseFiles(int argc, char** argv,
|
||||
std::vector<char*>& newArgv) {
|
||||
for (int i = 1; i != argc; ++i) {
|
||||
char* arg = argv[i];
|
||||
|
||||
if (arg[0] == '@') {
|
||||
|
||||
sys::PathWithStatus respFile(++arg);
|
||||
|
||||
// Check that the response file is not empty (mmap'ing empty
|
||||
// files can be problematic).
|
||||
const sys::FileStatus *FileStat = respFile.getFileStatus();
|
||||
if (!FileStat)
|
||||
continue;
|
||||
if (FileStat->getSize() == 0)
|
||||
continue;
|
||||
|
||||
// Mmap the response file into memory.
|
||||
OwningPtr<MemoryBuffer>
|
||||
respFilePtr(MemoryBuffer::getFile(respFile.c_str()));
|
||||
|
||||
if (respFilePtr == 0)
|
||||
continue;
|
||||
|
||||
ParseCStringVector(newArgv, respFilePtr->getBufferStart());
|
||||
}
|
||||
else {
|
||||
newArgv.push_back(strdup(arg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cl::ParseCommandLineOptions(int argc, char **argv,
|
||||
const char *Overview) {
|
||||
const char *Overview, bool ReadResponseFiles) {
|
||||
// Process all registered options.
|
||||
std::vector<Option*> PositionalOpts;
|
||||
std::vector<Option*> SinkOpts;
|
||||
std::map<std::string, Option*> Opts;
|
||||
GetOptionInfo(PositionalOpts, SinkOpts, Opts);
|
||||
|
||||
|
||||
assert((!Opts.empty() || !PositionalOpts.empty()) &&
|
||||
"No options specified!");
|
||||
|
||||
// Expand response files.
|
||||
std::vector<char*> newArgv;
|
||||
if (ReadResponseFiles) {
|
||||
newArgv.push_back(strdup(argv[0]));
|
||||
ExpandResponseFiles(argc, argv, newArgv);
|
||||
argv = &newArgv[0];
|
||||
argc = newArgv.size();
|
||||
}
|
||||
|
||||
sys::Path progname(argv[0]);
|
||||
|
||||
// Copy the program name into ProgName, making sure not to overflow it.
|
||||
std::string ProgName = sys::Path(argv[0]).getLast();
|
||||
if (ProgName.size() > 79) ProgName.resize(79);
|
||||
strcpy(ProgramName, ProgName.c_str());
|
||||
|
||||
|
||||
ProgramOverview = Overview;
|
||||
bool ErrorParsing = false;
|
||||
|
||||
// Check out the positional arguments to collect information about them.
|
||||
unsigned NumPositionalRequired = 0;
|
||||
|
||||
|
||||
// Determine whether or not there are an unlimited number of positionals
|
||||
bool HasUnlimitedPositionals = false;
|
||||
|
||||
|
||||
Option *ConsumeAfterOpt = 0;
|
||||
if (!PositionalOpts.empty()) {
|
||||
if (PositionalOpts[0]->getNumOccurrencesFlag() == cl::ConsumeAfter) {
|
||||
@ -427,7 +475,7 @@ void cl::ParseCommandLineOptions(int argc, char **argv,
|
||||
GetOptionInfo(PositionalOpts, SinkOpts, Opts);
|
||||
OptionListChanged = false;
|
||||
}
|
||||
|
||||
|
||||
// Check to see if this is a positional argument. This argument is
|
||||
// considered to be positional if it doesn't start with '-', if it is "-"
|
||||
// itself, or if we have seen "--" already.
|
||||
@ -567,7 +615,7 @@ void cl::ParseCommandLineOptions(int argc, char **argv,
|
||||
<< ": Not enough positional command line arguments specified!\n"
|
||||
<< "Must specify at least " << NumPositionalRequired
|
||||
<< " positional arguments: See: " << argv[0] << " --help\n";
|
||||
|
||||
|
||||
ErrorParsing = true;
|
||||
} else if (!HasUnlimitedPositionals
|
||||
&& PositionalVals.size() > PositionalOpts.size()) {
|
||||
@ -664,6 +712,14 @@ void cl::ParseCommandLineOptions(int argc, char **argv,
|
||||
PositionalOpts.clear();
|
||||
MoreHelp->clear();
|
||||
|
||||
// Free the memory allocated by ExpandResponseFiles.
|
||||
if (ReadResponseFiles) {
|
||||
// Free all the strdup()ed strings.
|
||||
for (std::vector<char*>::iterator i = newArgv.begin(), e = newArgv.end();
|
||||
i != e; ++i)
|
||||
free (*i);
|
||||
}
|
||||
|
||||
// If we had an error processing our arguments, don't let the program execute
|
||||
if (ErrorParsing) exit(1);
|
||||
}
|
||||
@ -678,7 +734,7 @@ bool Option::error(std::string Message, const char *ArgName) {
|
||||
cerr << HelpStr; // Be nice for positional arguments
|
||||
else
|
||||
cerr << ProgramName << ": for the -" << ArgName;
|
||||
|
||||
|
||||
cerr << " option: " << Message << "\n";
|
||||
return true;
|
||||
}
|
||||
@ -943,7 +999,7 @@ public:
|
||||
std::vector<Option*> SinkOpts;
|
||||
std::map<std::string, Option*> OptMap;
|
||||
GetOptionInfo(PositionalOpts, SinkOpts, OptMap);
|
||||
|
||||
|
||||
// Copy Options into a vector so we can sort them as we like...
|
||||
std::vector<std::pair<std::string, Option*> > Opts;
|
||||
copy(OptMap.begin(), OptMap.end(), std::back_inserter(Opts));
|
||||
@ -970,7 +1026,7 @@ public:
|
||||
|
||||
// Print out the positional options.
|
||||
Option *CAOpt = 0; // The cl::ConsumeAfter option, if it exists...
|
||||
if (!PositionalOpts.empty() &&
|
||||
if (!PositionalOpts.empty() &&
|
||||
PositionalOpts[0]->getNumOccurrencesFlag() == ConsumeAfter)
|
||||
CAOpt = PositionalOpts[0];
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user