blob: bece85e68c8ab03dcc95fed7eca765bc3ae73cad [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;
Andreas Huber019d21d2016-10-03 12:59:47 -070036 enum OutputMode {
37 NEEDS_DIR,
38 NEEDS_FILE,
Steven Morelanda171b562017-05-12 15:18:03 -070039 NEEDS_SRC, // for changes inside the source tree itself
Andreas Huber019d21d2016-10-03 12:59:47 -070040 NOT_NEEDED
41 } mOutputMode;
42
Iliyan Malchev5bb14022016-08-09 15:04:39 -070043 enum ValRes {
44 FAILED,
45 PASS_PACKAGE,
46 PASS_FULL
47 };
Steven Morelanddd583842017-04-19 13:09:57 -070048 const std::string& name() { return mKey; }
Steven Morelandbbbbeb82017-05-09 14:20:50 -070049
50 using ValidationFunction = std::function<ValRes(const FQName &, const std::string &language)>;
51 using GenerationFunction = std::function<status_t(const FQName &fqName,
52 const char *hidl_gen,
53 Coordinator *coordinator,
54 const std::string &outputDir)>;
55
56 ValidationFunction validate;
57 GenerationFunction generate;
Iliyan Malchev5bb14022016-08-09 15:04:39 -070058};
Andreas Huberdca261f2016-08-04 13:47:51 -070059
Iliyan Malchev5bb14022016-08-09 15:04:39 -070060static status_t generateSourcesForFile(
61 const FQName &fqName,
62 const char *,
63 Coordinator *coordinator,
Andreas Huber2831d512016-08-15 09:33:47 -070064 const std::string &outputDir,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070065 const std::string &lang) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -070066 CHECK(fqName.isFullyQualified());
67
Andreas Huber0fa9e392016-08-31 09:05:44 -070068 AST *ast;
Andreas Huberd29724f2016-09-14 09:33:13 -070069 std::string limitToType;
Andreas Huber0fa9e392016-08-31 09:05:44 -070070
71 if (fqName.name().find("types.") == 0) {
72 CHECK(lang == "java"); // Already verified in validate().
73
Andreas Huberd29724f2016-09-14 09:33:13 -070074 limitToType = fqName.name().substr(strlen("types."));
Andreas Huber0fa9e392016-08-31 09:05:44 -070075
Yifan Hongfece6ec2017-01-12 17:04:04 -080076 FQName typesName = fqName.getTypesForPackage();
Andreas Huber0fa9e392016-08-31 09:05:44 -070077 ast = coordinator->parse(typesName);
78 } else {
79 ast = coordinator->parse(fqName);
80 }
Iliyan Malchev5bb14022016-08-09 15:04:39 -070081
82 if (ast == NULL) {
83 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -070084 "ERROR: Could not parse %s. Aborting.\n",
Iliyan Malchev5bb14022016-08-09 15:04:39 -070085 fqName.string().c_str());
86
87 return UNKNOWN_ERROR;
88 }
89
Steven Moreland3b1ce262017-04-21 14:19:59 -070090 if (lang == "check") {
91 return OK; // only parsing, not generating
92 }
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070093 if (lang == "c++") {
94 return ast->generateCpp(outputDir);
95 }
Steven Moreland1cbf0362017-05-09 14:32:53 -070096 if (lang == "c++-headers") {
97 return ast->generateCppHeaders(outputDir);
98 }
99 if (lang == "c++-sources") {
100 return ast->generateCppSources(outputDir);
101 }
Steven Moreland9c387612016-09-07 09:54:26 -0700102 if (lang == "c++-impl") {
103 return ast->generateCppImpl(outputDir);
104 }
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700105 if (lang == "java") {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700106 return ast->generateJava(outputDir, limitToType);
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700107 }
108 if (lang == "vts") {
109 return ast->generateVts(outputDir);
110 }
111 // Unknown language.
112 return UNKNOWN_ERROR;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700113}
114
115static status_t generateSourcesForPackage(
116 const FQName &packageFQName,
117 const char *hidl_gen,
118 Coordinator *coordinator,
Andreas Huber2831d512016-08-15 09:33:47 -0700119 const std::string &outputDir,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700120 const std::string &lang) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700121 CHECK(packageFQName.isValid() &&
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700122 !packageFQName.isFullyQualified() &&
123 packageFQName.name().empty());
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700124
125 std::vector<FQName> packageInterfaces;
126
127 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700128 coordinator->appendPackageInterfacesToVector(packageFQName,
129 &packageInterfaces);
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700130
131 if (err != OK) {
132 return err;
133 }
134
135 for (const auto &fqName : packageInterfaces) {
Andreas Huber2831d512016-08-15 09:33:47 -0700136 err = generateSourcesForFile(
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700137 fqName, hidl_gen, coordinator, outputDir, lang);
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700138 if (err != OK) {
139 return err;
140 }
141 }
142
143 return OK;
Andreas Huberb82318c2016-08-02 14:45:54 -0700144}
145
Steven Morelandbbbbeb82017-05-09 14:20:50 -0700146OutputHandler::GenerationFunction generationFunctionForFileOrPackage(const std::string &language) {
147 return [language](const FQName &fqName,
148 const char *hidl_gen, Coordinator *coordinator,
149 const std::string &outputDir) -> status_t {
150 if (fqName.isFullyQualified()) {
151 return generateSourcesForFile(fqName,
152 hidl_gen,
153 coordinator,
154 outputDir,
155 language);
156 } else {
157 return generateSourcesForPackage(fqName,
158 hidl_gen,
159 coordinator,
160 outputDir,
161 language);
162 }
163 };
164}
165
Andreas Huberd2943e12016-08-05 11:59:31 -0700166static std::string makeLibraryName(const FQName &packageFQName) {
Iliyan Malcheve2c595a2016-08-07 21:20:04 -0700167 return packageFQName.string();
Andreas Huberd2943e12016-08-05 11:59:31 -0700168}
169
Andreas Huberaa573272017-04-13 09:58:06 -0700170static std::string makeJavaLibraryName(const FQName &packageFQName) {
171 std::string out;
172 out = packageFQName.package();
173 out += "-V";
174 out += packageFQName.version();
175 return out;
176}
177
Steven Moreland5715fed2017-01-16 11:06:47 -0800178static void generatePackagePathsSection(
179 Formatter &out,
180 Coordinator *coordinator,
181 const FQName &packageFQName,
182 const std::set<FQName> &importedPackages,
183 bool forMakefiles = false) {
184 std::set<std::string> options{};
185 for (const auto &interface : importedPackages) {
186 options.insert(coordinator->getPackageRootOption(interface));
187 }
188 options.insert(coordinator->getPackageRootOption(packageFQName));
189 options.insert(coordinator->getPackageRootOption(gIBasePackageFqName));
190 for (const auto &option : options) {
191 out << "-r"
192 << option
193 << " ";
194 if (forMakefiles) {
195 out << "\\\n";
196 }
197 }
198}
199
Dan Willemsen676abdc2016-09-28 19:42:22 -0700200static void generateMakefileSectionForType(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700201 Formatter &out,
202 Coordinator *coordinator,
203 const FQName &packageFQName,
204 const FQName &fqName,
Steven Moreland5715fed2017-01-16 11:06:47 -0800205 const std::set<FQName> &importedPackages,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700206 const char *typeName) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700207 out << "\n"
208 << "\n#"
209 << "\n# Build " << fqName.name() << ".hal";
210
Dan Willemsen676abdc2016-09-28 19:42:22 -0700211 if (typeName != nullptr) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700212 out << " (" << typeName << ")";
213 }
214
215 out << "\n#"
216 << "\nGEN := $(intermediates)/"
217 << coordinator->convertPackageRootToPath(packageFQName)
Yifan Hong97288ac2016-12-12 16:03:51 -0800218 << coordinator->getPackagePath(packageFQName, true /* relative */,
219 true /* sanitized */);
Dan Willemsen676abdc2016-09-28 19:42:22 -0700220 if (typeName == nullptr) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700221 out << fqName.name() << ".java";
222 } else {
223 out << typeName << ".java";
224 }
225
226 out << "\n$(GEN): $(HIDL)";
227 out << "\n$(GEN): PRIVATE_HIDL := $(HIDL)";
228 out << "\n$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/"
229 << fqName.name() << ".hal";
Iliyan Malchevb9819132016-09-07 12:38:31 -0700230
231 {
232 AST *ast = coordinator->parse(fqName);
233 CHECK(ast != nullptr);
234 const std::set<FQName>& refs = ast->getImportedNames();
235 for (auto depFQName : refs) {
236 // If the package of depFQName is the same as this fqName's package,
237 // then add it explicitly as a .hal dependency within the same
238 // package.
239 if (fqName.package() == depFQName.package() &&
240 fqName.version() == depFQName.version()) {
241 // PRIVATE_DEPS is not actually being used in the
242 // auto-generated file, but is necessary if the build rule
243 // ever needs to use the dependency information, since the
244 // built-in Make variables are not supported in the Android
245 // build system.
246 out << "\n$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/"
247 << depFQName.name() << ".hal";
248 // This is the actual dependency.
249 out << "\n$(GEN): $(LOCAL_PATH)/"
250 << depFQName.name() << ".hal";
251 }
252 }
253 }
254
Andreas Huber0fa9e392016-08-31 09:05:44 -0700255 out << "\n$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)"
256 << "\n$(GEN): PRIVATE_CUSTOM_TOOL = \\";
257 out.indent();
258 out.indent();
259 out << "\n$(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \\"
Steven Moreland5715fed2017-01-16 11:06:47 -0800260 << "\n-Ljava \\\n";
261
262 generatePackagePathsSection(out, coordinator, packageFQName, importedPackages, true /* forJava */);
Andreas Huber0fa9e392016-08-31 09:05:44 -0700263
264 out << packageFQName.string()
265 << "::"
266 << fqName.name();
267
Dan Willemsen676abdc2016-09-28 19:42:22 -0700268 if (typeName != nullptr) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700269 out << "." << typeName;
270 }
271
272 out << "\n";
273
274 out.unindent();
275 out.unindent();
276
277 out << "\n$(GEN): $(LOCAL_PATH)/" << fqName.name() << ".hal";
278 out << "\n\t$(transform-generated-source)";
279 out << "\nLOCAL_GENERATED_SOURCES += $(GEN)";
280}
281
Dan Willemsen676abdc2016-09-28 19:42:22 -0700282static void generateMakefileSection(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700283 Formatter &out,
284 Coordinator *coordinator,
285 const FQName &packageFQName,
286 const std::vector<FQName> &packageInterfaces,
Steven Moreland5715fed2017-01-16 11:06:47 -0800287 const std::set<FQName> &importedPackages,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700288 AST *typesAST) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700289 for (const auto &fqName : packageInterfaces) {
Dan Willemsen676abdc2016-09-28 19:42:22 -0700290 if (fqName.name() == "types") {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700291 CHECK(typesAST != nullptr);
292
293 Scope *rootScope = typesAST->scope();
Andreas Huber0fa9e392016-08-31 09:05:44 -0700294
Andreas Huberb747bd92016-09-26 15:55:31 -0700295 std::vector<NamedType *> subTypes = rootScope->getSubTypes();
296 std::sort(
297 subTypes.begin(),
298 subTypes.end(),
299 [](const NamedType *a, const NamedType *b) -> bool {
300 return a->fqName() < b->fqName();
301 });
302
303 for (const auto &type : subTypes) {
Andreas Huberdda25cc2016-09-22 10:39:47 -0700304 if (type->isTypeDef()) {
305 continue;
306 }
307
Dan Willemsen676abdc2016-09-28 19:42:22 -0700308 generateMakefileSectionForType(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700309 out,
310 coordinator,
311 packageFQName,
312 fqName,
Steven Moreland5715fed2017-01-16 11:06:47 -0800313 importedPackages,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700314 type->localName().c_str());
Andreas Huber0fa9e392016-08-31 09:05:44 -0700315 }
316
317 continue;
318 }
319
Dan Willemsen676abdc2016-09-28 19:42:22 -0700320 generateMakefileSectionForType(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700321 out,
322 coordinator,
323 packageFQName,
324 fqName,
Steven Moreland5715fed2017-01-16 11:06:47 -0800325 importedPackages,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700326 nullptr /* typeName */);
Andreas Huber0fa9e392016-08-31 09:05:44 -0700327 }
328}
329
Andreas Huber75ae95d2016-10-12 16:08:26 -0700330static status_t isPackageJavaCompatible(
331 const FQName &packageFQName,
332 Coordinator *coordinator,
333 bool *compatible) {
334 std::vector<FQName> todo;
335 status_t err =
336 coordinator->appendPackageInterfacesToVector(packageFQName, &todo);
337
338 if (err != OK) {
339 return err;
340 }
341
342 std::set<FQName> seen;
343 for (const auto &iface : todo) {
344 seen.insert(iface);
345 }
346
347 // Form the transitive closure of all imported interfaces (and types.hal-s)
348 // If any one of them is not java compatible, this package isn't either.
349 while (!todo.empty()) {
350 const FQName fqName = todo.back();
351 todo.pop_back();
352
353 AST *ast = coordinator->parse(fqName);
354
355 if (ast == nullptr) {
356 return UNKNOWN_ERROR;
357 }
358
359 if (!ast->isJavaCompatible()) {
360 *compatible = false;
361 return OK;
362 }
363
364 std::set<FQName> importedPackages;
365 ast->getImportedPackages(&importedPackages);
366
367 for (const auto &package : importedPackages) {
368 std::vector<FQName> packageInterfaces;
369 status_t err = coordinator->appendPackageInterfacesToVector(
370 package, &packageInterfaces);
371
372 if (err != OK) {
373 return err;
374 }
375
376 for (const auto &iface : packageInterfaces) {
377 if (seen.find(iface) != seen.end()) {
378 continue;
379 }
380
381 todo.push_back(iface);
382 seen.insert(iface);
383 }
384 }
385 }
386
387 *compatible = true;
388 return OK;
389}
390
Andreas Huber5a9fe2c2016-10-13 15:31:10 -0700391static bool packageNeedsJavaCode(
392 const std::vector<FQName> &packageInterfaces, AST *typesAST) {
393 // If there is more than just a types.hal file to this package we'll
394 // definitely need to generate Java code.
395 if (packageInterfaces.size() > 1
396 || packageInterfaces[0].name() != "types") {
397 return true;
398 }
399
400 CHECK(typesAST != nullptr);
401
402 // We'll have to generate Java code if types.hal contains any non-typedef
403 // type declarations.
404
405 Scope *rootScope = typesAST->scope();
406 std::vector<NamedType *> subTypes = rootScope->getSubTypes();
407
408 for (const auto &subType : subTypes) {
409 if (!subType->isTypeDef()) {
410 return true;
411 }
412 }
413
414 return false;
415}
416
Andreas Huber1c507272016-10-05 14:33:21 -0700417static void generateMakefileSectionForJavaConstants(
418 Formatter &out,
419 Coordinator *coordinator,
420 const FQName &packageFQName,
Steven Moreland5715fed2017-01-16 11:06:47 -0800421 const std::vector<FQName> &packageInterfaces,
422 const std::set<FQName> &importedPackages) {
Andreas Huber1c507272016-10-05 14:33:21 -0700423 out << "\n#"
424 << "\nGEN := $(intermediates)/"
425 << coordinator->convertPackageRootToPath(packageFQName)
Yifan Hong97288ac2016-12-12 16:03:51 -0800426 << coordinator->getPackagePath(packageFQName, true /* relative */, true /* sanitized */)
Andreas Huber1c507272016-10-05 14:33:21 -0700427 << "Constants.java";
428
429 out << "\n$(GEN): $(HIDL)\n";
430 for (const auto &iface : packageInterfaces) {
431 out << "$(GEN): $(LOCAL_PATH)/" << iface.name() << ".hal\n";
432 }
433 out << "\n$(GEN): PRIVATE_HIDL := $(HIDL)";
434 out << "\n$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)"
435 << "\n$(GEN): PRIVATE_CUSTOM_TOOL = \\";
436 out.indent();
437 out.indent();
438 out << "\n$(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \\"
Steven Moreland5715fed2017-01-16 11:06:47 -0800439 << "\n-Ljava-constants \\\n";
440
441 generatePackagePathsSection(out, coordinator, packageFQName, importedPackages, true /* forJava */);
Andreas Huber1c507272016-10-05 14:33:21 -0700442
443 out << packageFQName.string();
444 out << "\n";
445
446 out.unindent();
447 out.unindent();
448
449 out << "\n$(GEN):";
450 out << "\n\t$(transform-generated-source)";
451 out << "\nLOCAL_GENERATED_SOURCES += $(GEN)";
452}
453
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700454static status_t generateMakefileForPackage(
455 const FQName &packageFQName,
Iliyan Malchevb66c3992016-08-07 21:18:13 -0700456 const char *hidl_gen,
Andreas Huberd2943e12016-08-05 11:59:31 -0700457 Coordinator *coordinator,
Steven Morelanda171b562017-05-12 15:18:03 -0700458 const std::string &outputPath) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700459
460 CHECK(packageFQName.isValid() &&
461 !packageFQName.isFullyQualified() &&
462 packageFQName.name().empty());
463
Andreas Huberd2943e12016-08-05 11:59:31 -0700464 std::vector<FQName> packageInterfaces;
465
466 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700467 coordinator->appendPackageInterfacesToVector(packageFQName,
468 &packageInterfaces);
Andreas Huberd2943e12016-08-05 11:59:31 -0700469
470 if (err != OK) {
471 return err;
472 }
473
474 std::set<FQName> importedPackages;
Andreas Huber0fa9e392016-08-31 09:05:44 -0700475 AST *typesAST = nullptr;
Andreas Huber1c507272016-10-05 14:33:21 -0700476 std::vector<const Type *> exportedTypes;
Andreas Huber0fa9e392016-08-31 09:05:44 -0700477
Andreas Huberd2943e12016-08-05 11:59:31 -0700478 for (const auto &fqName : packageInterfaces) {
479 AST *ast = coordinator->parse(fqName);
480
481 if (ast == NULL) {
482 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700483 "ERROR: Could not parse %s. Aborting.\n",
Andreas Huberd2943e12016-08-05 11:59:31 -0700484 fqName.string().c_str());
485
486 return UNKNOWN_ERROR;
487 }
488
Andreas Huber0fa9e392016-08-31 09:05:44 -0700489 if (fqName.name() == "types") {
490 typesAST = ast;
491 }
492
Yifan Hong40a373d2016-11-30 15:16:47 -0800493 ast->getImportedPackagesHierarchy(&importedPackages);
Andreas Huber1c507272016-10-05 14:33:21 -0700494 ast->appendToExportedTypesVector(&exportedTypes);
Andreas Huberd2943e12016-08-05 11:59:31 -0700495 }
496
Andreas Huber75ae95d2016-10-12 16:08:26 -0700497 bool packageIsJavaCompatible;
498 err = isPackageJavaCompatible(
499 packageFQName, coordinator, &packageIsJavaCompatible);
500
501 if (err != OK) {
502 return err;
503 }
504
Andreas Huber1c507272016-10-05 14:33:21 -0700505 bool haveJavaConstants = !exportedTypes.empty();
506
507 if (!packageIsJavaCompatible && !haveJavaConstants) {
Steven Moreland81979932016-12-07 15:11:06 -0800508 // TODO(b/33420795)
509 fprintf(stderr,
510 "WARNING: %s is not java compatible. No java makefile created.\n",
511 packageFQName.string().c_str());
Dan Willemsen676abdc2016-09-28 19:42:22 -0700512 return OK;
513 }
514
Andreas Huber5a9fe2c2016-10-13 15:31:10 -0700515 if (!packageNeedsJavaCode(packageInterfaces, typesAST)) {
516 return OK;
517 }
518
Steven Morelanda171b562017-05-12 15:18:03 -0700519 std::string path = outputPath;
Steven Morelandf7fa0682017-05-11 16:14:55 -0700520 path.append(coordinator->getPackagePath(packageFQName, false /* relative */));
Andreas Huberd2943e12016-08-05 11:59:31 -0700521 path.append("Android.mk");
522
523 CHECK(Coordinator::MakeParentHierarchy(path));
524 FILE *file = fopen(path.c_str(), "w");
525
526 if (file == NULL) {
527 return -errno;
528 }
529
Andreas Huberaa573272017-04-13 09:58:06 -0700530 const std::string libraryName = makeJavaLibraryName(packageFQName);
Andreas Huberd2943e12016-08-05 11:59:31 -0700531
532 Formatter out(file);
533
Dan Willemsen676abdc2016-09-28 19:42:22 -0700534 out << "# This file is autogenerated by hidl-gen. Do not edit manually.\n\n";
535 out << "LOCAL_PATH := $(call my-dir)\n";
Andreas Huberd2943e12016-08-05 11:59:31 -0700536
Dan Willemsen676abdc2016-09-28 19:42:22 -0700537 enum LibraryStyle {
538 LIBRARY_STYLE_REGULAR,
539 LIBRARY_STYLE_STATIC,
540 LIBRARY_STYLE_END,
541 };
Andreas Huberd2943e12016-08-05 11:59:31 -0700542
Andreas Huber1c507272016-10-05 14:33:21 -0700543 for (int style = LIBRARY_STYLE_REGULAR;
544 (packageIsJavaCompatible && style != LIBRARY_STYLE_END);
Dan Willemsen676abdc2016-09-28 19:42:22 -0700545 ++style) {
546 const std::string staticSuffix =
547 (style == LIBRARY_STYLE_STATIC) ? "-static" : "";
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700548
Dan Willemsen676abdc2016-09-28 19:42:22 -0700549 out << "\n"
550 << "########################################"
551 << "########################################\n\n";
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700552
Dan Willemsen676abdc2016-09-28 19:42:22 -0700553 out << "include $(CLEAR_VARS)\n"
554 << "LOCAL_MODULE := "
555 << libraryName
556 << "-java"
557 << staticSuffix
558 << "\nLOCAL_MODULE_CLASS := JAVA_LIBRARIES\n\n"
Andreas Huber177a8b12017-02-09 10:08:48 -0800559 << "intermediates := $(call local-generated-sources-dir, COMMON)"
560 << "\n\n"
Dan Willemsen676abdc2016-09-28 19:42:22 -0700561 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
562 << hidl_gen
563 << "$(HOST_EXECUTABLE_SUFFIX)";
Andreas Huberd2943e12016-08-05 11:59:31 -0700564
Dan Willemsen676abdc2016-09-28 19:42:22 -0700565 if (!importedPackages.empty()) {
Iliyan Malchev800273d2016-09-02 15:25:07 -0700566 out << "\n"
Dan Willemsen676abdc2016-09-28 19:42:22 -0700567 << "\nLOCAL_"
Andreas Huber782d45e2016-09-22 13:25:14 -0700568 << ((style == LIBRARY_STYLE_STATIC) ? "STATIC_" : "")
Dan Willemsen676abdc2016-09-28 19:42:22 -0700569 << "JAVA_LIBRARIES := \\";
570
571 out.indent();
572 for (const auto &importedPackage : importedPackages) {
573 out << "\n"
Andreas Huberaa573272017-04-13 09:58:06 -0700574 << makeJavaLibraryName(importedPackage)
Dan Willemsen676abdc2016-09-28 19:42:22 -0700575 << "-java"
576 << staticSuffix
577 << " \\";
578 }
579 out << "\n";
580 out.unindent();
Iliyan Malchev800273d2016-09-02 15:25:07 -0700581 }
Dan Willemsen676abdc2016-09-28 19:42:22 -0700582
583 generateMakefileSection(
584 out,
585 coordinator,
586 packageFQName,
587 packageInterfaces,
Steven Moreland5715fed2017-01-16 11:06:47 -0800588 importedPackages,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700589 typesAST);
590
591 out << "\ninclude $(BUILD_"
592 << ((style == LIBRARY_STYLE_STATIC) ? "STATIC_" : "")
593 << "JAVA_LIBRARY)\n\n";
Andreas Huber0fa9e392016-08-31 09:05:44 -0700594 }
595
Andreas Huber1c507272016-10-05 14:33:21 -0700596 if (haveJavaConstants) {
597 out << "\n"
598 << "########################################"
599 << "########################################\n\n";
600
601 out << "include $(CLEAR_VARS)\n"
602 << "LOCAL_MODULE := "
603 << libraryName
604 << "-java-constants"
605 << "\nLOCAL_MODULE_CLASS := JAVA_LIBRARIES\n\n"
Andreas Huber177a8b12017-02-09 10:08:48 -0800606 << "intermediates := $(call local-generated-sources-dir, COMMON)"
607 << "\n\n"
Andreas Huber1c507272016-10-05 14:33:21 -0700608 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
609 << hidl_gen
610 << "$(HOST_EXECUTABLE_SUFFIX)";
611
612 generateMakefileSectionForJavaConstants(
Steven Moreland5715fed2017-01-16 11:06:47 -0800613 out, coordinator, packageFQName, packageInterfaces, importedPackages);
Andreas Huber1c507272016-10-05 14:33:21 -0700614
615 out << "\n# Avoid dependency cycle of framework.jar -> this-library "
616 << "-> framework.jar\n"
617 << "LOCAL_NO_STANDARD_LIBRARIES := true\n"
618 << "LOCAL_JAVA_LIBRARIES := core-oj\n\n"
619 << "include $(BUILD_STATIC_JAVA_LIBRARY)\n\n";
620 }
621
Iliyan Malchev8be09552016-09-22 16:20:33 -0700622 out << "\n\n"
623 << "include $(call all-makefiles-under,$(LOCAL_PATH))\n";
624
Andreas Huberd2943e12016-08-05 11:59:31 -0700625 return OK;
626}
627
Andreas Huber0fa9e392016-08-31 09:05:44 -0700628OutputHandler::ValRes validateForMakefile(
629 const FQName &fqName, const std::string & /* language */) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700630 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700631 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700632 return OutputHandler::FAILED;
633 }
634
635 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700636 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700637 return OutputHandler::FAILED;
638 }
639
640 if (!fqName.name().empty()) {
641 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700642 "ERROR: Expecting only package name and version.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700643 return OutputHandler::FAILED;
644 }
645
646 return OutputHandler::PASS_PACKAGE;
647}
648
Dan Willemsen676abdc2016-09-28 19:42:22 -0700649static void generateAndroidBpGenSection(
650 Formatter &out,
651 const FQName &packageFQName,
652 const char *hidl_gen,
653 Coordinator *coordinator,
Tri Vo6a827fa2017-02-08 10:24:42 -0800654 const std::string &halFilegroupName,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700655 const std::string &genName,
656 const char *language,
657 const std::vector<FQName> &packageInterfaces,
Steven Moreland5715fed2017-01-16 11:06:47 -0800658 const std::set<FQName> &importedPackages,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700659 const std::function<void(Formatter&, const FQName)> outputFn) {
660
661 out << "genrule {\n";
662 out.indent();
663 out << "name: \"" << genName << "\",\n"
Colin Crossd5419bd2016-11-04 15:05:54 -0700664 << "tools: [\"" << hidl_gen << "\"],\n";
Dan Willemsen676abdc2016-09-28 19:42:22 -0700665
Colin Crossd5419bd2016-11-04 15:05:54 -0700666 out << "cmd: \"$(location " << hidl_gen << ") -o $(genDir)"
Steven Moreland5715fed2017-01-16 11:06:47 -0800667 << " -L" << language << " ";
668
669 generatePackagePathsSection(out, coordinator, packageFQName, importedPackages);
670
671 out << packageFQName.string() << "\",\n";
Dan Willemsen676abdc2016-09-28 19:42:22 -0700672
673 out << "srcs: [\n";
674 out.indent();
Tri Vo6a827fa2017-02-08 10:24:42 -0800675 out << "\":" << halFilegroupName << "\",\n";
Dan Willemsen676abdc2016-09-28 19:42:22 -0700676 out.unindent();
677 out << "],\n";
678
679 out << "out: [\n";
680 out.indent();
681 for (const auto &fqName : packageInterfaces) {
682 outputFn(out, fqName);
683 }
684 out.unindent();
685 out << "],\n";
686
687 out.unindent();
688 out << "}\n\n";
689}
690
Steven Moreland1b2167b2017-05-01 10:06:21 -0700691bool isHidlTransportPackage(const FQName &package) {
692 return package == gIBasePackageFqName ||
693 package == gIManagerPackageFqName;
694}
695
Dan Willemsen676abdc2016-09-28 19:42:22 -0700696static status_t generateAndroidBpForPackage(
697 const FQName &packageFQName,
698 const char *hidl_gen,
699 Coordinator *coordinator,
Steven Morelanda171b562017-05-12 15:18:03 -0700700 const std::string &outputPath) {
Dan Willemsen676abdc2016-09-28 19:42:22 -0700701
702 CHECK(packageFQName.isValid() &&
703 !packageFQName.isFullyQualified() &&
704 packageFQName.name().empty());
705
706 std::vector<FQName> packageInterfaces;
707
708 status_t err =
709 coordinator->appendPackageInterfacesToVector(packageFQName,
710 &packageInterfaces);
711
712 if (err != OK) {
713 return err;
714 }
715
Steven Morelandff5262b2017-03-20 06:59:03 -0700716 std::set<FQName> importedPackagesHierarchy;
Dan Willemsen676abdc2016-09-28 19:42:22 -0700717 AST *typesAST = nullptr;
718
719 for (const auto &fqName : packageInterfaces) {
720 AST *ast = coordinator->parse(fqName);
721
722 if (ast == NULL) {
723 fprintf(stderr,
724 "ERROR: Could not parse %s. Aborting.\n",
725 fqName.string().c_str());
726
727 return UNKNOWN_ERROR;
728 }
729
730 if (fqName.name() == "types") {
731 typesAST = ast;
732 }
733
Steven Morelandff5262b2017-03-20 06:59:03 -0700734 ast->getImportedPackagesHierarchy(&importedPackagesHierarchy);
Dan Willemsen676abdc2016-09-28 19:42:22 -0700735 }
736
Steven Morelanda171b562017-05-12 15:18:03 -0700737 std::string path = outputPath;
Steven Morelandf7fa0682017-05-11 16:14:55 -0700738 path.append(coordinator->getPackagePath(packageFQName, false /* relative */));
Dan Willemsen676abdc2016-09-28 19:42:22 -0700739 path.append("Android.bp");
740
741 CHECK(Coordinator::MakeParentHierarchy(path));
742 FILE *file = fopen(path.c_str(), "w");
743
744 if (file == NULL) {
745 return -errno;
746 }
747
748 const std::string libraryName = makeLibraryName(packageFQName);
Tri Vo15052c62017-02-06 10:04:07 -0800749 const std::string halFilegroupName = libraryName + "_hal";
Dan Willemsen676abdc2016-09-28 19:42:22 -0700750 const std::string genSourceName = libraryName + "_genc++";
751 const std::string genHeaderName = libraryName + "_genc++_headers";
752 const std::string pathPrefix =
753 coordinator->convertPackageRootToPath(packageFQName) +
754 coordinator->getPackagePath(packageFQName, true /* relative */);
755
756 Formatter out(file);
757
758 out << "// This file is autogenerated by hidl-gen. Do not edit manually.\n\n";
759
Tri Vo15052c62017-02-06 10:04:07 -0800760 // Rule to generate .hal filegroup
761 out << "filegroup {\n";
762 out.indent();
763 out << "name: \"" << halFilegroupName << "\",\n";
764 out << "srcs: [\n";
765 out.indent();
766 for (const auto &fqName : packageInterfaces) {
767 out << "\"" << fqName.name() << ".hal\",\n";
768 }
769 out.unindent();
770 out << "],\n";
771 out.unindent();
772 out << "}\n\n";
773
Dan Willemsen676abdc2016-09-28 19:42:22 -0700774 // Rule to generate the C++ source files
775 generateAndroidBpGenSection(
776 out,
777 packageFQName,
778 hidl_gen,
779 coordinator,
Tri Vo6a827fa2017-02-08 10:24:42 -0800780 halFilegroupName,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700781 genSourceName,
Steven Moreland1cbf0362017-05-09 14:32:53 -0700782 "c++-sources",
Dan Willemsen676abdc2016-09-28 19:42:22 -0700783 packageInterfaces,
Steven Morelandff5262b2017-03-20 06:59:03 -0700784 importedPackagesHierarchy,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700785 [&pathPrefix](Formatter &out, const FQName &fqName) {
786 if (fqName.name() == "types") {
787 out << "\"" << pathPrefix << "types.cpp\",\n";
788 } else {
789 out << "\"" << pathPrefix << fqName.name().substr(1) << "All.cpp\",\n";
790 }
791 });
792
793 // Rule to generate the C++ header files
794 generateAndroidBpGenSection(
795 out,
796 packageFQName,
797 hidl_gen,
798 coordinator,
Tri Vo6a827fa2017-02-08 10:24:42 -0800799 halFilegroupName,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700800 genHeaderName,
Steven Moreland1cbf0362017-05-09 14:32:53 -0700801 "c++-headers",
Dan Willemsen676abdc2016-09-28 19:42:22 -0700802 packageInterfaces,
Steven Morelandff5262b2017-03-20 06:59:03 -0700803 importedPackagesHierarchy,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700804 [&pathPrefix](Formatter &out, const FQName &fqName) {
805 out << "\"" << pathPrefix << fqName.name() << ".h\",\n";
806 if (fqName.name() != "types") {
Yifan Hongeefe4f22017-01-04 15:32:42 -0800807 out << "\"" << pathPrefix << fqName.getInterfaceHwName() << ".h\",\n";
808 out << "\"" << pathPrefix << fqName.getInterfaceStubName() << ".h\",\n";
809 out << "\"" << pathPrefix << fqName.getInterfaceProxyName() << ".h\",\n";
810 out << "\"" << pathPrefix << fqName.getInterfacePassthroughName() << ".h\",\n";
Steven Moreland9774d622017-03-24 21:51:45 -0700811 } else {
812 out << "\"" << pathPrefix << "hwtypes.h\",\n";
Dan Willemsen676abdc2016-09-28 19:42:22 -0700813 }
814 });
815
Steven Morelandf5f593f2017-05-02 13:13:00 -0700816 if (isHidlTransportPackage(packageFQName)) {
817 out << "// " << packageFQName.string() << " is exported from libhidltransport\n";
Steven Moreland0e875df2017-04-25 13:24:17 -0700818 } else {
Steven Morelandf5f593f2017-05-02 13:13:00 -0700819 // C++ library definition
820 out << "cc_library_shared {\n";
821 out.indent();
822 out << "name: \"" << libraryName << "\",\n"
823 << "generated_sources: [\"" << genSourceName << "\"],\n"
824 << "generated_headers: [\"" << genHeaderName << "\"],\n"
825 << "export_generated_headers: [\"" << genHeaderName << "\"],\n";
Dan Willemsen676abdc2016-09-28 19:42:22 -0700826
Steven Morelandf5f593f2017-05-02 13:13:00 -0700827 // TODO(b/35813011): make always vendor_available
828 // Explicitly mark libraries vendor until BOARD_VNDK_VERSION can
829 // be enabled.
830 if (packageFQName.inPackage("android.hidl") ||
831 packageFQName.inPackage("android.system") ||
832 packageFQName.inPackage("android.frameworks") ||
833 packageFQName.inPackage("android.hardware")) {
834 out << "vendor_available: true,\n";
835 } else {
836 out << "vendor: true,\n";
Steven Moreland1b2167b2017-05-01 10:06:21 -0700837 }
Steven Morelandf5f593f2017-05-02 13:13:00 -0700838 out << "shared_libs: [\n";
Steven Moreland1b2167b2017-05-01 10:06:21 -0700839
Steven Morelandf5f593f2017-05-02 13:13:00 -0700840 out.indent();
841 out << "\"libhidlbase\",\n"
842 << "\"libhidltransport\",\n"
843 << "\"libhwbinder\",\n"
844 << "\"liblog\",\n"
845 << "\"libutils\",\n"
846 << "\"libcutils\",\n";
847 for (const auto &importedPackage : importedPackagesHierarchy) {
848 if (isHidlTransportPackage(importedPackage)) {
849 continue;
850 }
Dan Willemsen676abdc2016-09-28 19:42:22 -0700851
Steven Morelandf5f593f2017-05-02 13:13:00 -0700852 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
Steven Moreland1b2167b2017-05-01 10:06:21 -0700853 }
Steven Morelandf5f593f2017-05-02 13:13:00 -0700854 out.unindent();
Steven Moreland1b2167b2017-05-01 10:06:21 -0700855
Steven Morelandf5f593f2017-05-02 13:13:00 -0700856 out << "],\n";
857
858 out << "export_shared_lib_headers: [\n";
859 out.indent();
860 out << "\"libhidlbase\",\n"
861 << "\"libhidltransport\",\n"
862 << "\"libhwbinder\",\n"
863 << "\"libutils\",\n";
864 for (const auto &importedPackage : importedPackagesHierarchy) {
865 if (isHidlTransportPackage(importedPackage)) {
866 continue;
867 }
868
869 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
870 }
871 out.unindent();
872 out << "],\n";
873 out.unindent();
874
875 out << "}\n";
Yifan Hongc1f9b8d2016-11-07 14:35:44 -0800876 }
Dan Willemsen676abdc2016-09-28 19:42:22 -0700877
Zhuoyao Zhangb85e8c22016-12-21 10:24:16 -0800878 return OK;
Dan Willemsen676abdc2016-09-28 19:42:22 -0700879}
880
Yifan Hong958ee462016-12-06 17:09:51 -0800881static status_t generateAndroidBpImplForPackage(
Steven Moreland197d56c2016-09-09 10:03:58 -0700882 const FQName &packageFQName,
883 const char *,
884 Coordinator *coordinator,
885 const std::string &outputDir) {
886
Iliyan Malchev4923f932016-09-09 13:04:59 -0700887 const std::string libraryName = makeLibraryName(packageFQName) + "-impl";
Steven Moreland197d56c2016-09-09 10:03:58 -0700888
889 std::vector<FQName> packageInterfaces;
890
891 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700892 coordinator->appendPackageInterfacesToVector(packageFQName,
893 &packageInterfaces);
Steven Moreland197d56c2016-09-09 10:03:58 -0700894
895 if (err != OK) {
896 return err;
897 }
898
899 std::set<FQName> importedPackages;
900
901 for (const auto &fqName : packageInterfaces) {
902 AST *ast = coordinator->parse(fqName);
903
904 if (ast == NULL) {
905 fprintf(stderr,
906 "ERROR: Could not parse %s. Aborting.\n",
907 fqName.string().c_str());
908
909 return UNKNOWN_ERROR;
910 }
911
912 ast->getImportedPackages(&importedPackages);
913 }
914
Yifan Hongaafed702016-12-14 12:59:47 -0800915 std::string path = outputDir + "Android.bp";
Steven Moreland197d56c2016-09-09 10:03:58 -0700916
917 CHECK(Coordinator::MakeParentHierarchy(path));
918 FILE *file = fopen(path.c_str(), "w");
919
920 if (file == NULL) {
921 return -errno;
922 }
923
924 Formatter out(file);
925
Yifan Hong958ee462016-12-06 17:09:51 -0800926 out << "cc_library_shared {\n";
Yifan Hong33223ca2016-12-13 15:07:35 -0800927 out.indent([&] {
Yifan Hong958ee462016-12-06 17:09:51 -0800928 out << "name: \"" << libraryName << "\",\n"
929 << "relative_install_path: \"hw\",\n"
Steven Morelandf8a22e92017-02-15 18:46:04 -0800930 << "proprietary: true,\n"
Yifan Hong958ee462016-12-06 17:09:51 -0800931 << "srcs: [\n";
Yifan Hong33223ca2016-12-13 15:07:35 -0800932 out.indent([&] {
Yifan Hong958ee462016-12-06 17:09:51 -0800933 for (const auto &fqName : packageInterfaces) {
934 if (fqName.name() == "types") {
935 continue;
936 }
937 out << "\"" << fqName.getInterfaceBaseName() << ".cpp\",\n";
938 }
939 });
940 out << "],\n"
941 << "shared_libs: [\n";
Yifan Hong33223ca2016-12-13 15:07:35 -0800942 out.indent([&] {
Yifan Hong958ee462016-12-06 17:09:51 -0800943 out << "\"libhidlbase\",\n"
944 << "\"libhidltransport\",\n"
Yifan Hong958ee462016-12-06 17:09:51 -0800945 << "\"libutils\",\n"
946 << "\"" << makeLibraryName(packageFQName) << "\",\n";
Yifan Honge0f7d692016-10-20 17:51:33 -0700947
Yifan Hong958ee462016-12-06 17:09:51 -0800948 for (const auto &importedPackage : importedPackages) {
Steven Morelanddadd1842017-05-09 13:24:54 -0700949 if (isHidlTransportPackage(importedPackage)) {
950 continue;
951 }
952
Yifan Hong958ee462016-12-06 17:09:51 -0800953 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
954 }
955 });
956 out << "],\n";
957 });
958 out << "}\n";
Steven Moreland197d56c2016-09-09 10:03:58 -0700959
960 return OK;
961}
962
Andreas Huber0fa9e392016-08-31 09:05:44 -0700963OutputHandler::ValRes validateForSource(
964 const FQName &fqName, const std::string &language) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700965 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700966 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700967 return OutputHandler::FAILED;
968 }
969
970 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700971 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700972 return OutputHandler::FAILED;
973 }
974
Andreas Huber0fa9e392016-08-31 09:05:44 -0700975 const std::string &name = fqName.name();
976 if (!name.empty()) {
977 if (name.find('.') == std::string::npos) {
978 return OutputHandler::PASS_FULL;
979 }
980
981 if (language != "java" || name.find("types.") != 0) {
982 // When generating java sources for "types.hal", output can be
983 // constrained to just one of the top-level types declared
984 // by using the extended syntax
985 // android.hardware.Foo@1.0::types.TopLevelTypeName.
986 // In all other cases (different language, not 'types') the dot
987 // notation in the name is illegal in this context.
988 return OutputHandler::FAILED;
989 }
990
991 return OutputHandler::PASS_FULL;
992 }
993
994 return OutputHandler::PASS_PACKAGE;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700995}
996
Andreas Huber019d21d2016-10-03 12:59:47 -0700997OutputHandler::ValRes validateForExportHeader(
998 const FQName &fqName, const std::string & /* language */) {
999 if (fqName.package().empty()) {
1000 fprintf(stderr, "ERROR: Expecting package name\n");
1001 return OutputHandler::FAILED;
1002 }
1003
1004 if (fqName.version().empty()) {
1005 fprintf(stderr, "ERROR: Expecting package version\n");
1006 return OutputHandler::FAILED;
1007 }
1008
1009 if (!fqName.name().empty()) {
1010 fprintf(stderr,
1011 "ERROR: Expecting only package name and version.\n");
1012 return OutputHandler::FAILED;
1013 }
1014
1015 return OutputHandler::PASS_PACKAGE;
1016}
1017
1018
Steven Morelandf47912d2017-05-12 16:25:44 -07001019OutputHandler::GenerationFunction generateExportHeaderForPackage(bool forJava) {
1020 return [forJava](const FQName &packageFQName,
1021 const char * /* hidl_gen */,
1022 Coordinator *coordinator,
1023 const std::string &outputPath) -> status_t {
1024 CHECK(packageFQName.isValid()
1025 && !packageFQName.package().empty()
1026 && !packageFQName.version().empty()
1027 && packageFQName.name().empty());
Andreas Huber019d21d2016-10-03 12:59:47 -07001028
Steven Morelandf47912d2017-05-12 16:25:44 -07001029 std::vector<FQName> packageInterfaces;
Andreas Huber019d21d2016-10-03 12:59:47 -07001030
Steven Morelandf47912d2017-05-12 16:25:44 -07001031 status_t err = coordinator->appendPackageInterfacesToVector(
1032 packageFQName, &packageInterfaces);
Andreas Huber019d21d2016-10-03 12:59:47 -07001033
Steven Morelandf47912d2017-05-12 16:25:44 -07001034 if (err != OK) {
1035 return err;
Andreas Huber019d21d2016-10-03 12:59:47 -07001036 }
1037
Steven Morelandf47912d2017-05-12 16:25:44 -07001038 std::vector<const Type *> exportedTypes;
Andreas Huber019d21d2016-10-03 12:59:47 -07001039
Steven Morelandf47912d2017-05-12 16:25:44 -07001040 for (const auto &fqName : packageInterfaces) {
1041 AST *ast = coordinator->parse(fqName);
1042
1043 if (ast == NULL) {
1044 fprintf(stderr,
1045 "ERROR: Could not parse %s. Aborting.\n",
1046 fqName.string().c_str());
1047
1048 return UNKNOWN_ERROR;
1049 }
1050
1051 ast->appendToExportedTypesVector(&exportedTypes);
1052 }
1053
1054 if (exportedTypes.empty()) {
1055 return OK;
1056 }
1057
1058 std::string path = outputPath;
1059
1060 if (forJava) {
1061 path.append(coordinator->convertPackageRootToPath(packageFQName));
1062
1063 path.append(coordinator->getPackagePath(
1064 packageFQName, true /* relative */, true /* sanitized */));
1065
1066 path.append("Constants.java");
1067 }
1068
1069 CHECK(Coordinator::MakeParentHierarchy(path));
1070 FILE *file = fopen(path.c_str(), "w");
1071
1072 if (file == nullptr) {
1073 return -errno;
1074 }
1075
1076 Formatter out(file);
1077
1078 out << "// This file is autogenerated by hidl-gen. Do not edit manually.\n"
1079 << "// Source: " << packageFQName.string() << "\n"
1080 << "// Root: " << coordinator->getPackageRootOption(packageFQName) << "\n\n";
1081
1082 std::string guard;
1083 if (forJava) {
1084 out << "package " << packageFQName.javaPackage() << ";\n\n";
1085 out << "public class Constants {\n";
1086 out.indent();
1087 } else {
1088 guard = "HIDL_GENERATED_";
1089 guard += StringHelper::Uppercase(packageFQName.tokenName());
1090 guard += "_";
1091 guard += "EXPORTED_CONSTANTS_H_";
1092
1093 out << "#ifndef "
1094 << guard
1095 << "\n#define "
1096 << guard
1097 << "\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n";
1098 }
1099
1100 for (const auto &type : exportedTypes) {
1101 type->emitExportedHeader(out, forJava);
1102 }
1103
1104 if (forJava) {
1105 out.unindent();
1106 out << "}\n";
1107 } else {
1108 out << "#ifdef __cplusplus\n}\n#endif\n\n#endif // "
1109 << guard
1110 << "\n";
1111 }
1112
Andreas Huber019d21d2016-10-03 12:59:47 -07001113 return OK;
Steven Morelandf47912d2017-05-12 16:25:44 -07001114 };
Andreas Huber019d21d2016-10-03 12:59:47 -07001115}
1116
Steven Morelandf2e44692017-04-18 20:19:09 -07001117static status_t generateHashOutput(const FQName &fqName,
1118 const char* /*hidl_gen*/,
1119 Coordinator *coordinator,
1120 const std::string & /*outputDir*/) {
1121
1122 status_t err;
1123 std::vector<FQName> packageInterfaces;
1124
1125 if (fqName.isFullyQualified()) {
1126 packageInterfaces = {fqName};
1127 } else {
1128 err = coordinator->appendPackageInterfacesToVector(
1129 fqName, &packageInterfaces);
1130 if (err != OK) {
1131 return err;
1132 }
1133 }
1134
1135 for (const auto &currentFqName : packageInterfaces) {
1136 AST *ast = coordinator->parse(currentFqName);
1137
1138 if (ast == NULL) {
1139 fprintf(stderr,
1140 "ERROR: Could not parse %s. Aborting.\n",
1141 currentFqName.string().c_str());
1142
1143 return UNKNOWN_ERROR;
1144 }
1145
1146 printf("%s %s\n",
1147 Hash::getHash(ast->getFilename()).hexString().c_str(),
1148 currentFqName.string().c_str());
1149 }
1150
1151 return OK;
1152}
1153
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001154static std::vector<OutputHandler> formats = {
Steven Moreland3b1ce262017-04-21 14:19:59 -07001155 {"check",
1156 OutputHandler::NOT_NEEDED /* mOutputMode */,
1157 validateForSource,
Steven Morelandbbbbeb82017-05-09 14:20:50 -07001158 generationFunctionForFileOrPackage("check")
Steven Moreland3b1ce262017-04-21 14:19:59 -07001159 },
1160
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001161 {"c++",
Andreas Huber019d21d2016-10-03 12:59:47 -07001162 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001163 validateForSource,
Steven Morelandbbbbeb82017-05-09 14:20:50 -07001164 generationFunctionForFileOrPackage("c++")
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001165 },
1166
Steven Moreland1cbf0362017-05-09 14:32:53 -07001167 {"c++-headers",
1168 OutputHandler::NEEDS_DIR /* mOutputMode */,
1169 validateForSource,
1170 generationFunctionForFileOrPackage("c++-headers")
1171 },
1172
1173 {"c++-sources",
1174 OutputHandler::NEEDS_DIR /* mOutputMode */,
1175 validateForSource,
1176 generationFunctionForFileOrPackage("c++-sources")
1177 },
1178
Andreas Huber019d21d2016-10-03 12:59:47 -07001179 {"export-header",
1180 OutputHandler::NEEDS_FILE /* mOutputMode */,
1181 validateForExportHeader,
Steven Morelandf47912d2017-05-12 16:25:44 -07001182 generateExportHeaderForPackage(false /* forJava */)
Andreas Huber019d21d2016-10-03 12:59:47 -07001183 },
1184
Steven Moreland9c387612016-09-07 09:54:26 -07001185 {"c++-impl",
Andreas Huber019d21d2016-10-03 12:59:47 -07001186 OutputHandler::NEEDS_DIR /* mOutputMode */,
Steven Moreland9c387612016-09-07 09:54:26 -07001187 validateForSource,
Steven Morelandbbbbeb82017-05-09 14:20:50 -07001188 generationFunctionForFileOrPackage("c++-impl")
Steven Moreland9c387612016-09-07 09:54:26 -07001189 },
1190
1191
Andreas Huber2831d512016-08-15 09:33:47 -07001192 {"java",
Andreas Huber019d21d2016-10-03 12:59:47 -07001193 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001194 validateForSource,
Steven Morelandbbbbeb82017-05-09 14:20:50 -07001195 generationFunctionForFileOrPackage("java")
Andreas Huber2831d512016-08-15 09:33:47 -07001196 },
1197
Andreas Huber1c507272016-10-05 14:33:21 -07001198 {"java-constants",
1199 OutputHandler::NEEDS_DIR /* mOutputMode */,
1200 validateForExportHeader,
Steven Morelandf47912d2017-05-12 16:25:44 -07001201 generateExportHeaderForPackage(true /* forJava */)
Andreas Huber1c507272016-10-05 14:33:21 -07001202 },
1203
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001204 {"vts",
Andreas Huber019d21d2016-10-03 12:59:47 -07001205 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001206 validateForSource,
Steven Morelandbbbbeb82017-05-09 14:20:50 -07001207 generationFunctionForFileOrPackage("vts")
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001208 },
1209
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001210 {"makefile",
Steven Morelanda171b562017-05-12 15:18:03 -07001211 OutputHandler::NEEDS_SRC /* mOutputMode */,
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001212 validateForMakefile,
1213 generateMakefileForPackage,
1214 },
Steven Moreland197d56c2016-09-09 10:03:58 -07001215
Dan Willemsen676abdc2016-09-28 19:42:22 -07001216 {"androidbp",
Steven Morelanda171b562017-05-12 15:18:03 -07001217 OutputHandler::NEEDS_SRC /* mOutputMode */,
Dan Willemsen676abdc2016-09-28 19:42:22 -07001218 validateForMakefile,
1219 generateAndroidBpForPackage,
1220 },
1221
Yifan Hong958ee462016-12-06 17:09:51 -08001222 {"androidbp-impl",
Yifan Hong94bcea02016-10-06 13:51:31 -07001223 OutputHandler::NEEDS_DIR /* mOutputMode */,
Steven Moreland197d56c2016-09-09 10:03:58 -07001224 validateForMakefile,
Yifan Hong958ee462016-12-06 17:09:51 -08001225 generateAndroidBpImplForPackage,
Steven Morelandf2e44692017-04-18 20:19:09 -07001226 },
1227
1228 {"hash",
1229 OutputHandler::NOT_NEEDED /* mOutputMode */,
1230 validateForSource,
1231 generateHashOutput,
1232 },
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001233};
1234
1235static void usage(const char *me) {
1236 fprintf(stderr,
Steven Morelandf7fa0682017-05-11 16:14:55 -07001237 "usage: %s [-p root-path] -o output-path -L <language> (-r interface-root)+ fqname+\n",
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001238 me);
1239
Steven Morelandf7fa0682017-05-11 16:14:55 -07001240 fprintf(stderr, " -p root path to android build system (defaults to $ANDROID_BUILD_TOP or pwd)\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001241 fprintf(stderr, " -o output path\n");
1242
1243 fprintf(stderr, " -L <language> (one of");
1244 for (auto &e : formats) {
Steven Morelanddd583842017-04-19 13:09:57 -07001245 fprintf(stderr, " %s", e.name().c_str());
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001246 }
1247 fprintf(stderr, ")\n");
1248
1249 fprintf(stderr,
1250 " -r package:path root "
1251 "(e.g., android.hardware:hardware/interfaces)\n");
1252}
1253
Andreas Gampec4ce9262017-04-27 21:03:20 -07001254// hidl is intentionally leaky. Turn off LeakSanitizer by default.
1255extern "C" const char *__asan_default_options() {
1256 return "detect_leaks=0";
1257}
1258
Andreas Huberb82318c2016-08-02 14:45:54 -07001259int main(int argc, char **argv) {
Andreas Huber019d21d2016-10-03 12:59:47 -07001260 std::string outputPath;
Steven Morelandf7fa0682017-05-11 16:14:55 -07001261 std::string rootPath;
Andreas Huberdca261f2016-08-04 13:47:51 -07001262 std::vector<std::string> packageRootPaths;
1263 std::vector<std::string> packageRoots;
Andreas Huberb82318c2016-08-02 14:45:54 -07001264
Andreas Huber737080b2016-08-02 15:38:04 -07001265 const char *me = argv[0];
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001266 OutputHandler *outputFormat = nullptr;
Andreas Huber737080b2016-08-02 15:38:04 -07001267
Steven Moreland3db99f22017-05-11 16:21:46 -07001268 if (argc == 1) {
1269 usage(me);
1270 exit(1);
1271 }
1272
Andreas Huberb82318c2016-08-02 14:45:54 -07001273 int res;
Steven Morelandf7fa0682017-05-11 16:14:55 -07001274 while ((res = getopt(argc, argv, "hp:o:r:L:")) >= 0) {
Andreas Huberb82318c2016-08-02 14:45:54 -07001275 switch (res) {
Steven Morelandf7fa0682017-05-11 16:14:55 -07001276 case 'p':
1277 {
1278 rootPath = optarg;
1279 break;
1280 }
1281
Andreas Huberb82318c2016-08-02 14:45:54 -07001282 case 'o':
1283 {
Andreas Huber019d21d2016-10-03 12:59:47 -07001284 outputPath = optarg;
Andreas Huberb82318c2016-08-02 14:45:54 -07001285 break;
1286 }
1287
Andreas Huberdca261f2016-08-04 13:47:51 -07001288 case 'r':
1289 {
1290 std::string val(optarg);
1291 auto index = val.find_first_of(':');
Steven Moreland4ff74202017-04-21 14:24:47 -07001292 if (index == std::string::npos) {
1293 fprintf(stderr, "ERROR: -r option must contain ':': %s\n", val.c_str());
1294 exit(1);
1295 }
Andreas Huberdca261f2016-08-04 13:47:51 -07001296
1297 auto package = val.substr(0, index);
1298 auto path = val.substr(index + 1);
1299 packageRootPaths.push_back(path);
1300 packageRoots.push_back(package);
1301 break;
1302 }
1303
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001304 case 'L':
1305 {
Steven Morelanddd583842017-04-19 13:09:57 -07001306 if (outputFormat != nullptr) {
1307 fprintf(stderr,
1308 "ERROR: only one -L option allowed. \"%s\" already specified.\n",
1309 outputFormat->name().c_str());
1310 exit(1);
1311 }
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001312 for (auto &e : formats) {
Steven Morelanddd583842017-04-19 13:09:57 -07001313 if (e.name() == optarg) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001314 outputFormat = &e;
1315 break;
1316 }
1317 }
Steven Morelanddd583842017-04-19 13:09:57 -07001318 if (outputFormat == nullptr) {
1319 fprintf(stderr,
1320 "ERROR: unrecognized -L option: \"%s\".\n",
1321 optarg);
1322 exit(1);
1323 }
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001324 break;
1325 }
1326
Andreas Huberb82318c2016-08-02 14:45:54 -07001327 case '?':
1328 case 'h':
1329 default:
1330 {
Andreas Huber737080b2016-08-02 15:38:04 -07001331 usage(me);
Andreas Huberb82318c2016-08-02 14:45:54 -07001332 exit(1);
1333 break;
1334 }
1335 }
1336 }
1337
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001338 if (outputFormat == nullptr) {
Steven Morelanddd583842017-04-19 13:09:57 -07001339 fprintf(stderr,
1340 "ERROR: no -L option provided.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001341 exit(1);
1342 }
1343
Andreas Huberb82318c2016-08-02 14:45:54 -07001344 argc -= optind;
1345 argv += optind;
1346
Steven Morelandf7fa0682017-05-11 16:14:55 -07001347 if (rootPath.empty()) {
1348 const char *ANDROID_BUILD_TOP = getenv("ANDROID_BUILD_TOP");
1349
1350 if (ANDROID_BUILD_TOP != nullptr) {
1351 rootPath = ANDROID_BUILD_TOP;
1352 }
1353
1354 // else default to pwd
1355 }
1356
1357 if (!rootPath.empty() && !StringHelper::EndsWith(rootPath, "/")) {
1358 rootPath += "/";
1359 }
1360
Andreas Huber737080b2016-08-02 15:38:04 -07001361 // Valid options are now in argv[0] .. argv[argc - 1].
1362
Andreas Huber019d21d2016-10-03 12:59:47 -07001363 switch (outputFormat->mOutputMode) {
1364 case OutputHandler::NEEDS_DIR:
1365 case OutputHandler::NEEDS_FILE:
1366 {
1367 if (outputPath.empty()) {
1368 usage(me);
1369 exit(1);
1370 }
1371
1372 if (outputFormat->mOutputMode == OutputHandler::NEEDS_DIR) {
1373 const size_t len = outputPath.size();
1374 if (outputPath[len - 1] != '/') {
1375 outputPath += "/";
1376 }
1377 }
1378 break;
Andreas Huberb82318c2016-08-02 14:45:54 -07001379 }
Steven Morelanda171b562017-05-12 15:18:03 -07001380 case OutputHandler::NEEDS_SRC:
1381 {
1382 if (outputPath.empty()) {
1383 outputPath = rootPath;
1384 }
1385
1386 break;
1387 }
Andreas Huber019d21d2016-10-03 12:59:47 -07001388
1389 default:
1390 outputPath.clear(); // Unused.
1391 break;
Andreas Huberb82318c2016-08-02 14:45:54 -07001392 }
1393
Steven Morelandf7fa0682017-05-11 16:14:55 -07001394 Coordinator coordinator(packageRootPaths, packageRoots, rootPath);
Steven Moreland25c81662017-05-12 14:57:36 -07001395 coordinator.addDefaultPackagePath("android.hardware", "hardware/interfaces");
1396 coordinator.addDefaultPackagePath("android.hidl", "system/libhidl/transport");
1397 coordinator.addDefaultPackagePath("android.frameworks", "frameworks/hardware/interfaces");
1398 coordinator.addDefaultPackagePath("android.system", "system/hardware/interfaces");
Andreas Huber5345ec22016-07-29 13:33:27 -07001399
Andreas Huber737080b2016-08-02 15:38:04 -07001400 for (int i = 0; i < argc; ++i) {
Andreas Huber68f24592016-07-29 14:53:48 -07001401 FQName fqName(argv[i]);
Andreas Huber68f24592016-07-29 14:53:48 -07001402
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001403 if (!fqName.isValid()) {
Andreas Hubere61e3f72016-08-03 10:22:03 -07001404 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -07001405 "ERROR: Invalid fully-qualified name.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001406 exit(1);
1407 }
Andreas Huber881227d2016-08-02 14:20:21 -07001408
Andreas Huber0fa9e392016-08-31 09:05:44 -07001409 OutputHandler::ValRes valid =
Steven Morelanddd583842017-04-19 13:09:57 -07001410 outputFormat->validate(fqName, outputFormat->name());
Andreas Huber0fa9e392016-08-31 09:05:44 -07001411
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001412 if (valid == OutputHandler::FAILED) {
Steven Morelandf2e44692017-04-18 20:19:09 -07001413 fprintf(stderr,
1414 "ERROR: output handler failed.\n");
Andreas Hubere61e3f72016-08-03 10:22:03 -07001415 exit(1);
1416 }
Andreas Huberd2943e12016-08-05 11:59:31 -07001417
1418 status_t err =
Andreas Huber019d21d2016-10-03 12:59:47 -07001419 outputFormat->generate(fqName, me, &coordinator, outputPath);
Andreas Huberd2943e12016-08-05 11:59:31 -07001420
1421 if (err != OK) {
Steven Moreland261370a2016-08-29 15:36:59 -07001422 exit(1);
Andreas Huberd2943e12016-08-05 11:59:31 -07001423 }
Andreas Hubereb1081f2016-07-28 13:13:24 -07001424 }
Andreas Huberc9410c72016-07-28 12:18:40 -07001425
Andreas Huberd2943e12016-08-05 11:59:31 -07001426 return 0;
Andreas Huberc9410c72016-07-28 12:18:40 -07001427}