| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 1 | /* | 
| Elliott Hughes | dfb74c5 | 2016-10-24 12:53:17 -0700 | [diff] [blame] | 2 | * Copyright (C) 2016 The Android Open Source Project | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 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 | * | 
| Elliott Hughes | dfb74c5 | 2016-10-24 12:53:17 -0700 | [diff] [blame] | 8 | *      http://www.apache.org/licenses/LICENSE-2.0 | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 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 <dirent.h> | 
|  | 18 | #include <err.h> | 
|  | 19 | #include <limits.h> | 
|  | 20 | #include <stdio.h> | 
| Josh Gao | d2ab9ff | 2017-07-28 12:53:36 -0700 | [diff] [blame] | 21 | #include <stdlib.h> | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 22 | #include <sys/stat.h> | 
|  | 23 | #include <sys/types.h> | 
|  | 24 | #include <unistd.h> | 
|  | 25 |  | 
| Josh Gao | 338cf12 | 2016-11-09 18:01:41 -0800 | [diff] [blame] | 26 | #if defined(__linux__) | 
|  | 27 | #include <sched.h> | 
|  | 28 | #endif | 
|  | 29 |  | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 30 | #include <atomic> | 
| Josh Gao | 338cf12 | 2016-11-09 18:01:41 -0800 | [diff] [blame] | 31 | #include <chrono> | 
| Josh Gao | 16016df | 2016-11-07 18:27:16 -0800 | [diff] [blame] | 32 | #include <functional> | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 33 | #include <iostream> | 
|  | 34 | #include <map> | 
|  | 35 | #include <memory> | 
|  | 36 | #include <set> | 
|  | 37 | #include <sstream> | 
|  | 38 | #include <string> | 
|  | 39 | #include <thread> | 
|  | 40 | #include <unordered_map> | 
|  | 41 | #include <vector> | 
|  | 42 |  | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 43 | #include <llvm/ADT/StringRef.h> | 
|  | 44 |  | 
| Josh Gao | b50b8c8 | 2017-04-27 17:22:52 -0700 | [diff] [blame] | 45 | #include <android-base/file.h> | 
| Josh Gao | 338cf12 | 2016-11-09 18:01:41 -0800 | [diff] [blame] | 46 | #include <android-base/macros.h> | 
| Josh Gao | 16016df | 2016-11-07 18:27:16 -0800 | [diff] [blame] | 47 | #include <android-base/parseint.h> | 
|  | 48 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 49 | #include "Arch.h" | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 50 | #include "DeclarationDatabase.h" | 
| Josh Gao | b5c4963 | 2016-11-08 22:21:31 -0800 | [diff] [blame] | 51 | #include "Driver.h" | 
| Josh Gao | f8592a3 | 2016-07-26 18:58:27 -0700 | [diff] [blame] | 52 | #include "Preprocessor.h" | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 53 | #include "SymbolDatabase.h" | 
|  | 54 | #include "Utils.h" | 
| Josh Gao | 78b8a14 | 2016-11-09 01:00:41 -0800 | [diff] [blame] | 55 | #include "VFS.h" | 
|  | 56 |  | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 57 | #include "versioner.h" | 
|  | 58 |  | 
| Josh Gao | 338cf12 | 2016-11-09 18:01:41 -0800 | [diff] [blame] | 59 | using namespace std::chrono_literals; | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 60 | using namespace std::string_literals; | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 61 |  | 
| Josh Gao | acc3d80 | 2016-11-09 18:22:44 -0800 | [diff] [blame] | 62 | bool strict; | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 63 | bool verbose; | 
| Josh Gao | acc3d80 | 2016-11-09 18:22:44 -0800 | [diff] [blame] | 64 | bool add_include; | 
| Josh Gao | 338cf12 | 2016-11-09 18:01:41 -0800 | [diff] [blame] | 65 |  | 
|  | 66 | static int getCpuCount(); | 
|  | 67 | static int max_thread_count = getCpuCount(); | 
|  | 68 |  | 
|  | 69 | static int getCpuCount() { | 
|  | 70 | #if defined(__linux__) | 
|  | 71 | cpu_set_t cpu_set; | 
|  | 72 | int rc = sched_getaffinity(getpid(), sizeof(cpu_set), &cpu_set); | 
|  | 73 | if (rc != 0) { | 
|  | 74 | err(1, "sched_getaffinity failed"); | 
|  | 75 | } | 
|  | 76 | return CPU_COUNT(&cpu_set); | 
|  | 77 | #else | 
|  | 78 | return 1; | 
|  | 79 | #endif | 
|  | 80 | } | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 81 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 82 | static CompilationRequirements collectRequirements(const Arch& arch, const std::string& header_dir, | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 83 | const std::string& dependency_dir) { | 
| Josh Gao | 3091f5a | 2016-11-16 17:01:57 -0800 | [diff] [blame] | 84 | std::vector<std::string> headers = collectHeaders(header_dir); | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 85 | std::vector<std::string> dependencies = { header_dir }; | 
|  | 86 | if (!dependency_dir.empty()) { | 
| Yi Kong | ff6c8de | 2017-04-20 09:08:11 -0700 | [diff] [blame] | 87 | auto collect_children = [&dependencies](const std::string& dir_path) { | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 88 | DIR* dir = opendir(dir_path.c_str()); | 
|  | 89 | if (!dir) { | 
|  | 90 | err(1, "failed to open dependency directory '%s'", dir_path.c_str()); | 
|  | 91 | } | 
|  | 92 |  | 
|  | 93 | struct dirent* dent; | 
|  | 94 | while ((dent = readdir(dir))) { | 
|  | 95 | if (dent->d_name[0] == '.') { | 
|  | 96 | continue; | 
|  | 97 | } | 
|  | 98 |  | 
|  | 99 | // TODO: Resolve symlinks. | 
|  | 100 | std::string dependency = dir_path + "/" + dent->d_name; | 
|  | 101 |  | 
|  | 102 | struct stat st; | 
|  | 103 | if (stat(dependency.c_str(), &st) != 0) { | 
|  | 104 | err(1, "failed to stat dependency '%s'", dependency.c_str()); | 
|  | 105 | } | 
|  | 106 |  | 
|  | 107 | if (!S_ISDIR(st.st_mode)) { | 
|  | 108 | errx(1, "'%s' is not a directory", dependency.c_str()); | 
|  | 109 | } | 
|  | 110 |  | 
|  | 111 | dependencies.push_back(dependency); | 
|  | 112 | } | 
|  | 113 |  | 
|  | 114 | closedir(dir); | 
|  | 115 | }; | 
|  | 116 |  | 
|  | 117 | collect_children(dependency_dir + "/common"); | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 118 | collect_children(dependency_dir + "/" + to_string(arch)); | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 119 | } | 
|  | 120 |  | 
|  | 121 | auto new_end = std::remove_if(headers.begin(), headers.end(), [&arch](llvm::StringRef header) { | 
|  | 122 | for (const auto& it : header_blacklist) { | 
|  | 123 | if (it.second.find(arch) == it.second.end()) { | 
|  | 124 | continue; | 
|  | 125 | } | 
|  | 126 |  | 
|  | 127 | if (header.endswith("/" + it.first)) { | 
|  | 128 | return true; | 
|  | 129 | } | 
|  | 130 | } | 
|  | 131 | return false; | 
|  | 132 | }); | 
|  | 133 |  | 
|  | 134 | headers.erase(new_end, headers.end()); | 
|  | 135 |  | 
|  | 136 | CompilationRequirements result = { .headers = headers, .dependencies = dependencies }; | 
|  | 137 | return result; | 
|  | 138 | } | 
|  | 139 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 140 | static std::set<CompilationType> generateCompilationTypes(const std::set<Arch> selected_architectures, | 
|  | 141 | const std::set<int>& selected_levels) { | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 142 | std::set<CompilationType> result; | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 143 | for (const auto& arch : selected_architectures) { | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 144 | int min_api = arch_min_api[arch]; | 
|  | 145 | for (int api_level : selected_levels) { | 
|  | 146 | if (api_level < min_api) { | 
|  | 147 | continue; | 
|  | 148 | } | 
| Josh Gao | a77b3a9 | 2016-08-15 16:39:27 -0700 | [diff] [blame] | 149 |  | 
|  | 150 | for (int file_offset_bits : { 32, 64 }) { | 
|  | 151 | CompilationType type = { | 
|  | 152 | .arch = arch, .api_level = api_level, .file_offset_bits = file_offset_bits | 
|  | 153 | }; | 
|  | 154 | result.insert(type); | 
|  | 155 | } | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 156 | } | 
|  | 157 | } | 
|  | 158 | return result; | 
|  | 159 | } | 
|  | 160 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 161 | static std::unique_ptr<HeaderDatabase> compileHeaders(const std::set<CompilationType>& types, | 
|  | 162 | const std::string& header_dir, | 
| Josh Gao | 16016df | 2016-11-07 18:27:16 -0800 | [diff] [blame] | 163 | const std::string& dependency_dir) { | 
|  | 164 | if (types.empty()) { | 
|  | 165 | errx(1, "compileHeaders received no CompilationTypes"); | 
|  | 166 | } | 
|  | 167 |  | 
| Josh Gao | 78b8a14 | 2016-11-09 01:00:41 -0800 | [diff] [blame] | 168 | auto vfs = createCommonVFS(header_dir, dependency_dir, add_include); | 
|  | 169 |  | 
| Josh Gao | 16016df | 2016-11-07 18:27:16 -0800 | [diff] [blame] | 170 | size_t thread_count = max_thread_count; | 
|  | 171 | std::vector<std::thread> threads; | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 172 |  | 
|  | 173 | std::map<CompilationType, HeaderDatabase> header_databases; | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 174 | std::unordered_map<Arch, CompilationRequirements> requirements; | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 175 |  | 
| Josh Gao | 16016df | 2016-11-07 18:27:16 -0800 | [diff] [blame] | 176 | auto result = std::make_unique<HeaderDatabase>(); | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 177 | for (const auto& type : types) { | 
|  | 178 | if (requirements.count(type.arch) == 0) { | 
|  | 179 | requirements[type.arch] = collectRequirements(type.arch, header_dir, dependency_dir); | 
|  | 180 | } | 
|  | 181 | } | 
|  | 182 |  | 
| Josh Gao | 78b8a14 | 2016-11-09 01:00:41 -0800 | [diff] [blame] | 183 | initializeTargetCC1FlagCache(vfs, types, requirements); | 
| Josh Gao | b5c4963 | 2016-11-08 22:21:31 -0800 | [diff] [blame] | 184 |  | 
|  | 185 | std::vector<std::pair<CompilationType, const std::string&>> jobs; | 
| Josh Gao | 338cf12 | 2016-11-09 18:01:41 -0800 | [diff] [blame] | 186 | std::atomic<size_t> job_index(0); | 
| Josh Gao | 16016df | 2016-11-07 18:27:16 -0800 | [diff] [blame] | 187 | for (CompilationType type : types) { | 
|  | 188 | CompilationRequirements& req = requirements[type.arch]; | 
|  | 189 | for (const std::string& header : req.headers) { | 
| Josh Gao | b5c4963 | 2016-11-08 22:21:31 -0800 | [diff] [blame] | 190 | jobs.emplace_back(type, header); | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 191 | } | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 192 | } | 
|  | 193 |  | 
| Josh Gao | d2ab9ff | 2017-07-28 12:53:36 -0700 | [diff] [blame] | 194 | // Dup an empty file to stdin, so that we can use `clang -include a.h -` instead of `clang a.h`, | 
|  | 195 | // since some warnings don't get generated in files that are compiled directly. | 
|  | 196 | FILE* empty_file = tmpfile(); | 
|  | 197 | if (!empty_file) { | 
|  | 198 | err(1, "failed to create temporary file"); | 
|  | 199 | } | 
|  | 200 |  | 
|  | 201 | int empty_file_fd = fileno(empty_file); | 
|  | 202 | if (empty_file_fd == -1) { | 
|  | 203 | errx(1, "fileno failed on tmpfile"); | 
|  | 204 | } | 
|  | 205 |  | 
|  | 206 | dup2(empty_file_fd, STDIN_FILENO); | 
|  | 207 | fclose(empty_file); | 
|  | 208 |  | 
| Josh Gao | b5c4963 | 2016-11-08 22:21:31 -0800 | [diff] [blame] | 209 | thread_count = std::min(thread_count, jobs.size()); | 
|  | 210 |  | 
|  | 211 | if (thread_count == 1) { | 
|  | 212 | for (const auto& job : jobs) { | 
| Josh Gao | 78b8a14 | 2016-11-09 01:00:41 -0800 | [diff] [blame] | 213 | compileHeader(vfs, result.get(), job.first, job.second); | 
| Josh Gao | b5c4963 | 2016-11-08 22:21:31 -0800 | [diff] [blame] | 214 | } | 
|  | 215 | } else { | 
|  | 216 | // Spawn threads. | 
|  | 217 | for (size_t i = 0; i < thread_count; ++i) { | 
| Yi Kong | ff6c8de | 2017-04-20 09:08:11 -0700 | [diff] [blame] | 218 | threads.emplace_back([&jobs, &job_index, &result, vfs]() { | 
| Josh Gao | 338cf12 | 2016-11-09 18:01:41 -0800 | [diff] [blame] | 219 | while (true) { | 
|  | 220 | size_t idx = job_index++; | 
|  | 221 | if (idx >= jobs.size()) { | 
|  | 222 | return; | 
|  | 223 | } | 
|  | 224 |  | 
|  | 225 | const auto& job = jobs[idx]; | 
| Josh Gao | 78b8a14 | 2016-11-09 01:00:41 -0800 | [diff] [blame] | 226 | compileHeader(vfs, result.get(), job.first, job.second); | 
| Josh Gao | b5c4963 | 2016-11-08 22:21:31 -0800 | [diff] [blame] | 227 | } | 
|  | 228 | }); | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 229 | } | 
|  | 230 |  | 
| Josh Gao | b5c4963 | 2016-11-08 22:21:31 -0800 | [diff] [blame] | 231 | // Reap them. | 
|  | 232 | for (auto& thread : threads) { | 
|  | 233 | thread.join(); | 
|  | 234 | } | 
|  | 235 | threads.clear(); | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 236 | } | 
|  | 237 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 238 | return result; | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 239 | } | 
|  | 240 |  | 
| Josh Gao | 1a176de | 2016-11-04 13:15:11 -0700 | [diff] [blame] | 241 | static std::set<CompilationType> getCompilationTypes(const Declaration* decl) { | 
|  | 242 | std::set<CompilationType> result; | 
|  | 243 | for (const auto& it : decl->availability) { | 
|  | 244 | result.insert(it.first); | 
|  | 245 | } | 
|  | 246 | return result; | 
|  | 247 | } | 
|  | 248 |  | 
|  | 249 | template<typename T> | 
|  | 250 | static std::vector<T> Intersection(const std::set<T>& a, const std::set<T>& b) { | 
|  | 251 | std::vector<T> intersection; | 
|  | 252 | std::set_intersection(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(intersection)); | 
|  | 253 | return intersection; | 
|  | 254 | } | 
|  | 255 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 256 | // Perform a sanity check on a symbol's declarations, enforcing the following invariants: | 
|  | 257 | //   1. At most one inline definition of the function exists. | 
|  | 258 | //   2. All of the availability declarations for a symbol are compatible. | 
|  | 259 | //      If a function is declared as an inline before a certain version, the inline definition | 
|  | 260 | //      should have no version tag. | 
|  | 261 | //   3. Each availability type must only be present globally or on a per-arch basis. | 
|  | 262 | //      (e.g. __INTRODUCED_IN_ARM(9) __INTRODUCED_IN_X86(10) __DEPRECATED_IN(11) is fine, | 
|  | 263 | //      but not __INTRODUCED_IN(9) __INTRODUCED_IN_X86(10)) | 
|  | 264 | static bool checkSymbol(const Symbol& symbol) { | 
|  | 265 | std::string cwd = getWorkingDir() + "/"; | 
|  | 266 |  | 
| Josh Gao | 1a176de | 2016-11-04 13:15:11 -0700 | [diff] [blame] | 267 | std::unordered_map<const Declaration*, std::set<CompilationType>> inline_definitions; | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 268 | for (const auto& decl_it : symbol.declarations) { | 
|  | 269 | const Declaration* decl = &decl_it.second; | 
|  | 270 | if (decl->is_definition) { | 
| Josh Gao | 1a176de | 2016-11-04 13:15:11 -0700 | [diff] [blame] | 271 | std::set<CompilationType> compilation_types = getCompilationTypes(decl); | 
|  | 272 | for (const auto& inline_def_it : inline_definitions) { | 
|  | 273 | auto intersection = Intersection(compilation_types, inline_def_it.second); | 
|  | 274 | if (!intersection.empty()) { | 
|  | 275 | fprintf(stderr, "versioner: conflicting inline definitions:\n"); | 
|  | 276 | fprintf(stderr, "  declarations visible in: %s\n", Join(intersection, ", ").c_str()); | 
|  | 277 | decl->dump(cwd, stderr, 4); | 
|  | 278 | inline_def_it.first->dump(cwd, stderr, 4); | 
|  | 279 | return false; | 
|  | 280 | } | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 281 | } | 
|  | 282 |  | 
| Josh Gao | 1a176de | 2016-11-04 13:15:11 -0700 | [diff] [blame] | 283 | inline_definitions[decl] = std::move(compilation_types); | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 284 | } | 
|  | 285 |  | 
|  | 286 | DeclarationAvailability availability; | 
|  | 287 | if (!decl->calculateAvailability(&availability)) { | 
|  | 288 | fprintf(stderr, "versioner: failed to calculate availability for declaration:\n"); | 
| Josh Gao | 566735d | 2016-08-02 15:07:32 -0700 | [diff] [blame] | 289 | decl->dump(cwd, stderr, 2); | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 290 | return false; | 
|  | 291 | } | 
|  | 292 |  | 
|  | 293 | if (decl->is_definition && !availability.empty()) { | 
|  | 294 | fprintf(stderr, "versioner: inline definition has non-empty versioning information:\n"); | 
| Josh Gao | 566735d | 2016-08-02 15:07:32 -0700 | [diff] [blame] | 295 | decl->dump(cwd, stderr, 2); | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 296 | return false; | 
|  | 297 | } | 
|  | 298 | } | 
|  | 299 |  | 
|  | 300 | DeclarationAvailability availability; | 
|  | 301 | if (!symbol.calculateAvailability(&availability)) { | 
|  | 302 | fprintf(stderr, "versioner: inconsistent availability for symbol '%s'\n", symbol.name.c_str()); | 
|  | 303 | symbol.dump(cwd); | 
|  | 304 | return false; | 
|  | 305 | } | 
|  | 306 |  | 
|  | 307 | // TODO: Check invariant #3. | 
|  | 308 | return true; | 
|  | 309 | } | 
|  | 310 |  | 
|  | 311 | static bool sanityCheck(const HeaderDatabase* database) { | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 312 | bool error = false; | 
| Josh Gao | 958f3b3 | 2016-06-03 13:44:00 -0700 | [diff] [blame] | 313 | std::string cwd = getWorkingDir() + "/"; | 
|  | 314 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 315 | for (const auto& symbol_it : database->symbols) { | 
|  | 316 | if (!checkSymbol(symbol_it.second)) { | 
|  | 317 | error = true; | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 318 | } | 
|  | 319 | } | 
|  | 320 | return !error; | 
|  | 321 | } | 
|  | 322 |  | 
|  | 323 | // Check that our symbol availability declarations match the actual NDK | 
|  | 324 | // platform symbol availability. | 
|  | 325 | static bool checkVersions(const std::set<CompilationType>& types, | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 326 | const HeaderDatabase* header_database, | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 327 | const NdkSymbolDatabase& symbol_database) { | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 328 | std::string cwd = getWorkingDir() + "/"; | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 329 | bool failed = false; | 
|  | 330 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 331 | std::map<Arch, std::set<CompilationType>> arch_types; | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 332 | for (const CompilationType& type : types) { | 
|  | 333 | arch_types[type.arch].insert(type); | 
|  | 334 | } | 
|  | 335 |  | 
| Josh Gao | d67dbf0 | 2016-06-02 15:21:14 -0700 | [diff] [blame] | 336 | std::set<std::string> completely_unavailable; | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 337 | std::map<std::string, std::set<CompilationType>> missing_availability; | 
|  | 338 | std::map<std::string, std::set<CompilationType>> extra_availability; | 
| Josh Gao | d67dbf0 | 2016-06-02 15:21:14 -0700 | [diff] [blame] | 339 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 340 | for (const auto& symbol_it : header_database->symbols) { | 
|  | 341 | const auto& symbol_name = symbol_it.first; | 
|  | 342 | DeclarationAvailability symbol_availability; | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 343 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 344 | if (!symbol_it.second.calculateAvailability(&symbol_availability)) { | 
|  | 345 | errx(1, "failed to calculate symbol availability"); | 
|  | 346 | } | 
|  | 347 |  | 
|  | 348 | const auto platform_availability_it = symbol_database.find(symbol_name); | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 349 | if (platform_availability_it == symbol_database.end()) { | 
| Josh Gao | d67dbf0 | 2016-06-02 15:21:14 -0700 | [diff] [blame] | 350 | completely_unavailable.insert(symbol_name); | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 351 | continue; | 
|  | 352 | } | 
|  | 353 |  | 
|  | 354 | const auto& platform_availability = platform_availability_it->second; | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 355 |  | 
|  | 356 | for (const CompilationType& type : types) { | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 357 | bool should_be_available = true; | 
|  | 358 | const auto& global_availability = symbol_availability.global_availability; | 
|  | 359 | const auto& arch_availability = symbol_availability.arch_availability[type.arch]; | 
|  | 360 | if (global_availability.introduced != 0 && global_availability.introduced > type.api_level) { | 
|  | 361 | should_be_available = false; | 
|  | 362 | } | 
|  | 363 |  | 
|  | 364 | if (arch_availability.introduced != 0 && arch_availability.introduced > type.api_level) { | 
|  | 365 | should_be_available = false; | 
|  | 366 | } | 
|  | 367 |  | 
|  | 368 | if (global_availability.obsoleted != 0 && global_availability.obsoleted <= type.api_level) { | 
|  | 369 | should_be_available = false; | 
|  | 370 | } | 
|  | 371 |  | 
|  | 372 | if (arch_availability.obsoleted != 0 && arch_availability.obsoleted <= type.api_level) { | 
|  | 373 | should_be_available = false; | 
|  | 374 | } | 
|  | 375 |  | 
|  | 376 | if (arch_availability.future) { | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 377 | continue; | 
|  | 378 | } | 
|  | 379 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 380 | // The function declaration might be (validly) missing for the given CompilationType. | 
|  | 381 | if (!symbol_it.second.hasDeclaration(type)) { | 
|  | 382 | should_be_available = false; | 
|  | 383 | } | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 384 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 385 | bool is_available = platform_availability.count(type); | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 386 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 387 | if (should_be_available != is_available) { | 
|  | 388 | if (is_available) { | 
|  | 389 | extra_availability[symbol_name].insert(type); | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 390 | } else { | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 391 | missing_availability[symbol_name].insert(type); | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 392 | } | 
|  | 393 | } | 
|  | 394 | } | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 395 | } | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 396 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 397 | for (const auto& it : symbol_database) { | 
|  | 398 | const std::string& symbol_name = it.first; | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 399 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 400 | bool symbol_error = false; | 
| Josh Gao | 0a284f5 | 2016-12-15 13:56:00 -0800 | [diff] [blame] | 401 | if (auto missing_it = missing_availability.find(symbol_name); | 
|  | 402 | missing_it != missing_availability.end()) { | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 403 | printf("%s: declaration marked available but symbol missing in [%s]\n", symbol_name.c_str(), | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 404 | Join(missing_it->second, ", ").c_str()); | 
|  | 405 | symbol_error = true; | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 406 | failed = true; | 
|  | 407 | } | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 408 |  | 
| Josh Gao | acc3d80 | 2016-11-09 18:22:44 -0800 | [diff] [blame] | 409 | if (strict) { | 
| Josh Gao | 0a284f5 | 2016-12-15 13:56:00 -0800 | [diff] [blame] | 410 | if (auto extra_it = extra_availability.find(symbol_name); | 
|  | 411 | extra_it != extra_availability.end()) { | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 412 | printf("%s: declaration marked unavailable but symbol available in [%s]\n", | 
|  | 413 | symbol_name.c_str(), Join(extra_it->second, ", ").c_str()); | 
|  | 414 | symbol_error = true; | 
|  | 415 | failed = true; | 
| Josh Gao | 958f3b3 | 2016-06-03 13:44:00 -0700 | [diff] [blame] | 416 | } | 
|  | 417 | } | 
|  | 418 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 419 | if (symbol_error) { | 
| Josh Gao | 0a284f5 | 2016-12-15 13:56:00 -0800 | [diff] [blame] | 420 | if (auto symbol_it = header_database->symbols.find(symbol_name); | 
|  | 421 | symbol_it != header_database->symbols.end()) { | 
|  | 422 | symbol_it->second.dump(cwd); | 
|  | 423 | } else { | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 424 | errx(1, "failed to find symbol in header database"); | 
|  | 425 | } | 
| Josh Gao | d67dbf0 | 2016-06-02 15:21:14 -0700 | [diff] [blame] | 426 | } | 
| Josh Gao | d67dbf0 | 2016-06-02 15:21:14 -0700 | [diff] [blame] | 427 | } | 
|  | 428 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 429 | // TODO: Verify that function/variable declarations are actually function/variable symbols. | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 430 | return !failed; | 
|  | 431 | } | 
|  | 432 |  | 
| Josh Gao | 62aaf8f | 2016-06-02 14:27:21 -0700 | [diff] [blame] | 433 | static void usage(bool help = false) { | 
|  | 434 | fprintf(stderr, "Usage: versioner [OPTION]... [HEADER_PATH] [DEPS_PATH]\n"); | 
|  | 435 | if (!help) { | 
|  | 436 | printf("Try 'versioner -h' for more information.\n"); | 
|  | 437 | exit(1); | 
|  | 438 | } else { | 
|  | 439 | fprintf(stderr, "Version headers at HEADER_PATH, with DEPS_PATH/ARCH/* on the include path\n"); | 
| Josh Gao | 9b5af7a | 2016-06-02 14:29:13 -0700 | [diff] [blame] | 440 | fprintf(stderr, "Autodetects paths if HEADER_PATH and DEPS_PATH are not specified\n"); | 
| Josh Gao | 62aaf8f | 2016-06-02 14:27:21 -0700 | [diff] [blame] | 441 | fprintf(stderr, "\n"); | 
|  | 442 | fprintf(stderr, "Target specification (defaults to all):\n"); | 
|  | 443 | fprintf(stderr, "  -a API_LEVEL\tbuild with specified API level (can be repeated)\n"); | 
|  | 444 | fprintf(stderr, "    \t\tvalid levels are %s\n", Join(supported_levels).c_str()); | 
|  | 445 | fprintf(stderr, "  -r ARCH\tbuild with specified architecture (can be repeated)\n"); | 
|  | 446 | fprintf(stderr, "    \t\tvalid architectures are %s\n", Join(supported_archs).c_str()); | 
|  | 447 | fprintf(stderr, "\n"); | 
|  | 448 | fprintf(stderr, "Validation:\n"); | 
|  | 449 | fprintf(stderr, "  -p PATH\tcompare against NDK platform at PATH\n"); | 
| Josh Gao | acc3d80 | 2016-11-09 18:22:44 -0800 | [diff] [blame] | 450 | fprintf(stderr, "  -s\t\tenable strict warnings\n"); | 
| Josh Gao | 62aaf8f | 2016-06-02 14:27:21 -0700 | [diff] [blame] | 451 | fprintf(stderr, "\n"); | 
| Josh Gao | f8592a3 | 2016-07-26 18:58:27 -0700 | [diff] [blame] | 452 | fprintf(stderr, "Preprocessing:\n"); | 
|  | 453 | fprintf(stderr, "  -o PATH\tpreprocess header files and emit them at PATH\n"); | 
| Josh Gao | d744a9b | 2017-04-03 11:24:48 -0700 | [diff] [blame] | 454 | fprintf(stderr, "  -f\t\tpreprocess header files even if validation fails\n"); | 
| Josh Gao | f8592a3 | 2016-07-26 18:58:27 -0700 | [diff] [blame] | 455 | fprintf(stderr, "\n"); | 
| Josh Gao | 62aaf8f | 2016-06-02 14:27:21 -0700 | [diff] [blame] | 456 | fprintf(stderr, "Miscellaneous:\n"); | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 457 | fprintf(stderr, "  -d\t\tdump function availability\n"); | 
| Josh Gao | 16016df | 2016-11-07 18:27:16 -0800 | [diff] [blame] | 458 | fprintf(stderr, "  -j THREADS\tmaximum number of threads to use\n"); | 
| Josh Gao | acc3d80 | 2016-11-09 18:22:44 -0800 | [diff] [blame] | 459 | fprintf(stderr, "  -v\t\tenable verbose logging\n"); | 
| Josh Gao | 62aaf8f | 2016-06-02 14:27:21 -0700 | [diff] [blame] | 460 | fprintf(stderr, "  -h\t\tdisplay this message\n"); | 
|  | 461 | exit(0); | 
|  | 462 | } | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 463 | } | 
|  | 464 |  | 
| Andreas Gampe | d10d3ee | 2017-04-28 19:32:13 -0700 | [diff] [blame] | 465 | // versioner uses a prebuilt version of clang, which is not up-to-date wrt/ | 
|  | 466 | // container annotations. So disable container overflow checking. b/37775238 | 
|  | 467 | extern "C" const char* __asan_default_options() { | 
|  | 468 | return "detect_container_overflow=0"; | 
|  | 469 | } | 
|  | 470 |  | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 471 | int main(int argc, char** argv) { | 
|  | 472 | std::string cwd = getWorkingDir() + "/"; | 
|  | 473 | bool default_args = true; | 
|  | 474 | std::string platform_dir; | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 475 | std::set<Arch> selected_architectures; | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 476 | std::set<int> selected_levels; | 
| Josh Gao | f8592a3 | 2016-07-26 18:58:27 -0700 | [diff] [blame] | 477 | std::string preprocessor_output_path; | 
|  | 478 | bool force = false; | 
| Josh Gao | 16016df | 2016-11-07 18:27:16 -0800 | [diff] [blame] | 479 | bool dump = false; | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 480 |  | 
|  | 481 | int c; | 
| Josh Gao | acc3d80 | 2016-11-09 18:22:44 -0800 | [diff] [blame] | 482 | while ((c = getopt(argc, argv, "a:r:p:so:fdj:vhi")) != -1) { | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 483 | default_args = false; | 
|  | 484 | switch (c) { | 
|  | 485 | case 'a': { | 
|  | 486 | char* end; | 
|  | 487 | int api_level = strtol(optarg, &end, 10); | 
|  | 488 | if (end == optarg || strlen(end) > 0) { | 
|  | 489 | usage(); | 
|  | 490 | } | 
|  | 491 |  | 
|  | 492 | if (supported_levels.count(api_level) == 0) { | 
|  | 493 | errx(1, "unsupported API level %d", api_level); | 
|  | 494 | } | 
|  | 495 |  | 
|  | 496 | selected_levels.insert(api_level); | 
|  | 497 | break; | 
|  | 498 | } | 
|  | 499 |  | 
|  | 500 | case 'r': { | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 501 | Arch arch = arch_from_string(optarg); | 
|  | 502 | selected_architectures.insert(arch); | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 503 | break; | 
|  | 504 | } | 
|  | 505 |  | 
|  | 506 | case 'p': { | 
|  | 507 | if (!platform_dir.empty()) { | 
|  | 508 | usage(); | 
|  | 509 | } | 
|  | 510 |  | 
|  | 511 | platform_dir = optarg; | 
|  | 512 |  | 
| Josh Gao | f8592a3 | 2016-07-26 18:58:27 -0700 | [diff] [blame] | 513 | if (platform_dir.empty()) { | 
|  | 514 | usage(); | 
|  | 515 | } | 
|  | 516 |  | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 517 | struct stat st; | 
|  | 518 | if (stat(platform_dir.c_str(), &st) != 0) { | 
|  | 519 | err(1, "failed to stat platform directory '%s'", platform_dir.c_str()); | 
|  | 520 | } | 
|  | 521 | if (!S_ISDIR(st.st_mode)) { | 
|  | 522 | errx(1, "'%s' is not a directory", optarg); | 
|  | 523 | } | 
|  | 524 | break; | 
|  | 525 | } | 
|  | 526 |  | 
| Josh Gao | acc3d80 | 2016-11-09 18:22:44 -0800 | [diff] [blame] | 527 | case 's': | 
|  | 528 | strict = true; | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 529 | break; | 
|  | 530 |  | 
| Josh Gao | f8592a3 | 2016-07-26 18:58:27 -0700 | [diff] [blame] | 531 | case 'o': | 
|  | 532 | if (!preprocessor_output_path.empty()) { | 
|  | 533 | usage(); | 
|  | 534 | } | 
|  | 535 | preprocessor_output_path = optarg; | 
|  | 536 | if (preprocessor_output_path.empty()) { | 
|  | 537 | usage(); | 
|  | 538 | } | 
|  | 539 | break; | 
|  | 540 |  | 
|  | 541 | case 'f': | 
|  | 542 | force = true; | 
|  | 543 | break; | 
|  | 544 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 545 | case 'd': | 
|  | 546 | dump = true; | 
|  | 547 | break; | 
|  | 548 |  | 
| Josh Gao | 16016df | 2016-11-07 18:27:16 -0800 | [diff] [blame] | 549 | case 'j': | 
|  | 550 | if (!android::base::ParseInt<int>(optarg, &max_thread_count, 1)) { | 
|  | 551 | usage(); | 
|  | 552 | } | 
|  | 553 | break; | 
|  | 554 |  | 
| Josh Gao | acc3d80 | 2016-11-09 18:22:44 -0800 | [diff] [blame] | 555 | case 'v': | 
|  | 556 | verbose = true; | 
|  | 557 | break; | 
|  | 558 |  | 
| Josh Gao | 62aaf8f | 2016-06-02 14:27:21 -0700 | [diff] [blame] | 559 | case 'h': | 
|  | 560 | usage(true); | 
|  | 561 | break; | 
|  | 562 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 563 | case 'i': | 
|  | 564 | // Secret option for tests to -include <android/versioning.h>. | 
|  | 565 | add_include = true; | 
|  | 566 | break; | 
|  | 567 |  | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 568 | default: | 
|  | 569 | usage(); | 
|  | 570 | break; | 
|  | 571 | } | 
|  | 572 | } | 
|  | 573 |  | 
| Josh Gao | 9b5af7a | 2016-06-02 14:29:13 -0700 | [diff] [blame] | 574 | if (argc - optind > 2 || optind > argc) { | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 575 | usage(); | 
|  | 576 | } | 
|  | 577 |  | 
| Josh Gao | 9b5af7a | 2016-06-02 14:29:13 -0700 | [diff] [blame] | 578 | std::string header_dir; | 
|  | 579 | std::string dependency_dir; | 
|  | 580 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 581 | const char* top = getenv("ANDROID_BUILD_TOP"); | 
|  | 582 | if (!top && (optind == argc || add_include)) { | 
|  | 583 | fprintf(stderr, "versioner: failed to autodetect bionic paths. Is ANDROID_BUILD_TOP set?\n"); | 
|  | 584 | usage(); | 
|  | 585 | } | 
|  | 586 |  | 
| Josh Gao | 9b5af7a | 2016-06-02 14:29:13 -0700 | [diff] [blame] | 587 | if (optind == argc) { | 
|  | 588 | // Neither HEADER_PATH nor DEPS_PATH were specified, so try to figure them out. | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 589 | std::string versioner_dir = to_string(top) + "/bionic/tools/versioner"; | 
| Josh Gao | 9b5af7a | 2016-06-02 14:29:13 -0700 | [diff] [blame] | 590 | header_dir = versioner_dir + "/current"; | 
|  | 591 | dependency_dir = versioner_dir + "/dependencies"; | 
|  | 592 | if (platform_dir.empty()) { | 
|  | 593 | platform_dir = versioner_dir + "/platforms"; | 
|  | 594 | } | 
|  | 595 | } else { | 
| Josh Gao | b50b8c8 | 2017-04-27 17:22:52 -0700 | [diff] [blame] | 596 | if (!android::base::Realpath(argv[optind], &header_dir)) { | 
|  | 597 | err(1, "failed to get realpath for path '%s'", argv[optind]); | 
|  | 598 | } | 
| Josh Gao | 9b5af7a | 2016-06-02 14:29:13 -0700 | [diff] [blame] | 599 |  | 
|  | 600 | if (argc - optind == 2) { | 
|  | 601 | dependency_dir = argv[optind + 1]; | 
|  | 602 | } | 
|  | 603 | } | 
|  | 604 |  | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 605 | if (selected_levels.empty()) { | 
|  | 606 | selected_levels = supported_levels; | 
|  | 607 | } | 
|  | 608 |  | 
|  | 609 | if (selected_architectures.empty()) { | 
|  | 610 | selected_architectures = supported_archs; | 
|  | 611 | } | 
|  | 612 |  | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 613 |  | 
|  | 614 | struct stat st; | 
| Josh Gao | 9b5af7a | 2016-06-02 14:29:13 -0700 | [diff] [blame] | 615 | if (stat(header_dir.c_str(), &st) != 0) { | 
|  | 616 | err(1, "failed to stat '%s'", header_dir.c_str()); | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 617 | } else if (!S_ISDIR(st.st_mode)) { | 
| Josh Gao | 9b5af7a | 2016-06-02 14:29:13 -0700 | [diff] [blame] | 618 | errx(1, "'%s' is not a directory", header_dir.c_str()); | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 619 | } | 
|  | 620 |  | 
|  | 621 | std::set<CompilationType> compilation_types; | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 622 | NdkSymbolDatabase symbol_database; | 
|  | 623 |  | 
|  | 624 | compilation_types = generateCompilationTypes(selected_architectures, selected_levels); | 
|  | 625 |  | 
|  | 626 | // Do this before compiling so that we can early exit if the platforms don't match what we | 
|  | 627 | // expect. | 
|  | 628 | if (!platform_dir.empty()) { | 
|  | 629 | symbol_database = parsePlatforms(compilation_types, platform_dir); | 
|  | 630 | } | 
|  | 631 |  | 
| Josh Gao | 338cf12 | 2016-11-09 18:01:41 -0800 | [diff] [blame] | 632 | auto start = std::chrono::high_resolution_clock::now(); | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 633 | std::unique_ptr<HeaderDatabase> declaration_database = | 
| Josh Gao | 16016df | 2016-11-07 18:27:16 -0800 | [diff] [blame] | 634 | compileHeaders(compilation_types, header_dir, dependency_dir); | 
| Josh Gao | 338cf12 | 2016-11-09 18:01:41 -0800 | [diff] [blame] | 635 | auto end = std::chrono::high_resolution_clock::now(); | 
|  | 636 |  | 
|  | 637 | if (verbose) { | 
|  | 638 | auto diff = (end - start) / 1.0ms; | 
|  | 639 | printf("Compiled headers for %zu targets in %0.2LFms\n", compilation_types.size(), diff); | 
|  | 640 | } | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 641 |  | 
| Josh Gao | 16016df | 2016-11-07 18:27:16 -0800 | [diff] [blame] | 642 | bool failed = false; | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 643 | if (dump) { | 
|  | 644 | declaration_database->dump(header_dir + "/"); | 
|  | 645 | } else { | 
|  | 646 | if (!sanityCheck(declaration_database.get())) { | 
|  | 647 | printf("versioner: sanity check failed\n"); | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 648 | failed = true; | 
|  | 649 | } | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 650 |  | 
| Josh Gao | bfb6bae | 2016-07-15 17:25:21 -0700 | [diff] [blame] | 651 | if (!platform_dir.empty()) { | 
|  | 652 | if (!checkVersions(compilation_types, declaration_database.get(), symbol_database)) { | 
|  | 653 | printf("versioner: version check failed\n"); | 
|  | 654 | failed = true; | 
|  | 655 | } | 
|  | 656 | } | 
|  | 657 | } | 
| Josh Gao | f8592a3 | 2016-07-26 18:58:27 -0700 | [diff] [blame] | 658 |  | 
|  | 659 | if (!preprocessor_output_path.empty() && (force || !failed)) { | 
|  | 660 | failed = !preprocessHeaders(preprocessor_output_path, header_dir, declaration_database.get()); | 
|  | 661 | } | 
| Josh Gao | bf8a285 | 2016-05-27 11:59:09 -0700 | [diff] [blame] | 662 | return failed; | 
|  | 663 | } |