1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
|
//===--- CommonOptionsParser.cpp - common options for clang tools ---------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the CommonOptionsParser class used to parse common
// command-line options for clang tools, so that they can be run as separate
// command-line applications with a consistent common interface for handling
// compilation database and input files.
//
// It provides a common subset of command-line options, common algorithm
// for locating a compilation database and source files, and help messages
// for the basic command-line interface.
//
// It creates a CompilationDatabase and reads common command-line options.
//
// This class uses the Clang Tooling infrastructure, see
// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
// for details on setting it up with LLVM source tree.
//
//===----------------------------------------------------------------------===//
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/CommandLine.h"
using namespace clang::tooling;
using namespace llvm;
const char *const CommonOptionsParser::HelpMessage =
"\n"
"-p <build-path> is used to read a compile command database.\n"
"\n"
"\tFor example, it can be a CMake build directory in which a file named\n"
"\tcompile_commands.json exists (use -DCMAKE_EXPORT_COMPILE_COMMANDS=ON\n"
"\tCMake option to get this output). When no build path is specified,\n"
"\ta search for compile_commands.json will be attempted through all\n"
"\tparent paths of the first input file . See:\n"
"\thttp://clang.llvm.org/docs/HowToSetupToolingForLLVM.html for an\n"
"\texample of setting up Clang Tooling on a source tree.\n"
"\n"
"<source0> ... specify the paths of source files. These paths are\n"
"\tlooked up in the compile command database. If the path of a file is\n"
"\tabsolute, it needs to point into CMake's source tree. If the path is\n"
"\trelative, the current working directory needs to be in the CMake\n"
"\tsource tree and the file must be in a subdirectory of the current\n"
"\tworking directory. \"./\" prefixes in the relative files will be\n"
"\tautomatically removed, but the rest of a relative path must be a\n"
"\tsuffix of a path in the compile command database.\n"
"\n";
void ArgumentsAdjustingCompilations::appendArgumentsAdjuster(
ArgumentsAdjuster Adjuster) {
Adjusters.push_back(std::move(Adjuster));
}
std::vector<CompileCommand> ArgumentsAdjustingCompilations::getCompileCommands(
StringRef FilePath) const {
return adjustCommands(Compilations->getCompileCommands(FilePath));
}
std::vector<std::string>
ArgumentsAdjustingCompilations::getAllFiles() const {
return Compilations->getAllFiles();
}
std::vector<CompileCommand>
ArgumentsAdjustingCompilations::getAllCompileCommands() const {
return adjustCommands(Compilations->getAllCompileCommands());
}
std::vector<CompileCommand> ArgumentsAdjustingCompilations::adjustCommands(
std::vector<CompileCommand> Commands) const {
for (CompileCommand &Command : Commands)
for (const auto &Adjuster : Adjusters)
Command.CommandLine = Adjuster(Command.CommandLine, Command.Filename);
return Commands;
}
llvm::Error CommonOptionsParser::init(
int &argc, const char **argv, cl::OptionCategory &Category,
llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) {
static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden,
cl::sub(*cl::AllSubCommands));
static cl::opt<std::string> BuildPath("p", cl::desc("Build path"),
cl::Optional, cl::cat(Category),
cl::sub(*cl::AllSubCommands));
static cl::list<std::string> SourcePaths(
cl::Positional, cl::desc("<source0> [... <sourceN>]"), OccurrencesFlag,
cl::cat(Category), cl::sub(*cl::AllSubCommands));
static cl::list<std::string> ArgsAfter(
"extra-arg",
cl::desc("Additional argument to append to the compiler command line"),
cl::cat(Category), cl::sub(*cl::AllSubCommands));
static cl::list<std::string> ArgsBefore(
"extra-arg-before",
cl::desc("Additional argument to prepend to the compiler command line"),
cl::cat(Category), cl::sub(*cl::AllSubCommands));
cl::ResetAllOptionOccurrences();
cl::HideUnrelatedOptions(Category);
std::string ErrorMessage;
Compilations =
FixedCompilationDatabase::loadFromCommandLine(argc, argv, ErrorMessage);
if (!ErrorMessage.empty())
ErrorMessage.append("\n");
llvm::raw_string_ostream OS(ErrorMessage);
// Stop initializing if command-line option parsing failed.
if (!cl::ParseCommandLineOptions(argc, argv, Overview, &OS)) {
OS.flush();
return llvm::make_error<llvm::StringError>("[CommonOptionsParser]: " +
ErrorMessage,
llvm::inconvertibleErrorCode());
}
cl::PrintOptionValues();
SourcePathList = SourcePaths;
if ((OccurrencesFlag == cl::ZeroOrMore || OccurrencesFlag == cl::Optional) &&
SourcePathList.empty())
return llvm::Error::success();
if (!Compilations) {
if (!BuildPath.empty()) {
Compilations =
CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage);
} else {
Compilations = CompilationDatabase::autoDetectFromSource(SourcePaths[0],
ErrorMessage);
}
if (!Compilations) {
llvm::errs() << "Error while trying to load a compilation database:\n"
<< ErrorMessage << "Running without flags.\n";
Compilations.reset(
new FixedCompilationDatabase(".", std::vector<std::string>()));
}
}
auto AdjustingCompilations =
llvm::make_unique<ArgumentsAdjustingCompilations>(
std::move(Compilations));
Adjuster =
getInsertArgumentAdjuster(ArgsBefore, ArgumentInsertPosition::BEGIN);
Adjuster = combineAdjusters(
std::move(Adjuster),
getInsertArgumentAdjuster(ArgsAfter, ArgumentInsertPosition::END));
AdjustingCompilations->appendArgumentsAdjuster(Adjuster);
Compilations = std::move(AdjustingCompilations);
return llvm::Error::success();
}
llvm::Expected<CommonOptionsParser> CommonOptionsParser::create(
int &argc, const char **argv, llvm::cl::OptionCategory &Category,
llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) {
CommonOptionsParser Parser;
llvm::Error Err =
Parser.init(argc, argv, Category, OccurrencesFlag, Overview);
if (Err)
return std::move(Err);
return std::move(Parser);
}
CommonOptionsParser::CommonOptionsParser(
int &argc, const char **argv, cl::OptionCategory &Category,
llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) {
llvm::Error Err = init(argc, argv, Category, OccurrencesFlag, Overview);
if (Err) {
llvm::report_fatal_error(
"CommonOptionsParser: failed to parse command-line arguments. " +
llvm::toString(std::move(Err)));
}
}
|