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