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 | #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 | "\thttp://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 | static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden, |
87 | cl::sub(*cl::AllSubCommands)); |
88 | |
89 | static cl::opt<std::string> BuildPath("p", cl::desc("Build path"), |
90 | cl::Optional, cl::cat(Category), |
91 | cl::sub(*cl::AllSubCommands)); |
92 | |
93 | static cl::list<std::string> SourcePaths( |
94 | cl::Positional, cl::desc("<source0> [... <sourceN>]"), OccurrencesFlag, |
95 | cl::cat(Category), cl::sub(*cl::AllSubCommands)); |
96 | |
97 | static cl::list<std::string> ArgsAfter( |
98 | "extra-arg", |
99 | cl::desc("Additional argument to append to the compiler command line"), |
100 | cl::cat(Category), cl::sub(*cl::AllSubCommands)); |
101 | |
102 | static cl::list<std::string> ArgsBefore( |
103 | "extra-arg-before", |
104 | cl::desc("Additional argument to prepend to the compiler command line"), |
105 | cl::cat(Category), cl::sub(*cl::AllSubCommands)); |
106 | |
107 | cl::ResetAllOptionOccurrences(); |
108 | |
109 | cl::HideUnrelatedOptions(Category); |
110 | |
111 | std::string ErrorMessage; |
112 | Compilations = |
113 | FixedCompilationDatabase::loadFromCommandLine(argc, argv, ErrorMessage); |
114 | if (!ErrorMessage.empty()) |
115 | ErrorMessage.append("\n"); |
116 | llvm::raw_string_ostream OS(ErrorMessage); |
117 | |
118 | if (!cl::ParseCommandLineOptions(argc, argv, Overview, &OS)) { |
119 | OS.flush(); |
120 | return llvm::make_error<llvm::StringError>("[CommonOptionsParser]: " + |
121 | ErrorMessage, |
122 | llvm::inconvertibleErrorCode()); |
123 | } |
124 | |
125 | cl::PrintOptionValues(); |
126 | |
127 | SourcePathList = SourcePaths; |
128 | if ((OccurrencesFlag == cl::ZeroOrMore || OccurrencesFlag == cl::Optional) && |
129 | SourcePathList.empty()) |
130 | return llvm::Error::success(); |
131 | if (!Compilations) { |
132 | if (!BuildPath.empty()) { |
133 | Compilations = |
134 | CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage); |
135 | } else { |
136 | Compilations = CompilationDatabase::autoDetectFromSource(SourcePaths[0], |
137 | ErrorMessage); |
138 | } |
139 | if (!Compilations) { |
140 | llvm::errs() << "Error while trying to load a compilation database:\n" |
141 | << ErrorMessage << "Running without flags.\n"; |
142 | Compilations.reset( |
143 | new FixedCompilationDatabase(".", std::vector<std::string>())); |
144 | } |
145 | } |
146 | auto AdjustingCompilations = |
147 | llvm::make_unique<ArgumentsAdjustingCompilations>( |
148 | std::move(Compilations)); |
149 | Adjuster = |
150 | getInsertArgumentAdjuster(ArgsBefore, ArgumentInsertPosition::BEGIN); |
151 | Adjuster = combineAdjusters( |
152 | std::move(Adjuster), |
153 | getInsertArgumentAdjuster(ArgsAfter, ArgumentInsertPosition::END)); |
154 | AdjustingCompilations->appendArgumentsAdjuster(Adjuster); |
155 | Compilations = std::move(AdjustingCompilations); |
156 | return llvm::Error::success(); |
157 | } |
158 | |
159 | llvm::Expected<CommonOptionsParser> CommonOptionsParser::create( |
160 | int &argc, const char **argv, llvm::cl::OptionCategory &Category, |
161 | llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) { |
162 | CommonOptionsParser Parser; |
163 | llvm::Error Err = |
164 | Parser.init(argc, argv, Category, OccurrencesFlag, Overview); |
165 | if (Err) |
166 | return std::move(Err); |
167 | return std::move(Parser); |
168 | } |
169 | |
170 | CommonOptionsParser::CommonOptionsParser( |
171 | int &argc, const char **argv, cl::OptionCategory &Category, |
172 | llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) { |
173 | llvm::Error Err = init(argc, argv, Category, OccurrencesFlag, Overview); |
174 | if (Err) { |
175 | llvm::report_fatal_error( |
176 | "CommonOptionsParser: failed to parse command-line arguments. " + |
177 | llvm::toString(std::move(Err))); |
178 | } |
179 | } |
180 | |