blob: 24dc5ecd817e0741d44f1e1b825e9e2e9da3197e [file] [log] [blame]
Josh Gaob5c49632016-11-08 22:21:31 -08001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Driver.h"
18
19#include <err.h>
20#include <string.h>
21
22#include <chrono>
23#include <mutex>
24#include <string>
25#include <thread>
26#include <unordered_map>
27#include <vector>
28
29#include <clang/AST/ASTConsumer.h>
30#include <clang/Basic/Diagnostic.h>
31#include <clang/Basic/TargetInfo.h>
32#include <clang/Driver/Compilation.h>
33#include <clang/Driver/Driver.h>
34#include <clang/Frontend/CompilerInstance.h>
35#include <clang/Frontend/CompilerInvocation.h>
36#include <clang/Frontend/FrontendAction.h>
37#include <clang/Frontend/FrontendActions.h>
38#include <clang/Frontend/TextDiagnosticPrinter.h>
39#include <clang/Frontend/Utils.h>
40#include <clang/FrontendTool/Utils.h>
41#include <llvm/ADT/IntrusiveRefCntPtr.h>
42#include <llvm/ADT/SmallVector.h>
43#include <llvm/ADT/StringRef.h>
Logan Chienaef762a2018-12-04 17:17:51 +080044#include <llvm/Option/Option.h>
Stephen Hines76064772020-09-22 13:37:42 -070045#include <llvm/Support/Host.h>
Logan Chien6c148d12018-11-07 10:35:38 +080046#include <llvm/Support/VirtualFileSystem.h>
Josh Gaob5c49632016-11-08 22:21:31 -080047
48#include "Arch.h"
49#include "DeclarationDatabase.h"
50#include "versioner.h"
51
52using namespace std::chrono_literals;
53using namespace std::string_literals;
54
55using namespace clang;
56
57class VersionerASTConsumer : public clang::ASTConsumer {
58 public:
59 HeaderDatabase* header_database;
60 CompilationType type;
61
62 VersionerASTConsumer(HeaderDatabase* header_database, CompilationType type)
63 : header_database(header_database), type(type) {
64 }
65
Yi Kong358603a2019-03-29 14:25:16 -070066 void HandleTranslationUnit(ASTContext& ctx) override {
Josh Gaob5c49632016-11-08 22:21:31 -080067 header_database->parseAST(type, ctx);
68 }
69};
70
71class VersionerASTAction : public clang::ASTFrontendAction {
72 public:
73 HeaderDatabase* header_database;
74 CompilationType type;
75
76 VersionerASTAction(HeaderDatabase* header_database, CompilationType type)
77 : header_database(header_database), type(type) {
78 }
79
80 std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance&, llvm::StringRef) override {
81 return std::make_unique<VersionerASTConsumer>(header_database, type);
82 }
83};
84
85static IntrusiveRefCntPtr<DiagnosticsEngine> constructDiags() {
86 IntrusiveRefCntPtr<DiagnosticOptions> diag_opts(new DiagnosticOptions());
87 auto diag_printer = std::make_unique<TextDiagnosticPrinter>(llvm::errs(), diag_opts.get());
88 IntrusiveRefCntPtr<DiagnosticIDs> diag_ids(new DiagnosticIDs());
89 IntrusiveRefCntPtr<DiagnosticsEngine> diags(
90 new DiagnosticsEngine(diag_ids.get(), diag_opts.get(), diag_printer.release()));
91 return diags;
92}
93
94// clang's driver is slow compared to the work it performs to compile our headers.
95// Run it once to generate flags for each target, and memoize the results.
96static std::unordered_map<CompilationType, std::vector<std::string>> cc1_flags;
97static const char* filename_placeholder = "__VERSIONER_PLACEHOLDER__";
Logan Chien6c148d12018-11-07 10:35:38 +080098static void generateTargetCC1Flags(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs,
Josh Gao78b8a142016-11-09 01:00:41 -080099 CompilationType type,
Josh Gaob5c49632016-11-08 22:21:31 -0800100 const std::vector<std::string>& include_dirs) {
101 std::vector<std::string> cmd = { "versioner" };
Josh Gaoab25d0b2017-08-10 10:50:33 -0700102 if (type.cpp) {
103 cmd.push_back("-std=gnu++11");
104 cmd.push_back("-x");
105 cmd.push_back("c++");
106 } else {
107 cmd.push_back("-std=gnu11");
108 cmd.push_back("-x");
109 cmd.push_back("c");
110 }
111
Josh Gaob5c49632016-11-08 22:21:31 -0800112 cmd.push_back("-fsyntax-only");
113
114 cmd.push_back("-Wall");
115 cmd.push_back("-Wextra");
Josh Gaod2ab9ff2017-07-28 12:53:36 -0700116 cmd.push_back("-Weverything");
Josh Gaob5c49632016-11-08 22:21:31 -0800117 cmd.push_back("-Werror");
118 cmd.push_back("-Wundef");
119 cmd.push_back("-Wno-unused-macros");
120 cmd.push_back("-Wno-unused-function");
121 cmd.push_back("-Wno-unused-variable");
122 cmd.push_back("-Wno-unknown-attributes");
123 cmd.push_back("-Wno-pragma-once-outside-header");
124
125 cmd.push_back("-target");
126 cmd.push_back(arch_targets[type.arch]);
127
128 cmd.push_back("-DANDROID");
Logan Chiena6bf7f22019-11-27 07:24:42 -0800129 cmd.push_back("-D__BIONIC_VERSIONER=1");
Josh Gaob5c49632016-11-08 22:21:31 -0800130 cmd.push_back("-D__ANDROID_API__="s + std::to_string(type.api_level));
131 cmd.push_back("-D_FORTIFY_SOURCE=2");
132 cmd.push_back("-D_GNU_SOURCE");
133 cmd.push_back("-D_FILE_OFFSET_BITS="s + std::to_string(type.file_offset_bits));
134
135 cmd.push_back("-nostdinc");
136
137 if (add_include) {
Josh Gaob5c49632016-11-08 22:21:31 -0800138 cmd.push_back("-include");
Josh Gao78b8a142016-11-09 01:00:41 -0800139 cmd.push_back("android/versioning.h");
Josh Gaob5c49632016-11-08 22:21:31 -0800140 }
141
142 for (const auto& dir : include_dirs) {
143 cmd.push_back("-isystem");
144 cmd.push_back(dir);
145 }
146
Josh Gaod2ab9ff2017-07-28 12:53:36 -0700147 cmd.push_back("-include");
Josh Gaob5c49632016-11-08 22:21:31 -0800148 cmd.push_back(filename_placeholder);
Josh Gaod2ab9ff2017-07-28 12:53:36 -0700149 cmd.push_back("-");
Josh Gaob5c49632016-11-08 22:21:31 -0800150
151 auto diags = constructDiags();
Yabin Cui1169bf92021-01-07 15:57:26 -0800152 driver::Driver driver("versioner", llvm::sys::getDefaultTargetTriple(), *diags, "versioner", vfs);
Josh Gaob5c49632016-11-08 22:21:31 -0800153 driver.setCheckInputsExist(false);
154
155 llvm::SmallVector<const char*, 32> driver_args;
156 for (const std::string& str : cmd) {
157 driver_args.push_back(str.c_str());
158 }
159
160 std::unique_ptr<driver::Compilation> Compilation(driver.BuildCompilation(driver_args));
161 const driver::JobList& jobs = Compilation->getJobs();
162 if (jobs.size() != 1) {
163 errx(1, "driver returned %zu jobs for %s", jobs.size(), to_string(type).c_str());
164 }
165
166 const driver::Command& driver_cmd = llvm::cast<driver::Command>(*jobs.begin());
Logan Chienaef762a2018-12-04 17:17:51 +0800167 const llvm::opt::ArgStringList& cc_args = driver_cmd.getArguments();
Josh Gaob5c49632016-11-08 22:21:31 -0800168
169 if (cc_args.size() == 0) {
170 errx(1, "driver returned empty command for %s", to_string(type).c_str());
171 }
172
173 std::vector<std::string> result(cc_args.begin(), cc_args.end());
174
175 {
176 static std::mutex cc1_init_mutex;
177 std::unique_lock<std::mutex> lock(cc1_init_mutex);
178 if (cc1_flags.count(type) > 0) {
179 errx(1, "attemped to generate cc1 flags for existing CompilationType %s",
180 to_string(type).c_str());
181 }
182
183 cc1_flags.emplace(std::make_pair(type, std::move(result)));
184 }
185}
186
187static std::vector<const char*> getCC1Command(CompilationType type, const std::string& filename) {
188 const auto& target_flag_it = cc1_flags.find(type);
189 if (target_flag_it == cc1_flags.end()) {
190 errx(1, "failed to find target flags for CompilationType %s", to_string(type).c_str());
191 }
192
193 std::vector<const char*> result;
194 for (const std::string& flag : target_flag_it->second) {
195 if (flag == "-disable-free") {
196 continue;
197 } else if (flag == filename_placeholder) {
198 result.push_back(filename.c_str());
199 } else {
200 result.push_back(flag.c_str());
201 }
202 }
203 return result;
204}
205
Logan Chien6c148d12018-11-07 10:35:38 +0800206void initializeTargetCC1FlagCache(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs,
Josh Gao78b8a142016-11-09 01:00:41 -0800207 const std::set<CompilationType>& types,
Josh Gaob5c49632016-11-08 22:21:31 -0800208 const std::unordered_map<Arch, CompilationRequirements>& reqs) {
209 if (!cc1_flags.empty()) {
210 errx(1, "reinitializing target CC1 flag cache?");
211 }
212
213 auto start = std::chrono::high_resolution_clock::now();
214 std::vector<std::thread> threads;
215 for (const CompilationType type : types) {
Josh Gao78b8a142016-11-09 01:00:41 -0800216 threads.emplace_back([type, &vfs, &reqs]() {
Josh Gaob5c49632016-11-08 22:21:31 -0800217 const auto& arch_req_it = reqs.find(type.arch);
218 if (arch_req_it == reqs.end()) {
219 errx(1, "CompilationRequirement map missing entry for CompilationType %s",
220 to_string(type).c_str());
221 }
222
Josh Gao78b8a142016-11-09 01:00:41 -0800223 generateTargetCC1Flags(vfs, type, arch_req_it->second.dependencies);
Josh Gaob5c49632016-11-08 22:21:31 -0800224 });
225 }
226 for (auto& thread : threads) {
227 thread.join();
228 }
229 auto end = std::chrono::high_resolution_clock::now();
230
231 if (verbose) {
232 auto diff = (end - start) / 1.0ms;
233 printf("Generated compiler flags for %zu targets in %0.2Lfms\n", types.size(), diff);
234 }
235
236 if (cc1_flags.empty()) {
237 errx(1, "failed to initialize target CC1 flag cache");
238 }
239}
240
Logan Chien6c148d12018-11-07 10:35:38 +0800241void compileHeader(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> vfs,
Josh Gao78b8a142016-11-09 01:00:41 -0800242 HeaderDatabase* header_database, CompilationType type,
Josh Gaob5c49632016-11-08 22:21:31 -0800243 const std::string& filename) {
244 auto diags = constructDiags();
245 std::vector<const char*> cc1_flags = getCC1Command(type, filename);
246 auto invocation = std::make_unique<CompilerInvocation>();
Logan Chien1da9f962019-12-05 14:00:44 -0800247 if (!CompilerInvocation::CreateFromArgs(*invocation.get(), cc1_flags, *diags)) {
Josh Gaob5c49632016-11-08 22:21:31 -0800248 errx(1, "failed to create CompilerInvocation");
249 }
250
251 clang::CompilerInstance Compiler;
Yi Kong06be3452017-04-20 14:27:28 -0700252
Yi Kong06be3452017-04-20 14:27:28 -0700253 Compiler.setInvocation(std::move(invocation));
Josh Gaob5c49632016-11-08 22:21:31 -0800254 Compiler.setDiagnostics(diags.get());
Logan Chienc071fe42019-08-27 09:53:53 -0700255 Compiler.createFileManager(vfs);
Josh Gaob5c49632016-11-08 22:21:31 -0800256
257 VersionerASTAction versioner_action(header_database, type);
258 if (!Compiler.ExecuteAction(versioner_action)) {
259 errx(1, "compilation generated warnings or errors");
260 }
261
262 if (diags->getNumWarnings() || diags->hasErrorOccurred()) {
263 errx(1, "compilation generated warnings or errors");
264 }
265}