Added *hidden* flags -print-options and -print-all-options so

developers can see if their driver changed any cl::Option's. The
current implementation isn't perfect but handles most kinds of
options. This is nice to have when decomposing the stages of
compilation and moving between different drivers. It's also a good
sanity check when comparing results produced by different command line
invocations that are expected to produce the comparable results.

Note: This is not an attempt to prolong the life of cl::Option. On the
contrary, it's a placeholder for a feature that must exist when
cl::Option is replaced by a more appropriate framework. A new
framework needs: a central option registry, dynamic name lookup,
non-global containers of option values (e.g. per-module,
per-function), *and* the ability to print options values and their defaults at
any point during compilation.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@128910 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Andrew Trick
2011-04-05 18:54:36 +00:00
parent 5dc0c50372
commit ce96902d88
4 changed files with 436 additions and 41 deletions

View File

@ -908,8 +908,6 @@ void alias::printOptionInfo(size_t GlobalWidth) const {
errs().indent(GlobalWidth-L-6) << " - " << HelpStr << "\n";
}
//===----------------------------------------------------------------------===//
// Parser Implementation code...
//
@ -939,7 +937,11 @@ void basic_parser_impl::printOptionInfo(const Option &O,
outs().indent(GlobalWidth-getOptionWidth(O)) << " - " << O.HelpStr << '\n';
}
void basic_parser_impl::printOptionName(const Option &O,
size_t GlobalWidth) const {
outs() << " -" << O.ArgStr;
outs().indent(GlobalWidth-std::strlen(O.ArgStr));
}
// parser<bool> implementation
@ -1083,6 +1085,89 @@ void generic_parser_base::printOptionInfo(const Option &O,
}
}
static const size_t MaxOptWidth = 8; // arbitrary spacing for printOptionDiff
// printGenericOptionDiff - Print the value of this option and it's default.
//
// "Generic" options have each value mapped to a name.
void generic_parser_base::
printGenericOptionDiff(const Option &O, const GenericOptionValue &Value,
const GenericOptionValue &Default,
size_t GlobalWidth) const {
outs() << " -" << O.ArgStr;
outs().indent(GlobalWidth-std::strlen(O.ArgStr));
unsigned NumOpts = getNumOptions();
for (unsigned i = 0; i != NumOpts; ++i) {
if (Value.compare(getOptionValue(i)))
continue;
outs() << "= " << getOption(i);
size_t L = std::strlen(getOption(i));
size_t NumSpaces = MaxOptWidth > L ? MaxOptWidth - L : 0;
outs().indent(NumSpaces) << " (default: ";
for (unsigned j = 0; j != NumOpts; ++j) {
if (Default.compare(getOptionValue(j)))
continue;
outs() << getOption(j);
break;
}
outs() << ")\n";
return;
}
outs() << "= *unknown option value*\n";
}
// printOptionDiff - Specializations for printing basic value types.
//
#define PRINT_OPT_DIFF(T) \
void parser<T>:: \
printOptionDiff(const Option &O, T V, OptionValue<T> D, \
size_t GlobalWidth) const { \
printOptionName(O, GlobalWidth); \
std::string Str; \
{ \
raw_string_ostream SS(Str); \
SS << V; \
} \
outs() << "= " << Str; \
size_t NumSpaces = MaxOptWidth > Str.size() ? MaxOptWidth - Str.size() : 0;\
outs().indent(NumSpaces) << " (default: "; \
if (D.hasValue()) \
outs() << D.getValue(); \
else \
outs() << "*no default*"; \
outs() << ")\n"; \
} \
PRINT_OPT_DIFF(bool);
PRINT_OPT_DIFF(boolOrDefault);
PRINT_OPT_DIFF(int);
PRINT_OPT_DIFF(unsigned);
PRINT_OPT_DIFF(double);
PRINT_OPT_DIFF(float);
PRINT_OPT_DIFF(char);
void parser<std::string>::
printOptionDiff(const Option &O, StringRef V, OptionValue<std::string> D,
size_t GlobalWidth) const {
printOptionName(O, GlobalWidth);
outs() << "= " << V;
size_t NumSpaces = MaxOptWidth > V.size() ? MaxOptWidth - V.size() : 0;
outs().indent(NumSpaces) << " (default: ";
if (D.hasValue())
outs() << D.getValue();
else
outs() << "*no default*";
outs() << ")\n";
}
// Print a placeholder for options that don't yet support printOptionDiff().
void basic_parser_impl::
printOptionNoValue(const Option &O, size_t GlobalWidth) const {
printOptionName(O, GlobalWidth);
outs() << "= *cannot print option value*\n";
}
//===----------------------------------------------------------------------===//
// -help and -help-hidden option implementation
@ -1094,6 +1179,35 @@ static int OptNameCompare(const void *LHS, const void *RHS) {
return strcmp(((pair_ty*)LHS)->first, ((pair_ty*)RHS)->first);
}
// Copy Options into a vector so we can sort them as we like.
static void
sortOpts(StringMap<Option*> &OptMap,
SmallVectorImpl< std::pair<const char *, Option*> > &Opts,
bool ShowHidden) {
SmallPtrSet<Option*, 128> OptionSet; // Duplicate option detection.
for (StringMap<Option*>::iterator I = OptMap.begin(), E = OptMap.end();
I != E; ++I) {
// Ignore really-hidden options.
if (I->second->getOptionHiddenFlag() == ReallyHidden)
continue;
// Unless showhidden is set, ignore hidden flags.
if (I->second->getOptionHiddenFlag() == Hidden && !ShowHidden)
continue;
// If we've already seen this option, don't add it to the list again.
if (!OptionSet.insert(I->second))
continue;
Opts.push_back(std::pair<const char *, Option*>(I->getKey().data(),
I->second));
}
// Sort the options list alphabetically.
qsort(Opts.data(), Opts.size(), sizeof(Opts[0]), OptNameCompare);
}
namespace {
class HelpPrinter {
@ -1115,30 +1229,8 @@ public:
StringMap<Option*> OptMap;
GetOptionInfo(PositionalOpts, SinkOpts, OptMap);
// Copy Options into a vector so we can sort them as we like.
SmallVector<std::pair<const char *, Option*>, 128> Opts;
SmallPtrSet<Option*, 128> OptionSet; // Duplicate option detection.
for (StringMap<Option*>::iterator I = OptMap.begin(), E = OptMap.end();
I != E; ++I) {
// Ignore really-hidden options.
if (I->second->getOptionHiddenFlag() == ReallyHidden)
continue;
// Unless showhidden is set, ignore hidden flags.
if (I->second->getOptionHiddenFlag() == Hidden && !ShowHidden)
continue;
// If we've already seen this option, don't add it to the list again.
if (!OptionSet.insert(I->second))
continue;
Opts.push_back(std::pair<const char *, Option*>(I->getKey().data(),
I->second));
}
// Sort the options list alphabetically.
qsort(Opts.data(), Opts.size(), sizeof(Opts[0]), OptNameCompare);
sortOpts(OptMap, Opts, ShowHidden);
if (ProgramOverview)
outs() << "OVERVIEW: " << ProgramOverview << "\n";
@ -1197,6 +1289,38 @@ static cl::opt<HelpPrinter, true, parser<bool> >
HHOp("help-hidden", cl::desc("Display all available options"),
cl::location(HiddenPrinter), cl::Hidden, cl::ValueDisallowed);
static cl::opt<bool>
PrintOptions("print-options",
cl::desc("Print non-default options after command line parsing"),
cl::Hidden, cl::init(false));
static cl::opt<bool>
PrintAllOptions("print-all-options",
cl::desc("Print all option values after command line parsing"),
cl::Hidden, cl::init(false));
// Print the value of each option.
void cl::PrintOptionValues() {
if (!PrintOptions && !PrintAllOptions) return;
// Get all the options.
SmallVector<Option*, 4> PositionalOpts;
SmallVector<Option*, 4> SinkOpts;
StringMap<Option*> OptMap;
GetOptionInfo(PositionalOpts, SinkOpts, OptMap);
SmallVector<std::pair<const char *, Option*>, 128> Opts;
sortOpts(OptMap, Opts, /*ShowHidden*/true);
// Compute the maximum argument length...
size_t MaxArgLen = 0;
for (size_t i = 0, e = Opts.size(); i != e; ++i)
MaxArgLen = std::max(MaxArgLen, Opts[i].second->getOptionWidth());
for (size_t i = 0, e = Opts.size(); i != e; ++i)
Opts[i].second->printOptionValue(MaxArgLen, PrintAllOptions);
}
static void (*OverrideVersionPrinter)() = 0;
static int TargetArraySortFn(const void *LHS, const void *RHS) {