blob: 3c29a09745c6a509f33f0d9159e2e1d2d9c68563 [file] [log] [blame]
Andreas Huber1aec3972016-08-26 09:26:32 -07001/*
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
Andreas Huberc9410c72016-07-28 12:18:40 -070017#include "AST.h"
Andreas Huber5345ec22016-07-29 13:33:27 -070018#include "Coordinator.h"
Andreas Huber0fa9e392016-08-31 09:05:44 -070019#include "Scope.h"
Andreas Huberc9410c72016-07-28 12:18:40 -070020
Steven Moreland5bdfa702017-04-18 23:20:39 -070021#include <hidl-hash/Hash.h>
Iliyan Malcheva72e0d22016-09-09 11:03:08 -070022#include <hidl-util/Formatter.h>
Steven Moreland7ae3d542017-01-18 16:46:01 -080023#include <hidl-util/FQName.h>
Steven Morelandd177b122016-12-12 09:15:37 -080024#include <hidl-util/StringHelper.h>
Andreas Huber68f24592016-07-29 14:53:48 -070025#include <android-base/logging.h>
Iliyan Malchev5bb14022016-08-09 15:04:39 -070026#include <set>
Andreas Huberc9410c72016-07-28 12:18:40 -070027#include <stdio.h>
Andreas Huberdca261f2016-08-04 13:47:51 -070028#include <string>
Andreas Huberb82318c2016-08-02 14:45:54 -070029#include <unistd.h>
Andreas Huberdca261f2016-08-04 13:47:51 -070030#include <vector>
Andreas Huberc9410c72016-07-28 12:18:40 -070031
32using namespace android;
33
Iliyan Malchev5bb14022016-08-09 15:04:39 -070034struct OutputHandler {
35 std::string mKey;
Steven Moreland97e52332017-05-12 16:47:19 -070036 std::string mDescription;
Andreas Huber019d21d2016-10-03 12:59:47 -070037 enum OutputMode {
38 NEEDS_DIR,
39 NEEDS_FILE,
Steven Morelanda171b562017-05-12 15:18:03 -070040 NEEDS_SRC, // for changes inside the source tree itself
Andreas Huber019d21d2016-10-03 12:59:47 -070041 NOT_NEEDED
42 } mOutputMode;
43
Steven Morelanddd583842017-04-19 13:09:57 -070044 const std::string& name() { return mKey; }
Steven Moreland97e52332017-05-12 16:47:19 -070045 const std::string& description() { return mDescription; }
Steven Morelandbbbbeb82017-05-09 14:20:50 -070046
Steven Moreland05951b32017-05-12 17:22:22 -070047 using ValidationFunction = std::function<bool(const FQName &, const std::string &language)>;
Steven Morelandbbbbeb82017-05-09 14:20:50 -070048 using GenerationFunction = std::function<status_t(const FQName &fqName,
49 const char *hidl_gen,
50 Coordinator *coordinator,
51 const std::string &outputDir)>;
52
53 ValidationFunction validate;
54 GenerationFunction generate;
Iliyan Malchev5bb14022016-08-09 15:04:39 -070055};
Andreas Huberdca261f2016-08-04 13:47:51 -070056
Iliyan Malchev5bb14022016-08-09 15:04:39 -070057static status_t generateSourcesForFile(
58 const FQName &fqName,
59 const char *,
60 Coordinator *coordinator,
Andreas Huber2831d512016-08-15 09:33:47 -070061 const std::string &outputDir,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070062 const std::string &lang) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -070063 CHECK(fqName.isFullyQualified());
64
Andreas Huber0fa9e392016-08-31 09:05:44 -070065 AST *ast;
Andreas Huberd29724f2016-09-14 09:33:13 -070066 std::string limitToType;
Andreas Huber0fa9e392016-08-31 09:05:44 -070067
68 if (fqName.name().find("types.") == 0) {
69 CHECK(lang == "java"); // Already verified in validate().
70
Andreas Huberd29724f2016-09-14 09:33:13 -070071 limitToType = fqName.name().substr(strlen("types."));
Andreas Huber0fa9e392016-08-31 09:05:44 -070072
Yifan Hongfece6ec2017-01-12 17:04:04 -080073 FQName typesName = fqName.getTypesForPackage();
Andreas Huber0fa9e392016-08-31 09:05:44 -070074 ast = coordinator->parse(typesName);
75 } else {
76 ast = coordinator->parse(fqName);
77 }
Iliyan Malchev5bb14022016-08-09 15:04:39 -070078
79 if (ast == NULL) {
80 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -070081 "ERROR: Could not parse %s. Aborting.\n",
Iliyan Malchev5bb14022016-08-09 15:04:39 -070082 fqName.string().c_str());
83
84 return UNKNOWN_ERROR;
85 }
86
Steven Moreland3b1ce262017-04-21 14:19:59 -070087 if (lang == "check") {
88 return OK; // only parsing, not generating
89 }
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070090 if (lang == "c++") {
91 return ast->generateCpp(outputDir);
92 }
Steven Moreland1cbf0362017-05-09 14:32:53 -070093 if (lang == "c++-headers") {
94 return ast->generateCppHeaders(outputDir);
95 }
96 if (lang == "c++-sources") {
97 return ast->generateCppSources(outputDir);
98 }
Steven Moreland9c387612016-09-07 09:54:26 -070099 if (lang == "c++-impl") {
100 return ast->generateCppImpl(outputDir);
101 }
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700102 if (lang == "java") {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700103 return ast->generateJava(outputDir, limitToType);
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700104 }
105 if (lang == "vts") {
106 return ast->generateVts(outputDir);
107 }
108 // Unknown language.
109 return UNKNOWN_ERROR;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700110}
111
112static status_t generateSourcesForPackage(
113 const FQName &packageFQName,
114 const char *hidl_gen,
115 Coordinator *coordinator,
Andreas Huber2831d512016-08-15 09:33:47 -0700116 const std::string &outputDir,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700117 const std::string &lang) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700118 CHECK(packageFQName.isValid() &&
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700119 !packageFQName.isFullyQualified() &&
120 packageFQName.name().empty());
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700121
122 std::vector<FQName> packageInterfaces;
123
124 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700125 coordinator->appendPackageInterfacesToVector(packageFQName,
126 &packageInterfaces);
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700127
128 if (err != OK) {
129 return err;
130 }
131
132 for (const auto &fqName : packageInterfaces) {
Andreas Huber2831d512016-08-15 09:33:47 -0700133 err = generateSourcesForFile(
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700134 fqName, hidl_gen, coordinator, outputDir, lang);
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700135 if (err != OK) {
136 return err;
137 }
138 }
139
140 return OK;
Andreas Huberb82318c2016-08-02 14:45:54 -0700141}
142
Steven Morelandbbbbeb82017-05-09 14:20:50 -0700143OutputHandler::GenerationFunction generationFunctionForFileOrPackage(const std::string &language) {
144 return [language](const FQName &fqName,
145 const char *hidl_gen, Coordinator *coordinator,
146 const std::string &outputDir) -> status_t {
147 if (fqName.isFullyQualified()) {
148 return generateSourcesForFile(fqName,
149 hidl_gen,
150 coordinator,
151 outputDir,
152 language);
153 } else {
154 return generateSourcesForPackage(fqName,
155 hidl_gen,
156 coordinator,
157 outputDir,
158 language);
159 }
160 };
161}
162
Andreas Huberd2943e12016-08-05 11:59:31 -0700163static std::string makeLibraryName(const FQName &packageFQName) {
Iliyan Malcheve2c595a2016-08-07 21:20:04 -0700164 return packageFQName.string();
Andreas Huberd2943e12016-08-05 11:59:31 -0700165}
166
Andreas Huberaa573272017-04-13 09:58:06 -0700167static std::string makeJavaLibraryName(const FQName &packageFQName) {
168 std::string out;
169 out = packageFQName.package();
170 out += "-V";
171 out += packageFQName.version();
172 return out;
173}
174
Steven Moreland5715fed2017-01-16 11:06:47 -0800175static void generatePackagePathsSection(
176 Formatter &out,
177 Coordinator *coordinator,
178 const FQName &packageFQName,
179 const std::set<FQName> &importedPackages,
180 bool forMakefiles = false) {
181 std::set<std::string> options{};
182 for (const auto &interface : importedPackages) {
183 options.insert(coordinator->getPackageRootOption(interface));
184 }
185 options.insert(coordinator->getPackageRootOption(packageFQName));
186 options.insert(coordinator->getPackageRootOption(gIBasePackageFqName));
187 for (const auto &option : options) {
188 out << "-r"
189 << option
190 << " ";
191 if (forMakefiles) {
192 out << "\\\n";
193 }
194 }
195}
196
Dan Willemsen676abdc2016-09-28 19:42:22 -0700197static void generateMakefileSectionForType(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700198 Formatter &out,
199 Coordinator *coordinator,
200 const FQName &packageFQName,
201 const FQName &fqName,
Steven Moreland5715fed2017-01-16 11:06:47 -0800202 const std::set<FQName> &importedPackages,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700203 const char *typeName) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700204 out << "\n"
205 << "\n#"
206 << "\n# Build " << fqName.name() << ".hal";
207
Dan Willemsen676abdc2016-09-28 19:42:22 -0700208 if (typeName != nullptr) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700209 out << " (" << typeName << ")";
210 }
211
212 out << "\n#"
213 << "\nGEN := $(intermediates)/"
214 << coordinator->convertPackageRootToPath(packageFQName)
Yifan Hong97288ac2016-12-12 16:03:51 -0800215 << coordinator->getPackagePath(packageFQName, true /* relative */,
216 true /* sanitized */);
Dan Willemsen676abdc2016-09-28 19:42:22 -0700217 if (typeName == nullptr) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700218 out << fqName.name() << ".java";
219 } else {
220 out << typeName << ".java";
221 }
222
223 out << "\n$(GEN): $(HIDL)";
224 out << "\n$(GEN): PRIVATE_HIDL := $(HIDL)";
225 out << "\n$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/"
226 << fqName.name() << ".hal";
Iliyan Malchevb9819132016-09-07 12:38:31 -0700227
228 {
229 AST *ast = coordinator->parse(fqName);
230 CHECK(ast != nullptr);
231 const std::set<FQName>& refs = ast->getImportedNames();
232 for (auto depFQName : refs) {
233 // If the package of depFQName is the same as this fqName's package,
234 // then add it explicitly as a .hal dependency within the same
235 // package.
236 if (fqName.package() == depFQName.package() &&
237 fqName.version() == depFQName.version()) {
238 // PRIVATE_DEPS is not actually being used in the
239 // auto-generated file, but is necessary if the build rule
240 // ever needs to use the dependency information, since the
241 // built-in Make variables are not supported in the Android
242 // build system.
243 out << "\n$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/"
244 << depFQName.name() << ".hal";
245 // This is the actual dependency.
246 out << "\n$(GEN): $(LOCAL_PATH)/"
247 << depFQName.name() << ".hal";
248 }
249 }
250 }
251
Andreas Huber0fa9e392016-08-31 09:05:44 -0700252 out << "\n$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)"
253 << "\n$(GEN): PRIVATE_CUSTOM_TOOL = \\";
254 out.indent();
255 out.indent();
256 out << "\n$(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \\"
Steven Moreland5715fed2017-01-16 11:06:47 -0800257 << "\n-Ljava \\\n";
258
259 generatePackagePathsSection(out, coordinator, packageFQName, importedPackages, true /* forJava */);
Andreas Huber0fa9e392016-08-31 09:05:44 -0700260
261 out << packageFQName.string()
262 << "::"
263 << fqName.name();
264
Dan Willemsen676abdc2016-09-28 19:42:22 -0700265 if (typeName != nullptr) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700266 out << "." << typeName;
267 }
268
269 out << "\n";
270
271 out.unindent();
272 out.unindent();
273
274 out << "\n$(GEN): $(LOCAL_PATH)/" << fqName.name() << ".hal";
275 out << "\n\t$(transform-generated-source)";
276 out << "\nLOCAL_GENERATED_SOURCES += $(GEN)";
277}
278
Dan Willemsen676abdc2016-09-28 19:42:22 -0700279static void generateMakefileSection(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700280 Formatter &out,
281 Coordinator *coordinator,
282 const FQName &packageFQName,
283 const std::vector<FQName> &packageInterfaces,
Steven Moreland5715fed2017-01-16 11:06:47 -0800284 const std::set<FQName> &importedPackages,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700285 AST *typesAST) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700286 for (const auto &fqName : packageInterfaces) {
Dan Willemsen676abdc2016-09-28 19:42:22 -0700287 if (fqName.name() == "types") {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700288 CHECK(typesAST != nullptr);
289
290 Scope *rootScope = typesAST->scope();
Andreas Huber0fa9e392016-08-31 09:05:44 -0700291
Andreas Huberb747bd92016-09-26 15:55:31 -0700292 std::vector<NamedType *> subTypes = rootScope->getSubTypes();
293 std::sort(
294 subTypes.begin(),
295 subTypes.end(),
296 [](const NamedType *a, const NamedType *b) -> bool {
297 return a->fqName() < b->fqName();
298 });
299
300 for (const auto &type : subTypes) {
Andreas Huberdda25cc2016-09-22 10:39:47 -0700301 if (type->isTypeDef()) {
302 continue;
303 }
304
Dan Willemsen676abdc2016-09-28 19:42:22 -0700305 generateMakefileSectionForType(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700306 out,
307 coordinator,
308 packageFQName,
309 fqName,
Steven Moreland5715fed2017-01-16 11:06:47 -0800310 importedPackages,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700311 type->localName().c_str());
Andreas Huber0fa9e392016-08-31 09:05:44 -0700312 }
313
314 continue;
315 }
316
Dan Willemsen676abdc2016-09-28 19:42:22 -0700317 generateMakefileSectionForType(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700318 out,
319 coordinator,
320 packageFQName,
321 fqName,
Steven Moreland5715fed2017-01-16 11:06:47 -0800322 importedPackages,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700323 nullptr /* typeName */);
Andreas Huber0fa9e392016-08-31 09:05:44 -0700324 }
325}
326
Andreas Huber75ae95d2016-10-12 16:08:26 -0700327static status_t isPackageJavaCompatible(
328 const FQName &packageFQName,
329 Coordinator *coordinator,
330 bool *compatible) {
331 std::vector<FQName> todo;
332 status_t err =
333 coordinator->appendPackageInterfacesToVector(packageFQName, &todo);
334
335 if (err != OK) {
336 return err;
337 }
338
339 std::set<FQName> seen;
340 for (const auto &iface : todo) {
341 seen.insert(iface);
342 }
343
344 // Form the transitive closure of all imported interfaces (and types.hal-s)
345 // If any one of them is not java compatible, this package isn't either.
346 while (!todo.empty()) {
347 const FQName fqName = todo.back();
348 todo.pop_back();
349
350 AST *ast = coordinator->parse(fqName);
351
352 if (ast == nullptr) {
353 return UNKNOWN_ERROR;
354 }
355
356 if (!ast->isJavaCompatible()) {
357 *compatible = false;
358 return OK;
359 }
360
361 std::set<FQName> importedPackages;
362 ast->getImportedPackages(&importedPackages);
363
364 for (const auto &package : importedPackages) {
365 std::vector<FQName> packageInterfaces;
366 status_t err = coordinator->appendPackageInterfacesToVector(
367 package, &packageInterfaces);
368
369 if (err != OK) {
370 return err;
371 }
372
373 for (const auto &iface : packageInterfaces) {
374 if (seen.find(iface) != seen.end()) {
375 continue;
376 }
377
378 todo.push_back(iface);
379 seen.insert(iface);
380 }
381 }
382 }
383
384 *compatible = true;
385 return OK;
386}
387
Andreas Huber5a9fe2c2016-10-13 15:31:10 -0700388static bool packageNeedsJavaCode(
389 const std::vector<FQName> &packageInterfaces, AST *typesAST) {
390 // If there is more than just a types.hal file to this package we'll
391 // definitely need to generate Java code.
392 if (packageInterfaces.size() > 1
393 || packageInterfaces[0].name() != "types") {
394 return true;
395 }
396
397 CHECK(typesAST != nullptr);
398
399 // We'll have to generate Java code if types.hal contains any non-typedef
400 // type declarations.
401
402 Scope *rootScope = typesAST->scope();
403 std::vector<NamedType *> subTypes = rootScope->getSubTypes();
404
405 for (const auto &subType : subTypes) {
406 if (!subType->isTypeDef()) {
407 return true;
408 }
409 }
410
411 return false;
412}
413
Andreas Huber1c507272016-10-05 14:33:21 -0700414static void generateMakefileSectionForJavaConstants(
415 Formatter &out,
416 Coordinator *coordinator,
417 const FQName &packageFQName,
Steven Moreland5715fed2017-01-16 11:06:47 -0800418 const std::vector<FQName> &packageInterfaces,
419 const std::set<FQName> &importedPackages) {
Andreas Huber1c507272016-10-05 14:33:21 -0700420 out << "\n#"
421 << "\nGEN := $(intermediates)/"
422 << coordinator->convertPackageRootToPath(packageFQName)
Yifan Hong97288ac2016-12-12 16:03:51 -0800423 << coordinator->getPackagePath(packageFQName, true /* relative */, true /* sanitized */)
Andreas Huber1c507272016-10-05 14:33:21 -0700424 << "Constants.java";
425
426 out << "\n$(GEN): $(HIDL)\n";
427 for (const auto &iface : packageInterfaces) {
428 out << "$(GEN): $(LOCAL_PATH)/" << iface.name() << ".hal\n";
429 }
430 out << "\n$(GEN): PRIVATE_HIDL := $(HIDL)";
431 out << "\n$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)"
432 << "\n$(GEN): PRIVATE_CUSTOM_TOOL = \\";
433 out.indent();
434 out.indent();
435 out << "\n$(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \\"
Steven Moreland5715fed2017-01-16 11:06:47 -0800436 << "\n-Ljava-constants \\\n";
437
438 generatePackagePathsSection(out, coordinator, packageFQName, importedPackages, true /* forJava */);
Andreas Huber1c507272016-10-05 14:33:21 -0700439
440 out << packageFQName.string();
441 out << "\n";
442
443 out.unindent();
444 out.unindent();
445
446 out << "\n$(GEN):";
447 out << "\n\t$(transform-generated-source)";
448 out << "\nLOCAL_GENERATED_SOURCES += $(GEN)";
449}
450
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700451static status_t generateMakefileForPackage(
452 const FQName &packageFQName,
Iliyan Malchevb66c3992016-08-07 21:18:13 -0700453 const char *hidl_gen,
Andreas Huberd2943e12016-08-05 11:59:31 -0700454 Coordinator *coordinator,
Steven Morelanda171b562017-05-12 15:18:03 -0700455 const std::string &outputPath) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700456
457 CHECK(packageFQName.isValid() &&
458 !packageFQName.isFullyQualified() &&
459 packageFQName.name().empty());
460
Andreas Huberd2943e12016-08-05 11:59:31 -0700461 std::vector<FQName> packageInterfaces;
462
463 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700464 coordinator->appendPackageInterfacesToVector(packageFQName,
465 &packageInterfaces);
Andreas Huberd2943e12016-08-05 11:59:31 -0700466
467 if (err != OK) {
468 return err;
469 }
470
471 std::set<FQName> importedPackages;
Andreas Huber0fa9e392016-08-31 09:05:44 -0700472 AST *typesAST = nullptr;
Andreas Huber1c507272016-10-05 14:33:21 -0700473 std::vector<const Type *> exportedTypes;
Andreas Huber0fa9e392016-08-31 09:05:44 -0700474
Andreas Huberd2943e12016-08-05 11:59:31 -0700475 for (const auto &fqName : packageInterfaces) {
476 AST *ast = coordinator->parse(fqName);
477
478 if (ast == NULL) {
479 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700480 "ERROR: Could not parse %s. Aborting.\n",
Andreas Huberd2943e12016-08-05 11:59:31 -0700481 fqName.string().c_str());
482
483 return UNKNOWN_ERROR;
484 }
485
Andreas Huber0fa9e392016-08-31 09:05:44 -0700486 if (fqName.name() == "types") {
487 typesAST = ast;
488 }
489
Yifan Hong40a373d2016-11-30 15:16:47 -0800490 ast->getImportedPackagesHierarchy(&importedPackages);
Andreas Huber1c507272016-10-05 14:33:21 -0700491 ast->appendToExportedTypesVector(&exportedTypes);
Andreas Huberd2943e12016-08-05 11:59:31 -0700492 }
493
Andreas Huber75ae95d2016-10-12 16:08:26 -0700494 bool packageIsJavaCompatible;
495 err = isPackageJavaCompatible(
496 packageFQName, coordinator, &packageIsJavaCompatible);
497
498 if (err != OK) {
499 return err;
500 }
501
Andreas Huber1c507272016-10-05 14:33:21 -0700502 bool haveJavaConstants = !exportedTypes.empty();
503
504 if (!packageIsJavaCompatible && !haveJavaConstants) {
Steven Moreland81979932016-12-07 15:11:06 -0800505 // TODO(b/33420795)
506 fprintf(stderr,
507 "WARNING: %s is not java compatible. No java makefile created.\n",
508 packageFQName.string().c_str());
Dan Willemsen676abdc2016-09-28 19:42:22 -0700509 return OK;
510 }
511
Andreas Huber5a9fe2c2016-10-13 15:31:10 -0700512 if (!packageNeedsJavaCode(packageInterfaces, typesAST)) {
513 return OK;
514 }
515
Steven Morelanda171b562017-05-12 15:18:03 -0700516 std::string path = outputPath;
Steven Morelandf7fa0682017-05-11 16:14:55 -0700517 path.append(coordinator->getPackagePath(packageFQName, false /* relative */));
Andreas Huberd2943e12016-08-05 11:59:31 -0700518 path.append("Android.mk");
519
520 CHECK(Coordinator::MakeParentHierarchy(path));
521 FILE *file = fopen(path.c_str(), "w");
522
523 if (file == NULL) {
524 return -errno;
525 }
526
Andreas Huberaa573272017-04-13 09:58:06 -0700527 const std::string libraryName = makeJavaLibraryName(packageFQName);
Andreas Huberd2943e12016-08-05 11:59:31 -0700528
529 Formatter out(file);
530
Dan Willemsen676abdc2016-09-28 19:42:22 -0700531 out << "# This file is autogenerated by hidl-gen. Do not edit manually.\n\n";
532 out << "LOCAL_PATH := $(call my-dir)\n";
Andreas Huberd2943e12016-08-05 11:59:31 -0700533
Dan Willemsen676abdc2016-09-28 19:42:22 -0700534 enum LibraryStyle {
535 LIBRARY_STYLE_REGULAR,
536 LIBRARY_STYLE_STATIC,
537 LIBRARY_STYLE_END,
538 };
Andreas Huberd2943e12016-08-05 11:59:31 -0700539
Andreas Huber1c507272016-10-05 14:33:21 -0700540 for (int style = LIBRARY_STYLE_REGULAR;
541 (packageIsJavaCompatible && style != LIBRARY_STYLE_END);
Dan Willemsen676abdc2016-09-28 19:42:22 -0700542 ++style) {
543 const std::string staticSuffix =
544 (style == LIBRARY_STYLE_STATIC) ? "-static" : "";
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700545
Dan Willemsen676abdc2016-09-28 19:42:22 -0700546 out << "\n"
547 << "########################################"
548 << "########################################\n\n";
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700549
Dan Willemsen676abdc2016-09-28 19:42:22 -0700550 out << "include $(CLEAR_VARS)\n"
551 << "LOCAL_MODULE := "
552 << libraryName
553 << "-java"
554 << staticSuffix
555 << "\nLOCAL_MODULE_CLASS := JAVA_LIBRARIES\n\n"
Andreas Huber177a8b12017-02-09 10:08:48 -0800556 << "intermediates := $(call local-generated-sources-dir, COMMON)"
557 << "\n\n"
Dan Willemsen676abdc2016-09-28 19:42:22 -0700558 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
559 << hidl_gen
560 << "$(HOST_EXECUTABLE_SUFFIX)";
Andreas Huberd2943e12016-08-05 11:59:31 -0700561
Dan Willemsen676abdc2016-09-28 19:42:22 -0700562 if (!importedPackages.empty()) {
Iliyan Malchev800273d2016-09-02 15:25:07 -0700563 out << "\n"
Dan Willemsen676abdc2016-09-28 19:42:22 -0700564 << "\nLOCAL_"
Andreas Huber782d45e2016-09-22 13:25:14 -0700565 << ((style == LIBRARY_STYLE_STATIC) ? "STATIC_" : "")
Dan Willemsen676abdc2016-09-28 19:42:22 -0700566 << "JAVA_LIBRARIES := \\";
567
568 out.indent();
569 for (const auto &importedPackage : importedPackages) {
570 out << "\n"
Andreas Huberaa573272017-04-13 09:58:06 -0700571 << makeJavaLibraryName(importedPackage)
Dan Willemsen676abdc2016-09-28 19:42:22 -0700572 << "-java"
573 << staticSuffix
574 << " \\";
575 }
576 out << "\n";
577 out.unindent();
Iliyan Malchev800273d2016-09-02 15:25:07 -0700578 }
Dan Willemsen676abdc2016-09-28 19:42:22 -0700579
580 generateMakefileSection(
581 out,
582 coordinator,
583 packageFQName,
584 packageInterfaces,
Steven Moreland5715fed2017-01-16 11:06:47 -0800585 importedPackages,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700586 typesAST);
587
588 out << "\ninclude $(BUILD_"
589 << ((style == LIBRARY_STYLE_STATIC) ? "STATIC_" : "")
590 << "JAVA_LIBRARY)\n\n";
Andreas Huber0fa9e392016-08-31 09:05:44 -0700591 }
592
Andreas Huber1c507272016-10-05 14:33:21 -0700593 if (haveJavaConstants) {
594 out << "\n"
595 << "########################################"
596 << "########################################\n\n";
597
598 out << "include $(CLEAR_VARS)\n"
599 << "LOCAL_MODULE := "
600 << libraryName
601 << "-java-constants"
602 << "\nLOCAL_MODULE_CLASS := JAVA_LIBRARIES\n\n"
Andreas Huber177a8b12017-02-09 10:08:48 -0800603 << "intermediates := $(call local-generated-sources-dir, COMMON)"
604 << "\n\n"
Andreas Huber1c507272016-10-05 14:33:21 -0700605 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
606 << hidl_gen
607 << "$(HOST_EXECUTABLE_SUFFIX)";
608
609 generateMakefileSectionForJavaConstants(
Steven Moreland5715fed2017-01-16 11:06:47 -0800610 out, coordinator, packageFQName, packageInterfaces, importedPackages);
Andreas Huber1c507272016-10-05 14:33:21 -0700611
612 out << "\n# Avoid dependency cycle of framework.jar -> this-library "
613 << "-> framework.jar\n"
614 << "LOCAL_NO_STANDARD_LIBRARIES := true\n"
615 << "LOCAL_JAVA_LIBRARIES := core-oj\n\n"
616 << "include $(BUILD_STATIC_JAVA_LIBRARY)\n\n";
617 }
618
Iliyan Malchev8be09552016-09-22 16:20:33 -0700619 out << "\n\n"
620 << "include $(call all-makefiles-under,$(LOCAL_PATH))\n";
621
Andreas Huberd2943e12016-08-05 11:59:31 -0700622 return OK;
623}
624
Steven Moreland05951b32017-05-12 17:22:22 -0700625bool validateIsPackage(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700626 const FQName &fqName, const std::string & /* language */) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700627 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700628 fprintf(stderr, "ERROR: Expecting package name\n");
Steven Moreland05951b32017-05-12 17:22:22 -0700629 return false;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700630 }
631
632 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700633 fprintf(stderr, "ERROR: Expecting package version\n");
Steven Moreland05951b32017-05-12 17:22:22 -0700634 return false;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700635 }
636
637 if (!fqName.name().empty()) {
638 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700639 "ERROR: Expecting only package name and version.\n");
Steven Moreland05951b32017-05-12 17:22:22 -0700640 return false;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700641 }
642
Steven Moreland05951b32017-05-12 17:22:22 -0700643 return true;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700644}
645
Steven Moreland77cf7642017-06-15 14:49:39 -0700646bool isHidlTransportPackage(const FQName &package) {
647 return package == gIBasePackageFqName ||
648 package == gIManagerPackageFqName;
649}
650
Dan Willemsen676abdc2016-09-28 19:42:22 -0700651static void generateAndroidBpGenSection(
652 Formatter &out,
653 const FQName &packageFQName,
654 const char *hidl_gen,
655 Coordinator *coordinator,
Tri Vo6a827fa2017-02-08 10:24:42 -0800656 const std::string &halFilegroupName,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700657 const std::string &genName,
658 const char *language,
659 const std::vector<FQName> &packageInterfaces,
Steven Moreland5715fed2017-01-16 11:06:47 -0800660 const std::set<FQName> &importedPackages,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700661 const std::function<void(Formatter&, const FQName)> outputFn) {
662
663 out << "genrule {\n";
664 out.indent();
665 out << "name: \"" << genName << "\",\n"
Colin Crossd5419bd2016-11-04 15:05:54 -0700666 << "tools: [\"" << hidl_gen << "\"],\n";
Dan Willemsen676abdc2016-09-28 19:42:22 -0700667
Colin Crossd5419bd2016-11-04 15:05:54 -0700668 out << "cmd: \"$(location " << hidl_gen << ") -o $(genDir)"
Steven Moreland5715fed2017-01-16 11:06:47 -0800669 << " -L" << language << " ";
670
671 generatePackagePathsSection(out, coordinator, packageFQName, importedPackages);
672
673 out << packageFQName.string() << "\",\n";
Dan Willemsen676abdc2016-09-28 19:42:22 -0700674
675 out << "srcs: [\n";
676 out.indent();
Tri Vo6a827fa2017-02-08 10:24:42 -0800677 out << "\":" << halFilegroupName << "\",\n";
Dan Willemsen676abdc2016-09-28 19:42:22 -0700678 out.unindent();
679 out << "],\n";
680
681 out << "out: [\n";
682 out.indent();
683 for (const auto &fqName : packageInterfaces) {
684 outputFn(out, fqName);
685 }
686 out.unindent();
687 out << "],\n";
688
689 out.unindent();
690 out << "}\n\n";
691}
692
Steven Moreland77cf7642017-06-15 14:49:39 -0700693static void generateAndroidBpLibSection(
694 Formatter &out,
695 bool generateVendor,
696 const std::string &libraryName,
697 const std::string &genSourceName,
698 const std::string &genHeaderName,
699 const std::set<FQName> &importedPackagesHierarchy) {
700
701 // C++ library definition
702 out << "cc_library_shared {\n";
703 out.indent();
704 out << "name: \"" << libraryName << (generateVendor ? "_vendor" : "") << "\",\n"
705 << "defaults: [\"hidl-module-defaults\"],\n"
706 << "generated_sources: [\"" << genSourceName << "\"],\n"
707 << "generated_headers: [\"" << genHeaderName << "\"],\n"
708 << "export_generated_headers: [\"" << genHeaderName << "\"],\n";
709
710 if (generateVendor) {
711 out << "vendor: true,\n";
712 } else {
713 out << "vendor_available: true,\n";
714 }
715 out << "shared_libs: [\n";
716
717 out.indent();
718 out << "\"libhidlbase\",\n"
719 << "\"libhidltransport\",\n"
720 << "\"libhwbinder\",\n"
721 << "\"liblog\",\n"
722 << "\"libutils\",\n"
723 << "\"libcutils\",\n";
724 for (const auto &importedPackage : importedPackagesHierarchy) {
725 if (isHidlTransportPackage(importedPackage)) {
726 continue;
727 }
728
729 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
730 }
731 out.unindent();
732
733 out << "],\n";
734
735 out << "export_shared_lib_headers: [\n";
736 out.indent();
737 out << "\"libhidlbase\",\n"
738 << "\"libhidltransport\",\n"
739 << "\"libhwbinder\",\n"
740 << "\"libutils\",\n";
741 for (const auto &importedPackage : importedPackagesHierarchy) {
742 if (isHidlTransportPackage(importedPackage)) {
743 continue;
744 }
745
746 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
747 }
748 out.unindent();
749 out << "],\n";
750 out.unindent();
751
752 out << "}\n";
Steven Moreland1b2167b2017-05-01 10:06:21 -0700753}
754
Dan Willemsen676abdc2016-09-28 19:42:22 -0700755static status_t generateAndroidBpForPackage(
756 const FQName &packageFQName,
757 const char *hidl_gen,
758 Coordinator *coordinator,
Steven Morelanda171b562017-05-12 15:18:03 -0700759 const std::string &outputPath) {
Dan Willemsen676abdc2016-09-28 19:42:22 -0700760
761 CHECK(packageFQName.isValid() &&
762 !packageFQName.isFullyQualified() &&
763 packageFQName.name().empty());
764
765 std::vector<FQName> packageInterfaces;
766
767 status_t err =
768 coordinator->appendPackageInterfacesToVector(packageFQName,
769 &packageInterfaces);
770
771 if (err != OK) {
772 return err;
773 }
774
Steven Morelandff5262b2017-03-20 06:59:03 -0700775 std::set<FQName> importedPackagesHierarchy;
Dan Willemsen676abdc2016-09-28 19:42:22 -0700776 AST *typesAST = nullptr;
777
778 for (const auto &fqName : packageInterfaces) {
779 AST *ast = coordinator->parse(fqName);
780
781 if (ast == NULL) {
782 fprintf(stderr,
783 "ERROR: Could not parse %s. Aborting.\n",
784 fqName.string().c_str());
785
786 return UNKNOWN_ERROR;
787 }
788
789 if (fqName.name() == "types") {
790 typesAST = ast;
791 }
792
Steven Morelandff5262b2017-03-20 06:59:03 -0700793 ast->getImportedPackagesHierarchy(&importedPackagesHierarchy);
Dan Willemsen676abdc2016-09-28 19:42:22 -0700794 }
795
Steven Morelanda171b562017-05-12 15:18:03 -0700796 std::string path = outputPath;
Steven Morelandf7fa0682017-05-11 16:14:55 -0700797 path.append(coordinator->getPackagePath(packageFQName, false /* relative */));
Dan Willemsen676abdc2016-09-28 19:42:22 -0700798 path.append("Android.bp");
799
800 CHECK(Coordinator::MakeParentHierarchy(path));
801 FILE *file = fopen(path.c_str(), "w");
802
803 if (file == NULL) {
804 return -errno;
805 }
806
807 const std::string libraryName = makeLibraryName(packageFQName);
Tri Vo15052c62017-02-06 10:04:07 -0800808 const std::string halFilegroupName = libraryName + "_hal";
Dan Willemsen676abdc2016-09-28 19:42:22 -0700809 const std::string genSourceName = libraryName + "_genc++";
810 const std::string genHeaderName = libraryName + "_genc++_headers";
811 const std::string pathPrefix =
812 coordinator->convertPackageRootToPath(packageFQName) +
813 coordinator->getPackagePath(packageFQName, true /* relative */);
814
815 Formatter out(file);
816
817 out << "// This file is autogenerated by hidl-gen. Do not edit manually.\n\n";
818
Tri Vo15052c62017-02-06 10:04:07 -0800819 // Rule to generate .hal filegroup
820 out << "filegroup {\n";
821 out.indent();
822 out << "name: \"" << halFilegroupName << "\",\n";
823 out << "srcs: [\n";
824 out.indent();
825 for (const auto &fqName : packageInterfaces) {
826 out << "\"" << fqName.name() << ".hal\",\n";
827 }
828 out.unindent();
829 out << "],\n";
830 out.unindent();
831 out << "}\n\n";
832
Dan Willemsen676abdc2016-09-28 19:42:22 -0700833 // Rule to generate the C++ source files
834 generateAndroidBpGenSection(
835 out,
836 packageFQName,
837 hidl_gen,
838 coordinator,
Tri Vo6a827fa2017-02-08 10:24:42 -0800839 halFilegroupName,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700840 genSourceName,
Steven Moreland1cbf0362017-05-09 14:32:53 -0700841 "c++-sources",
Dan Willemsen676abdc2016-09-28 19:42:22 -0700842 packageInterfaces,
Steven Morelandff5262b2017-03-20 06:59:03 -0700843 importedPackagesHierarchy,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700844 [&pathPrefix](Formatter &out, const FQName &fqName) {
845 if (fqName.name() == "types") {
846 out << "\"" << pathPrefix << "types.cpp\",\n";
847 } else {
848 out << "\"" << pathPrefix << fqName.name().substr(1) << "All.cpp\",\n";
849 }
850 });
851
852 // Rule to generate the C++ header files
853 generateAndroidBpGenSection(
854 out,
855 packageFQName,
856 hidl_gen,
857 coordinator,
Tri Vo6a827fa2017-02-08 10:24:42 -0800858 halFilegroupName,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700859 genHeaderName,
Steven Moreland1cbf0362017-05-09 14:32:53 -0700860 "c++-headers",
Dan Willemsen676abdc2016-09-28 19:42:22 -0700861 packageInterfaces,
Steven Morelandff5262b2017-03-20 06:59:03 -0700862 importedPackagesHierarchy,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700863 [&pathPrefix](Formatter &out, const FQName &fqName) {
864 out << "\"" << pathPrefix << fqName.name() << ".h\",\n";
865 if (fqName.name() != "types") {
Yifan Hongeefe4f22017-01-04 15:32:42 -0800866 out << "\"" << pathPrefix << fqName.getInterfaceHwName() << ".h\",\n";
867 out << "\"" << pathPrefix << fqName.getInterfaceStubName() << ".h\",\n";
868 out << "\"" << pathPrefix << fqName.getInterfaceProxyName() << ".h\",\n";
869 out << "\"" << pathPrefix << fqName.getInterfacePassthroughName() << ".h\",\n";
Steven Moreland9774d622017-03-24 21:51:45 -0700870 } else {
871 out << "\"" << pathPrefix << "hwtypes.h\",\n";
Dan Willemsen676abdc2016-09-28 19:42:22 -0700872 }
873 });
874
Steven Morelandf5f593f2017-05-02 13:13:00 -0700875 if (isHidlTransportPackage(packageFQName)) {
876 out << "// " << packageFQName.string() << " is exported from libhidltransport\n";
Steven Moreland0e875df2017-04-25 13:24:17 -0700877 } else {
Steven Moreland77cf7642017-06-15 14:49:39 -0700878 generateAndroidBpLibSection(
879 out,
880 false /* generateVendor */,
881 libraryName,
882 genSourceName,
883 genHeaderName,
884 importedPackagesHierarchy);
Dan Willemsen676abdc2016-09-28 19:42:22 -0700885
Steven Moreland77cf7642017-06-15 14:49:39 -0700886 // TODO(b/35813011): make all libraries vendor_available
887 // Explicitly create '_vendor' copies of libraries so that
888 // vendor code can link against the extensions. When this is
889 // used, framework code should link against vendor.awesome.foo@1.0
890 // and code on the vendor image should link against
891 // vendor.awesome.foo@1.0_vendor. For libraries with the below extensions,
892 // they will be available even on the generic system image.
893 // Because of this, they should always be referenced without the
894 // '_vendor' name suffix.
895 if (!(packageFQName.inPackage("android.hidl") ||
Steven Morelandf5f593f2017-05-02 13:13:00 -0700896 packageFQName.inPackage("android.system") ||
897 packageFQName.inPackage("android.frameworks") ||
Steven Moreland77cf7642017-06-15 14:49:39 -0700898 packageFQName.inPackage("android.hardware"))) {
899
900 // Note, not using cc_defaults here since it's already not used and
901 // because generating this libraries will be removed when the VNDK
902 // is enabled (done by the build system itself).
903 out.endl();
904 generateAndroidBpLibSection(
905 out,
906 true /* generateVendor */,
907 libraryName,
908 genSourceName,
909 genHeaderName,
910 importedPackagesHierarchy);
Steven Moreland1b2167b2017-05-01 10:06:21 -0700911 }
Yifan Hongc1f9b8d2016-11-07 14:35:44 -0800912 }
Dan Willemsen676abdc2016-09-28 19:42:22 -0700913
Zhuoyao Zhangb85e8c22016-12-21 10:24:16 -0800914 return OK;
Dan Willemsen676abdc2016-09-28 19:42:22 -0700915}
916
Yifan Hong958ee462016-12-06 17:09:51 -0800917static status_t generateAndroidBpImplForPackage(
Steven Moreland197d56c2016-09-09 10:03:58 -0700918 const FQName &packageFQName,
919 const char *,
920 Coordinator *coordinator,
921 const std::string &outputDir) {
922
Iliyan Malchev4923f932016-09-09 13:04:59 -0700923 const std::string libraryName = makeLibraryName(packageFQName) + "-impl";
Steven Moreland197d56c2016-09-09 10:03:58 -0700924
925 std::vector<FQName> packageInterfaces;
926
927 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700928 coordinator->appendPackageInterfacesToVector(packageFQName,
929 &packageInterfaces);
Steven Moreland197d56c2016-09-09 10:03:58 -0700930
931 if (err != OK) {
932 return err;
933 }
934
935 std::set<FQName> importedPackages;
936
937 for (const auto &fqName : packageInterfaces) {
938 AST *ast = coordinator->parse(fqName);
939
940 if (ast == NULL) {
941 fprintf(stderr,
942 "ERROR: Could not parse %s. Aborting.\n",
943 fqName.string().c_str());
944
945 return UNKNOWN_ERROR;
946 }
947
948 ast->getImportedPackages(&importedPackages);
949 }
950
Yifan Hongaafed702016-12-14 12:59:47 -0800951 std::string path = outputDir + "Android.bp";
Steven Moreland197d56c2016-09-09 10:03:58 -0700952
953 CHECK(Coordinator::MakeParentHierarchy(path));
954 FILE *file = fopen(path.c_str(), "w");
955
956 if (file == NULL) {
957 return -errno;
958 }
959
960 Formatter out(file);
961
Yifan Hong958ee462016-12-06 17:09:51 -0800962 out << "cc_library_shared {\n";
Yifan Hong33223ca2016-12-13 15:07:35 -0800963 out.indent([&] {
Yifan Hong958ee462016-12-06 17:09:51 -0800964 out << "name: \"" << libraryName << "\",\n"
965 << "relative_install_path: \"hw\",\n"
Steven Morelandf8a22e92017-02-15 18:46:04 -0800966 << "proprietary: true,\n"
Yifan Hong958ee462016-12-06 17:09:51 -0800967 << "srcs: [\n";
Yifan Hong33223ca2016-12-13 15:07:35 -0800968 out.indent([&] {
Yifan Hong958ee462016-12-06 17:09:51 -0800969 for (const auto &fqName : packageInterfaces) {
970 if (fqName.name() == "types") {
971 continue;
972 }
973 out << "\"" << fqName.getInterfaceBaseName() << ".cpp\",\n";
974 }
975 });
976 out << "],\n"
977 << "shared_libs: [\n";
Yifan Hong33223ca2016-12-13 15:07:35 -0800978 out.indent([&] {
Yifan Hong958ee462016-12-06 17:09:51 -0800979 out << "\"libhidlbase\",\n"
980 << "\"libhidltransport\",\n"
Yifan Hong958ee462016-12-06 17:09:51 -0800981 << "\"libutils\",\n"
982 << "\"" << makeLibraryName(packageFQName) << "\",\n";
Yifan Honge0f7d692016-10-20 17:51:33 -0700983
Yifan Hong958ee462016-12-06 17:09:51 -0800984 for (const auto &importedPackage : importedPackages) {
Steven Morelanddadd1842017-05-09 13:24:54 -0700985 if (isHidlTransportPackage(importedPackage)) {
986 continue;
987 }
988
Yifan Hong958ee462016-12-06 17:09:51 -0800989 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
990 }
991 });
992 out << "],\n";
993 });
994 out << "}\n";
Steven Moreland197d56c2016-09-09 10:03:58 -0700995
996 return OK;
997}
998
Steven Moreland05951b32017-05-12 17:22:22 -0700999bool validateForSource(
Andreas Huber0fa9e392016-08-31 09:05:44 -07001000 const FQName &fqName, const std::string &language) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001001 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -07001002 fprintf(stderr, "ERROR: Expecting package name\n");
Steven Moreland05951b32017-05-12 17:22:22 -07001003 return false;
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001004 }
1005
1006 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -07001007 fprintf(stderr, "ERROR: Expecting package version\n");
Steven Moreland05951b32017-05-12 17:22:22 -07001008 return false;
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001009 }
1010
Andreas Huber0fa9e392016-08-31 09:05:44 -07001011 const std::string &name = fqName.name();
1012 if (!name.empty()) {
1013 if (name.find('.') == std::string::npos) {
Steven Moreland05951b32017-05-12 17:22:22 -07001014 return true;
Andreas Huber0fa9e392016-08-31 09:05:44 -07001015 }
1016
1017 if (language != "java" || name.find("types.") != 0) {
1018 // When generating java sources for "types.hal", output can be
1019 // constrained to just one of the top-level types declared
1020 // by using the extended syntax
1021 // android.hardware.Foo@1.0::types.TopLevelTypeName.
1022 // In all other cases (different language, not 'types') the dot
1023 // notation in the name is illegal in this context.
Steven Moreland05951b32017-05-12 17:22:22 -07001024 return false;
Andreas Huber0fa9e392016-08-31 09:05:44 -07001025 }
1026
Steven Moreland05951b32017-05-12 17:22:22 -07001027 return true;
Andreas Huber0fa9e392016-08-31 09:05:44 -07001028 }
1029
Steven Moreland05951b32017-05-12 17:22:22 -07001030 return true;
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001031}
1032
Steven Morelandf47912d2017-05-12 16:25:44 -07001033OutputHandler::GenerationFunction generateExportHeaderForPackage(bool forJava) {
1034 return [forJava](const FQName &packageFQName,
1035 const char * /* hidl_gen */,
1036 Coordinator *coordinator,
1037 const std::string &outputPath) -> status_t {
1038 CHECK(packageFQName.isValid()
1039 && !packageFQName.package().empty()
1040 && !packageFQName.version().empty()
1041 && packageFQName.name().empty());
Andreas Huber019d21d2016-10-03 12:59:47 -07001042
Steven Morelandf47912d2017-05-12 16:25:44 -07001043 std::vector<FQName> packageInterfaces;
Andreas Huber019d21d2016-10-03 12:59:47 -07001044
Steven Morelandf47912d2017-05-12 16:25:44 -07001045 status_t err = coordinator->appendPackageInterfacesToVector(
1046 packageFQName, &packageInterfaces);
Andreas Huber019d21d2016-10-03 12:59:47 -07001047
Steven Morelandf47912d2017-05-12 16:25:44 -07001048 if (err != OK) {
1049 return err;
Andreas Huber019d21d2016-10-03 12:59:47 -07001050 }
1051
Steven Morelandf47912d2017-05-12 16:25:44 -07001052 std::vector<const Type *> exportedTypes;
Andreas Huber019d21d2016-10-03 12:59:47 -07001053
Steven Morelandf47912d2017-05-12 16:25:44 -07001054 for (const auto &fqName : packageInterfaces) {
1055 AST *ast = coordinator->parse(fqName);
1056
1057 if (ast == NULL) {
1058 fprintf(stderr,
1059 "ERROR: Could not parse %s. Aborting.\n",
1060 fqName.string().c_str());
1061
1062 return UNKNOWN_ERROR;
1063 }
1064
1065 ast->appendToExportedTypesVector(&exportedTypes);
1066 }
1067
1068 if (exportedTypes.empty()) {
1069 return OK;
1070 }
1071
1072 std::string path = outputPath;
1073
1074 if (forJava) {
1075 path.append(coordinator->convertPackageRootToPath(packageFQName));
1076
1077 path.append(coordinator->getPackagePath(
1078 packageFQName, true /* relative */, true /* sanitized */));
1079
1080 path.append("Constants.java");
1081 }
1082
1083 CHECK(Coordinator::MakeParentHierarchy(path));
1084 FILE *file = fopen(path.c_str(), "w");
1085
1086 if (file == nullptr) {
1087 return -errno;
1088 }
1089
1090 Formatter out(file);
1091
1092 out << "// This file is autogenerated by hidl-gen. Do not edit manually.\n"
1093 << "// Source: " << packageFQName.string() << "\n"
1094 << "// Root: " << coordinator->getPackageRootOption(packageFQName) << "\n\n";
1095
1096 std::string guard;
1097 if (forJava) {
1098 out << "package " << packageFQName.javaPackage() << ";\n\n";
1099 out << "public class Constants {\n";
1100 out.indent();
1101 } else {
1102 guard = "HIDL_GENERATED_";
1103 guard += StringHelper::Uppercase(packageFQName.tokenName());
1104 guard += "_";
1105 guard += "EXPORTED_CONSTANTS_H_";
1106
1107 out << "#ifndef "
1108 << guard
1109 << "\n#define "
1110 << guard
1111 << "\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n";
1112 }
1113
1114 for (const auto &type : exportedTypes) {
1115 type->emitExportedHeader(out, forJava);
1116 }
1117
1118 if (forJava) {
1119 out.unindent();
1120 out << "}\n";
1121 } else {
1122 out << "#ifdef __cplusplus\n}\n#endif\n\n#endif // "
1123 << guard
1124 << "\n";
1125 }
1126
Andreas Huber019d21d2016-10-03 12:59:47 -07001127 return OK;
Steven Morelandf47912d2017-05-12 16:25:44 -07001128 };
Andreas Huber019d21d2016-10-03 12:59:47 -07001129}
1130
Steven Morelandf2e44692017-04-18 20:19:09 -07001131static status_t generateHashOutput(const FQName &fqName,
1132 const char* /*hidl_gen*/,
1133 Coordinator *coordinator,
1134 const std::string & /*outputDir*/) {
1135
1136 status_t err;
1137 std::vector<FQName> packageInterfaces;
1138
1139 if (fqName.isFullyQualified()) {
1140 packageInterfaces = {fqName};
1141 } else {
1142 err = coordinator->appendPackageInterfacesToVector(
1143 fqName, &packageInterfaces);
1144 if (err != OK) {
1145 return err;
1146 }
1147 }
1148
1149 for (const auto &currentFqName : packageInterfaces) {
Steven Morelandc59326e2017-06-20 15:19:30 -07001150 AST* ast = coordinator->parse(currentFqName, {} /* parsed */,
1151 Coordinator::Enforce::NO_HASH /* enforcement */);
Steven Morelandf2e44692017-04-18 20:19:09 -07001152
1153 if (ast == NULL) {
1154 fprintf(stderr,
1155 "ERROR: Could not parse %s. Aborting.\n",
1156 currentFqName.string().c_str());
1157
1158 return UNKNOWN_ERROR;
1159 }
1160
1161 printf("%s %s\n",
1162 Hash::getHash(ast->getFilename()).hexString().c_str(),
1163 currentFqName.string().c_str());
1164 }
1165
1166 return OK;
1167}
1168
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001169static std::vector<OutputHandler> formats = {
Steven Moreland3b1ce262017-04-21 14:19:59 -07001170 {"check",
Steven Moreland97e52332017-05-12 16:47:19 -07001171 "Parses the interface to see if valid but doesn't write any files.",
Steven Moreland3b1ce262017-04-21 14:19:59 -07001172 OutputHandler::NOT_NEEDED /* mOutputMode */,
1173 validateForSource,
Steven Morelandbbbbeb82017-05-09 14:20:50 -07001174 generationFunctionForFileOrPackage("check")
Steven Moreland3b1ce262017-04-21 14:19:59 -07001175 },
1176
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001177 {"c++",
Steven Moreland97e52332017-05-12 16:47:19 -07001178 "(internal) (deprecated) Generates C++ interface files for talking to HIDL interfaces.",
Andreas Huber019d21d2016-10-03 12:59:47 -07001179 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001180 validateForSource,
Steven Morelandbbbbeb82017-05-09 14:20:50 -07001181 generationFunctionForFileOrPackage("c++")
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001182 },
1183
Steven Moreland1cbf0362017-05-09 14:32:53 -07001184 {"c++-headers",
Steven Moreland97e52332017-05-12 16:47:19 -07001185 "(internal) Generates C++ headers for interface files for talking to HIDL interfaces.",
Steven Moreland1cbf0362017-05-09 14:32:53 -07001186 OutputHandler::NEEDS_DIR /* mOutputMode */,
1187 validateForSource,
1188 generationFunctionForFileOrPackage("c++-headers")
1189 },
1190
1191 {"c++-sources",
Steven Moreland97e52332017-05-12 16:47:19 -07001192 "(internal) Generates C++ sources for interface files for talking to HIDL interfaces.",
Steven Moreland1cbf0362017-05-09 14:32:53 -07001193 OutputHandler::NEEDS_DIR /* mOutputMode */,
1194 validateForSource,
1195 generationFunctionForFileOrPackage("c++-sources")
1196 },
1197
Andreas Huber019d21d2016-10-03 12:59:47 -07001198 {"export-header",
Steven Moreland97e52332017-05-12 16:47:19 -07001199 "Generates a header file from @export enumerations to help maintain legacy code.",
Andreas Huber019d21d2016-10-03 12:59:47 -07001200 OutputHandler::NEEDS_FILE /* mOutputMode */,
Steven Moreland05951b32017-05-12 17:22:22 -07001201 validateIsPackage,
Steven Morelandf47912d2017-05-12 16:25:44 -07001202 generateExportHeaderForPackage(false /* forJava */)
Andreas Huber019d21d2016-10-03 12:59:47 -07001203 },
1204
Steven Moreland9c387612016-09-07 09:54:26 -07001205 {"c++-impl",
Steven Moreland97e52332017-05-12 16:47:19 -07001206 "Generates boilerplate implementation of a hidl interface in C++ (for convenience).",
Andreas Huber019d21d2016-10-03 12:59:47 -07001207 OutputHandler::NEEDS_DIR /* mOutputMode */,
Steven Moreland9c387612016-09-07 09:54:26 -07001208 validateForSource,
Steven Morelandbbbbeb82017-05-09 14:20:50 -07001209 generationFunctionForFileOrPackage("c++-impl")
Steven Moreland9c387612016-09-07 09:54:26 -07001210 },
1211
1212
Andreas Huber2831d512016-08-15 09:33:47 -07001213 {"java",
Steven Moreland97e52332017-05-12 16:47:19 -07001214 "(internal) Generates Java library for talking to HIDL interfaces in Java.",
Andreas Huber019d21d2016-10-03 12:59:47 -07001215 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001216 validateForSource,
Steven Morelandbbbbeb82017-05-09 14:20:50 -07001217 generationFunctionForFileOrPackage("java")
Andreas Huber2831d512016-08-15 09:33:47 -07001218 },
1219
Andreas Huber1c507272016-10-05 14:33:21 -07001220 {"java-constants",
Steven Moreland97e52332017-05-12 16:47:19 -07001221 "(internal) Like export-header but for Java (always created by -Lmakefile if @export exists).",
Andreas Huber1c507272016-10-05 14:33:21 -07001222 OutputHandler::NEEDS_DIR /* mOutputMode */,
Steven Moreland05951b32017-05-12 17:22:22 -07001223 validateIsPackage,
Steven Morelandf47912d2017-05-12 16:25:44 -07001224 generateExportHeaderForPackage(true /* forJava */)
Andreas Huber1c507272016-10-05 14:33:21 -07001225 },
1226
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001227 {"vts",
Steven Moreland97e52332017-05-12 16:47:19 -07001228 "(internal) Generates vts proto files for use in vtsd.",
Andreas Huber019d21d2016-10-03 12:59:47 -07001229 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001230 validateForSource,
Steven Morelandbbbbeb82017-05-09 14:20:50 -07001231 generationFunctionForFileOrPackage("vts")
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001232 },
1233
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001234 {"makefile",
Steven Moreland97e52332017-05-12 16:47:19 -07001235 "(internal) Generates makefiles for -Ljava and -Ljava-constants.",
Steven Morelanda171b562017-05-12 15:18:03 -07001236 OutputHandler::NEEDS_SRC /* mOutputMode */,
Steven Moreland05951b32017-05-12 17:22:22 -07001237 validateIsPackage,
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001238 generateMakefileForPackage,
1239 },
Steven Moreland197d56c2016-09-09 10:03:58 -07001240
Dan Willemsen676abdc2016-09-28 19:42:22 -07001241 {"androidbp",
Steven Moreland97e52332017-05-12 16:47:19 -07001242 "(internal) Generates Soong bp files for -Lc++-headers and -Lc++-sources.",
Steven Morelanda171b562017-05-12 15:18:03 -07001243 OutputHandler::NEEDS_SRC /* mOutputMode */,
Steven Moreland05951b32017-05-12 17:22:22 -07001244 validateIsPackage,
Dan Willemsen676abdc2016-09-28 19:42:22 -07001245 generateAndroidBpForPackage,
1246 },
1247
Yifan Hong958ee462016-12-06 17:09:51 -08001248 {"androidbp-impl",
Steven Moreland97e52332017-05-12 16:47:19 -07001249 "Generates boilerplate bp files for implementation created with -Lc++-impl.",
Yifan Hong94bcea02016-10-06 13:51:31 -07001250 OutputHandler::NEEDS_DIR /* mOutputMode */,
Steven Moreland05951b32017-05-12 17:22:22 -07001251 validateIsPackage,
Yifan Hong958ee462016-12-06 17:09:51 -08001252 generateAndroidBpImplForPackage,
Steven Morelandf2e44692017-04-18 20:19:09 -07001253 },
1254
1255 {"hash",
Steven Moreland97e52332017-05-12 16:47:19 -07001256 "Prints hashes of interface in `current.txt` format to standard out.",
Steven Morelandf2e44692017-04-18 20:19:09 -07001257 OutputHandler::NOT_NEEDED /* mOutputMode */,
1258 validateForSource,
1259 generateHashOutput,
1260 },
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001261};
1262
1263static void usage(const char *me) {
1264 fprintf(stderr,
Steven Moreland97e52332017-05-12 16:47:19 -07001265 "usage: %s [-p <root path>] -o <output path> -L <language> (-r <interface root>)+ fqname+\n",
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001266 me);
1267
Steven Moreland97e52332017-05-12 16:47:19 -07001268 fprintf(stderr, " -h: Prints this menu.\n");
1269 fprintf(stderr, " -L <language>: The following options are available:\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001270 for (auto &e : formats) {
Steven Moreland97e52332017-05-12 16:47:19 -07001271 fprintf(stderr, " %-16s: %s\n", e.name().c_str(), e.description().c_str());
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001272 }
Steven Moreland97e52332017-05-12 16:47:19 -07001273 fprintf(stderr, " -o <output path>: Location to output files.\n");
1274 fprintf(stderr, " -p <root path>: Android build root, defaults to $ANDROID_BUILD_TOP or pwd.\n");
1275 fprintf(stderr, " -r <package:path root>: E.g., android.hardware:hardware/interfaces.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001276}
1277
Andreas Gampec4ce9262017-04-27 21:03:20 -07001278// hidl is intentionally leaky. Turn off LeakSanitizer by default.
1279extern "C" const char *__asan_default_options() {
1280 return "detect_leaks=0";
1281}
1282
Andreas Huberb82318c2016-08-02 14:45:54 -07001283int main(int argc, char **argv) {
Andreas Huber019d21d2016-10-03 12:59:47 -07001284 std::string outputPath;
Steven Morelandf7fa0682017-05-11 16:14:55 -07001285 std::string rootPath;
Andreas Huberdca261f2016-08-04 13:47:51 -07001286 std::vector<std::string> packageRootPaths;
1287 std::vector<std::string> packageRoots;
Andreas Huberb82318c2016-08-02 14:45:54 -07001288
Andreas Huber737080b2016-08-02 15:38:04 -07001289 const char *me = argv[0];
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001290 OutputHandler *outputFormat = nullptr;
Andreas Huber737080b2016-08-02 15:38:04 -07001291
Steven Moreland3db99f22017-05-11 16:21:46 -07001292 if (argc == 1) {
1293 usage(me);
1294 exit(1);
1295 }
1296
Andreas Huberb82318c2016-08-02 14:45:54 -07001297 int res;
Steven Morelandf7fa0682017-05-11 16:14:55 -07001298 while ((res = getopt(argc, argv, "hp:o:r:L:")) >= 0) {
Andreas Huberb82318c2016-08-02 14:45:54 -07001299 switch (res) {
Steven Morelandf7fa0682017-05-11 16:14:55 -07001300 case 'p':
1301 {
1302 rootPath = optarg;
1303 break;
1304 }
1305
Andreas Huberb82318c2016-08-02 14:45:54 -07001306 case 'o':
1307 {
Andreas Huber019d21d2016-10-03 12:59:47 -07001308 outputPath = optarg;
Andreas Huberb82318c2016-08-02 14:45:54 -07001309 break;
1310 }
1311
Andreas Huberdca261f2016-08-04 13:47:51 -07001312 case 'r':
1313 {
1314 std::string val(optarg);
1315 auto index = val.find_first_of(':');
Steven Moreland4ff74202017-04-21 14:24:47 -07001316 if (index == std::string::npos) {
1317 fprintf(stderr, "ERROR: -r option must contain ':': %s\n", val.c_str());
1318 exit(1);
1319 }
Andreas Huberdca261f2016-08-04 13:47:51 -07001320
1321 auto package = val.substr(0, index);
1322 auto path = val.substr(index + 1);
1323 packageRootPaths.push_back(path);
1324 packageRoots.push_back(package);
1325 break;
1326 }
1327
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001328 case 'L':
1329 {
Steven Morelanddd583842017-04-19 13:09:57 -07001330 if (outputFormat != nullptr) {
1331 fprintf(stderr,
1332 "ERROR: only one -L option allowed. \"%s\" already specified.\n",
1333 outputFormat->name().c_str());
1334 exit(1);
1335 }
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001336 for (auto &e : formats) {
Steven Morelanddd583842017-04-19 13:09:57 -07001337 if (e.name() == optarg) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001338 outputFormat = &e;
1339 break;
1340 }
1341 }
Steven Morelanddd583842017-04-19 13:09:57 -07001342 if (outputFormat == nullptr) {
1343 fprintf(stderr,
1344 "ERROR: unrecognized -L option: \"%s\".\n",
1345 optarg);
1346 exit(1);
1347 }
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001348 break;
1349 }
1350
Andreas Huberb82318c2016-08-02 14:45:54 -07001351 case '?':
1352 case 'h':
1353 default:
1354 {
Andreas Huber737080b2016-08-02 15:38:04 -07001355 usage(me);
Andreas Huberb82318c2016-08-02 14:45:54 -07001356 exit(1);
1357 break;
1358 }
1359 }
1360 }
1361
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001362 if (outputFormat == nullptr) {
Steven Morelanddd583842017-04-19 13:09:57 -07001363 fprintf(stderr,
1364 "ERROR: no -L option provided.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001365 exit(1);
1366 }
1367
Andreas Huberb82318c2016-08-02 14:45:54 -07001368 argc -= optind;
1369 argv += optind;
1370
Steven Moreland3effa832017-06-16 16:17:41 -07001371 if (argc == 0) {
1372 fprintf(stderr, "ERROR: no fqname specified.\n");
1373 usage(me);
1374 exit(1);
1375 }
1376
Steven Morelandf7fa0682017-05-11 16:14:55 -07001377 if (rootPath.empty()) {
1378 const char *ANDROID_BUILD_TOP = getenv("ANDROID_BUILD_TOP");
1379
1380 if (ANDROID_BUILD_TOP != nullptr) {
1381 rootPath = ANDROID_BUILD_TOP;
1382 }
1383
1384 // else default to pwd
1385 }
1386
1387 if (!rootPath.empty() && !StringHelper::EndsWith(rootPath, "/")) {
1388 rootPath += "/";
1389 }
1390
Andreas Huber737080b2016-08-02 15:38:04 -07001391 // Valid options are now in argv[0] .. argv[argc - 1].
1392
Andreas Huber019d21d2016-10-03 12:59:47 -07001393 switch (outputFormat->mOutputMode) {
1394 case OutputHandler::NEEDS_DIR:
1395 case OutputHandler::NEEDS_FILE:
1396 {
1397 if (outputPath.empty()) {
1398 usage(me);
1399 exit(1);
1400 }
1401
1402 if (outputFormat->mOutputMode == OutputHandler::NEEDS_DIR) {
1403 const size_t len = outputPath.size();
1404 if (outputPath[len - 1] != '/') {
1405 outputPath += "/";
1406 }
1407 }
1408 break;
Andreas Huberb82318c2016-08-02 14:45:54 -07001409 }
Steven Morelanda171b562017-05-12 15:18:03 -07001410 case OutputHandler::NEEDS_SRC:
1411 {
1412 if (outputPath.empty()) {
1413 outputPath = rootPath;
1414 }
1415
1416 break;
1417 }
Andreas Huber019d21d2016-10-03 12:59:47 -07001418
1419 default:
1420 outputPath.clear(); // Unused.
1421 break;
Andreas Huberb82318c2016-08-02 14:45:54 -07001422 }
1423
Steven Morelandf7fa0682017-05-11 16:14:55 -07001424 Coordinator coordinator(packageRootPaths, packageRoots, rootPath);
Steven Moreland25c81662017-05-12 14:57:36 -07001425 coordinator.addDefaultPackagePath("android.hardware", "hardware/interfaces");
1426 coordinator.addDefaultPackagePath("android.hidl", "system/libhidl/transport");
1427 coordinator.addDefaultPackagePath("android.frameworks", "frameworks/hardware/interfaces");
1428 coordinator.addDefaultPackagePath("android.system", "system/hardware/interfaces");
Andreas Huber5345ec22016-07-29 13:33:27 -07001429
Andreas Huber737080b2016-08-02 15:38:04 -07001430 for (int i = 0; i < argc; ++i) {
Andreas Huber68f24592016-07-29 14:53:48 -07001431 FQName fqName(argv[i]);
Andreas Huber68f24592016-07-29 14:53:48 -07001432
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001433 if (!fqName.isValid()) {
Andreas Hubere61e3f72016-08-03 10:22:03 -07001434 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -07001435 "ERROR: Invalid fully-qualified name.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001436 exit(1);
1437 }
Andreas Huber881227d2016-08-02 14:20:21 -07001438
Steven Moreland05951b32017-05-12 17:22:22 -07001439 if (!outputFormat->validate(fqName, outputFormat->name())) {
Steven Morelandf2e44692017-04-18 20:19:09 -07001440 fprintf(stderr,
1441 "ERROR: output handler failed.\n");
Andreas Hubere61e3f72016-08-03 10:22:03 -07001442 exit(1);
1443 }
Andreas Huberd2943e12016-08-05 11:59:31 -07001444
1445 status_t err =
Andreas Huber019d21d2016-10-03 12:59:47 -07001446 outputFormat->generate(fqName, me, &coordinator, outputPath);
Andreas Huberd2943e12016-08-05 11:59:31 -07001447
1448 if (err != OK) {
Steven Moreland261370a2016-08-29 15:36:59 -07001449 exit(1);
Andreas Huberd2943e12016-08-05 11:59:31 -07001450 }
Andreas Hubereb1081f2016-07-28 13:13:24 -07001451 }
Andreas Huberc9410c72016-07-28 12:18:40 -07001452
Andreas Huberd2943e12016-08-05 11:59:31 -07001453 return 0;
Andreas Huberc9410c72016-07-28 12:18:40 -07001454}