blob: e7c308a0c4a4d2f7fccea380595a0348720c48c4 [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,
39 NOT_NEEDED
40 } mOutputMode;
41
Iliyan Malchev5bb14022016-08-09 15:04:39 -070042 enum ValRes {
43 FAILED,
44 PASS_PACKAGE,
45 PASS_FULL
46 };
Steven Morelanddd583842017-04-19 13:09:57 -070047 const std::string& name() { return mKey; }
Steven Morelandbbbbeb82017-05-09 14:20:50 -070048
49 using ValidationFunction = std::function<ValRes(const FQName &, const std::string &language)>;
50 using GenerationFunction = std::function<status_t(const FQName &fqName,
51 const char *hidl_gen,
52 Coordinator *coordinator,
53 const std::string &outputDir)>;
54
55 ValidationFunction validate;
56 GenerationFunction generate;
Iliyan Malchev5bb14022016-08-09 15:04:39 -070057};
Andreas Huberdca261f2016-08-04 13:47:51 -070058
Iliyan Malchev5bb14022016-08-09 15:04:39 -070059static status_t generateSourcesForFile(
60 const FQName &fqName,
61 const char *,
62 Coordinator *coordinator,
Andreas Huber2831d512016-08-15 09:33:47 -070063 const std::string &outputDir,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070064 const std::string &lang) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -070065 CHECK(fqName.isFullyQualified());
66
Andreas Huber0fa9e392016-08-31 09:05:44 -070067 AST *ast;
Andreas Huberd29724f2016-09-14 09:33:13 -070068 std::string limitToType;
Andreas Huber0fa9e392016-08-31 09:05:44 -070069
70 if (fqName.name().find("types.") == 0) {
71 CHECK(lang == "java"); // Already verified in validate().
72
Andreas Huberd29724f2016-09-14 09:33:13 -070073 limitToType = fqName.name().substr(strlen("types."));
Andreas Huber0fa9e392016-08-31 09:05:44 -070074
Yifan Hongfece6ec2017-01-12 17:04:04 -080075 FQName typesName = fqName.getTypesForPackage();
Andreas Huber0fa9e392016-08-31 09:05:44 -070076 ast = coordinator->parse(typesName);
77 } else {
78 ast = coordinator->parse(fqName);
79 }
Iliyan Malchev5bb14022016-08-09 15:04:39 -070080
81 if (ast == NULL) {
82 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -070083 "ERROR: Could not parse %s. Aborting.\n",
Iliyan Malchev5bb14022016-08-09 15:04:39 -070084 fqName.string().c_str());
85
86 return UNKNOWN_ERROR;
87 }
88
Steven Moreland3b1ce262017-04-21 14:19:59 -070089 if (lang == "check") {
90 return OK; // only parsing, not generating
91 }
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070092 if (lang == "c++") {
93 return ast->generateCpp(outputDir);
94 }
Steven Moreland1cbf0362017-05-09 14:32:53 -070095 if (lang == "c++-headers") {
96 return ast->generateCppHeaders(outputDir);
97 }
98 if (lang == "c++-sources") {
99 return ast->generateCppSources(outputDir);
100 }
Steven Moreland9c387612016-09-07 09:54:26 -0700101 if (lang == "c++-impl") {
102 return ast->generateCppImpl(outputDir);
103 }
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700104 if (lang == "java") {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700105 return ast->generateJava(outputDir, limitToType);
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700106 }
107 if (lang == "vts") {
108 return ast->generateVts(outputDir);
109 }
110 // Unknown language.
111 return UNKNOWN_ERROR;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700112}
113
114static status_t generateSourcesForPackage(
115 const FQName &packageFQName,
116 const char *hidl_gen,
117 Coordinator *coordinator,
Andreas Huber2831d512016-08-15 09:33:47 -0700118 const std::string &outputDir,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700119 const std::string &lang) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700120 CHECK(packageFQName.isValid() &&
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700121 !packageFQName.isFullyQualified() &&
122 packageFQName.name().empty());
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700123
124 std::vector<FQName> packageInterfaces;
125
126 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700127 coordinator->appendPackageInterfacesToVector(packageFQName,
128 &packageInterfaces);
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700129
130 if (err != OK) {
131 return err;
132 }
133
134 for (const auto &fqName : packageInterfaces) {
Andreas Huber2831d512016-08-15 09:33:47 -0700135 err = generateSourcesForFile(
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700136 fqName, hidl_gen, coordinator, outputDir, lang);
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700137 if (err != OK) {
138 return err;
139 }
140 }
141
142 return OK;
Andreas Huberb82318c2016-08-02 14:45:54 -0700143}
144
Steven Morelandbbbbeb82017-05-09 14:20:50 -0700145OutputHandler::GenerationFunction generationFunctionForFileOrPackage(const std::string &language) {
146 return [language](const FQName &fqName,
147 const char *hidl_gen, Coordinator *coordinator,
148 const std::string &outputDir) -> status_t {
149 if (fqName.isFullyQualified()) {
150 return generateSourcesForFile(fqName,
151 hidl_gen,
152 coordinator,
153 outputDir,
154 language);
155 } else {
156 return generateSourcesForPackage(fqName,
157 hidl_gen,
158 coordinator,
159 outputDir,
160 language);
161 }
162 };
163}
164
Andreas Huberd2943e12016-08-05 11:59:31 -0700165static std::string makeLibraryName(const FQName &packageFQName) {
Iliyan Malcheve2c595a2016-08-07 21:20:04 -0700166 return packageFQName.string();
Andreas Huberd2943e12016-08-05 11:59:31 -0700167}
168
Andreas Huberaa573272017-04-13 09:58:06 -0700169static std::string makeJavaLibraryName(const FQName &packageFQName) {
170 std::string out;
171 out = packageFQName.package();
172 out += "-V";
173 out += packageFQName.version();
174 return out;
175}
176
Steven Moreland5715fed2017-01-16 11:06:47 -0800177static void generatePackagePathsSection(
178 Formatter &out,
179 Coordinator *coordinator,
180 const FQName &packageFQName,
181 const std::set<FQName> &importedPackages,
182 bool forMakefiles = false) {
183 std::set<std::string> options{};
184 for (const auto &interface : importedPackages) {
185 options.insert(coordinator->getPackageRootOption(interface));
186 }
187 options.insert(coordinator->getPackageRootOption(packageFQName));
188 options.insert(coordinator->getPackageRootOption(gIBasePackageFqName));
189 for (const auto &option : options) {
190 out << "-r"
191 << option
192 << " ";
193 if (forMakefiles) {
194 out << "\\\n";
195 }
196 }
197}
198
Dan Willemsen676abdc2016-09-28 19:42:22 -0700199static void generateMakefileSectionForType(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700200 Formatter &out,
201 Coordinator *coordinator,
202 const FQName &packageFQName,
203 const FQName &fqName,
Steven Moreland5715fed2017-01-16 11:06:47 -0800204 const std::set<FQName> &importedPackages,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700205 const char *typeName) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700206 out << "\n"
207 << "\n#"
208 << "\n# Build " << fqName.name() << ".hal";
209
Dan Willemsen676abdc2016-09-28 19:42:22 -0700210 if (typeName != nullptr) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700211 out << " (" << typeName << ")";
212 }
213
214 out << "\n#"
215 << "\nGEN := $(intermediates)/"
216 << coordinator->convertPackageRootToPath(packageFQName)
Yifan Hong97288ac2016-12-12 16:03:51 -0800217 << coordinator->getPackagePath(packageFQName, true /* relative */,
218 true /* sanitized */);
Dan Willemsen676abdc2016-09-28 19:42:22 -0700219 if (typeName == nullptr) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700220 out << fqName.name() << ".java";
221 } else {
222 out << typeName << ".java";
223 }
224
225 out << "\n$(GEN): $(HIDL)";
226 out << "\n$(GEN): PRIVATE_HIDL := $(HIDL)";
227 out << "\n$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/"
228 << fqName.name() << ".hal";
Iliyan Malchevb9819132016-09-07 12:38:31 -0700229
230 {
231 AST *ast = coordinator->parse(fqName);
232 CHECK(ast != nullptr);
233 const std::set<FQName>& refs = ast->getImportedNames();
234 for (auto depFQName : refs) {
235 // If the package of depFQName is the same as this fqName's package,
236 // then add it explicitly as a .hal dependency within the same
237 // package.
238 if (fqName.package() == depFQName.package() &&
239 fqName.version() == depFQName.version()) {
240 // PRIVATE_DEPS is not actually being used in the
241 // auto-generated file, but is necessary if the build rule
242 // ever needs to use the dependency information, since the
243 // built-in Make variables are not supported in the Android
244 // build system.
245 out << "\n$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/"
246 << depFQName.name() << ".hal";
247 // This is the actual dependency.
248 out << "\n$(GEN): $(LOCAL_PATH)/"
249 << depFQName.name() << ".hal";
250 }
251 }
252 }
253
Andreas Huber0fa9e392016-08-31 09:05:44 -0700254 out << "\n$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)"
255 << "\n$(GEN): PRIVATE_CUSTOM_TOOL = \\";
256 out.indent();
257 out.indent();
258 out << "\n$(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \\"
Steven Moreland5715fed2017-01-16 11:06:47 -0800259 << "\n-Ljava \\\n";
260
261 generatePackagePathsSection(out, coordinator, packageFQName, importedPackages, true /* forJava */);
Andreas Huber0fa9e392016-08-31 09:05:44 -0700262
263 out << packageFQName.string()
264 << "::"
265 << fqName.name();
266
Dan Willemsen676abdc2016-09-28 19:42:22 -0700267 if (typeName != nullptr) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700268 out << "." << typeName;
269 }
270
271 out << "\n";
272
273 out.unindent();
274 out.unindent();
275
276 out << "\n$(GEN): $(LOCAL_PATH)/" << fqName.name() << ".hal";
277 out << "\n\t$(transform-generated-source)";
278 out << "\nLOCAL_GENERATED_SOURCES += $(GEN)";
279}
280
Dan Willemsen676abdc2016-09-28 19:42:22 -0700281static void generateMakefileSection(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700282 Formatter &out,
283 Coordinator *coordinator,
284 const FQName &packageFQName,
285 const std::vector<FQName> &packageInterfaces,
Steven Moreland5715fed2017-01-16 11:06:47 -0800286 const std::set<FQName> &importedPackages,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700287 AST *typesAST) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700288 for (const auto &fqName : packageInterfaces) {
Dan Willemsen676abdc2016-09-28 19:42:22 -0700289 if (fqName.name() == "types") {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700290 CHECK(typesAST != nullptr);
291
292 Scope *rootScope = typesAST->scope();
Andreas Huber0fa9e392016-08-31 09:05:44 -0700293
Andreas Huberb747bd92016-09-26 15:55:31 -0700294 std::vector<NamedType *> subTypes = rootScope->getSubTypes();
295 std::sort(
296 subTypes.begin(),
297 subTypes.end(),
298 [](const NamedType *a, const NamedType *b) -> bool {
299 return a->fqName() < b->fqName();
300 });
301
302 for (const auto &type : subTypes) {
Andreas Huberdda25cc2016-09-22 10:39:47 -0700303 if (type->isTypeDef()) {
304 continue;
305 }
306
Dan Willemsen676abdc2016-09-28 19:42:22 -0700307 generateMakefileSectionForType(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700308 out,
309 coordinator,
310 packageFQName,
311 fqName,
Steven Moreland5715fed2017-01-16 11:06:47 -0800312 importedPackages,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700313 type->localName().c_str());
Andreas Huber0fa9e392016-08-31 09:05:44 -0700314 }
315
316 continue;
317 }
318
Dan Willemsen676abdc2016-09-28 19:42:22 -0700319 generateMakefileSectionForType(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700320 out,
321 coordinator,
322 packageFQName,
323 fqName,
Steven Moreland5715fed2017-01-16 11:06:47 -0800324 importedPackages,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700325 nullptr /* typeName */);
Andreas Huber0fa9e392016-08-31 09:05:44 -0700326 }
327}
328
Andreas Huber75ae95d2016-10-12 16:08:26 -0700329static status_t isPackageJavaCompatible(
330 const FQName &packageFQName,
331 Coordinator *coordinator,
332 bool *compatible) {
333 std::vector<FQName> todo;
334 status_t err =
335 coordinator->appendPackageInterfacesToVector(packageFQName, &todo);
336
337 if (err != OK) {
338 return err;
339 }
340
341 std::set<FQName> seen;
342 for (const auto &iface : todo) {
343 seen.insert(iface);
344 }
345
346 // Form the transitive closure of all imported interfaces (and types.hal-s)
347 // If any one of them is not java compatible, this package isn't either.
348 while (!todo.empty()) {
349 const FQName fqName = todo.back();
350 todo.pop_back();
351
352 AST *ast = coordinator->parse(fqName);
353
354 if (ast == nullptr) {
355 return UNKNOWN_ERROR;
356 }
357
358 if (!ast->isJavaCompatible()) {
359 *compatible = false;
360 return OK;
361 }
362
363 std::set<FQName> importedPackages;
364 ast->getImportedPackages(&importedPackages);
365
366 for (const auto &package : importedPackages) {
367 std::vector<FQName> packageInterfaces;
368 status_t err = coordinator->appendPackageInterfacesToVector(
369 package, &packageInterfaces);
370
371 if (err != OK) {
372 return err;
373 }
374
375 for (const auto &iface : packageInterfaces) {
376 if (seen.find(iface) != seen.end()) {
377 continue;
378 }
379
380 todo.push_back(iface);
381 seen.insert(iface);
382 }
383 }
384 }
385
386 *compatible = true;
387 return OK;
388}
389
Andreas Huber5a9fe2c2016-10-13 15:31:10 -0700390static bool packageNeedsJavaCode(
391 const std::vector<FQName> &packageInterfaces, AST *typesAST) {
392 // If there is more than just a types.hal file to this package we'll
393 // definitely need to generate Java code.
394 if (packageInterfaces.size() > 1
395 || packageInterfaces[0].name() != "types") {
396 return true;
397 }
398
399 CHECK(typesAST != nullptr);
400
401 // We'll have to generate Java code if types.hal contains any non-typedef
402 // type declarations.
403
404 Scope *rootScope = typesAST->scope();
405 std::vector<NamedType *> subTypes = rootScope->getSubTypes();
406
407 for (const auto &subType : subTypes) {
408 if (!subType->isTypeDef()) {
409 return true;
410 }
411 }
412
413 return false;
414}
415
Andreas Huber1c507272016-10-05 14:33:21 -0700416static void generateMakefileSectionForJavaConstants(
417 Formatter &out,
418 Coordinator *coordinator,
419 const FQName &packageFQName,
Steven Moreland5715fed2017-01-16 11:06:47 -0800420 const std::vector<FQName> &packageInterfaces,
421 const std::set<FQName> &importedPackages) {
Andreas Huber1c507272016-10-05 14:33:21 -0700422 out << "\n#"
423 << "\nGEN := $(intermediates)/"
424 << coordinator->convertPackageRootToPath(packageFQName)
Yifan Hong97288ac2016-12-12 16:03:51 -0800425 << coordinator->getPackagePath(packageFQName, true /* relative */, true /* sanitized */)
Andreas Huber1c507272016-10-05 14:33:21 -0700426 << "Constants.java";
427
428 out << "\n$(GEN): $(HIDL)\n";
429 for (const auto &iface : packageInterfaces) {
430 out << "$(GEN): $(LOCAL_PATH)/" << iface.name() << ".hal\n";
431 }
432 out << "\n$(GEN): PRIVATE_HIDL := $(HIDL)";
433 out << "\n$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)"
434 << "\n$(GEN): PRIVATE_CUSTOM_TOOL = \\";
435 out.indent();
436 out.indent();
437 out << "\n$(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \\"
Steven Moreland5715fed2017-01-16 11:06:47 -0800438 << "\n-Ljava-constants \\\n";
439
440 generatePackagePathsSection(out, coordinator, packageFQName, importedPackages, true /* forJava */);
Andreas Huber1c507272016-10-05 14:33:21 -0700441
442 out << packageFQName.string();
443 out << "\n";
444
445 out.unindent();
446 out.unindent();
447
448 out << "\n$(GEN):";
449 out << "\n\t$(transform-generated-source)";
450 out << "\nLOCAL_GENERATED_SOURCES += $(GEN)";
451}
452
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700453static status_t generateMakefileForPackage(
454 const FQName &packageFQName,
Iliyan Malchevb66c3992016-08-07 21:18:13 -0700455 const char *hidl_gen,
Andreas Huberd2943e12016-08-05 11:59:31 -0700456 Coordinator *coordinator,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700457 const std::string &) {
458
459 CHECK(packageFQName.isValid() &&
460 !packageFQName.isFullyQualified() &&
461 packageFQName.name().empty());
462
Andreas Huberd2943e12016-08-05 11:59:31 -0700463 std::vector<FQName> packageInterfaces;
464
465 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700466 coordinator->appendPackageInterfacesToVector(packageFQName,
467 &packageInterfaces);
Andreas Huberd2943e12016-08-05 11:59:31 -0700468
469 if (err != OK) {
470 return err;
471 }
472
473 std::set<FQName> importedPackages;
Andreas Huber0fa9e392016-08-31 09:05:44 -0700474 AST *typesAST = nullptr;
Andreas Huber1c507272016-10-05 14:33:21 -0700475 std::vector<const Type *> exportedTypes;
Andreas Huber0fa9e392016-08-31 09:05:44 -0700476
Andreas Huberd2943e12016-08-05 11:59:31 -0700477 for (const auto &fqName : packageInterfaces) {
478 AST *ast = coordinator->parse(fqName);
479
480 if (ast == NULL) {
481 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700482 "ERROR: Could not parse %s. Aborting.\n",
Andreas Huberd2943e12016-08-05 11:59:31 -0700483 fqName.string().c_str());
484
485 return UNKNOWN_ERROR;
486 }
487
Andreas Huber0fa9e392016-08-31 09:05:44 -0700488 if (fqName.name() == "types") {
489 typesAST = ast;
490 }
491
Yifan Hong40a373d2016-11-30 15:16:47 -0800492 ast->getImportedPackagesHierarchy(&importedPackages);
Andreas Huber1c507272016-10-05 14:33:21 -0700493 ast->appendToExportedTypesVector(&exportedTypes);
Andreas Huberd2943e12016-08-05 11:59:31 -0700494 }
495
Andreas Huber75ae95d2016-10-12 16:08:26 -0700496 bool packageIsJavaCompatible;
497 err = isPackageJavaCompatible(
498 packageFQName, coordinator, &packageIsJavaCompatible);
499
500 if (err != OK) {
501 return err;
502 }
503
Andreas Huber1c507272016-10-05 14:33:21 -0700504 bool haveJavaConstants = !exportedTypes.empty();
505
506 if (!packageIsJavaCompatible && !haveJavaConstants) {
Steven Moreland81979932016-12-07 15:11:06 -0800507 // TODO(b/33420795)
508 fprintf(stderr,
509 "WARNING: %s is not java compatible. No java makefile created.\n",
510 packageFQName.string().c_str());
Dan Willemsen676abdc2016-09-28 19:42:22 -0700511 return OK;
512 }
513
Andreas Huber5a9fe2c2016-10-13 15:31:10 -0700514 if (!packageNeedsJavaCode(packageInterfaces, typesAST)) {
515 return OK;
516 }
517
Steven Morelandf7fa0682017-05-11 16:14:55 -0700518 std::string path = coordinator->getRootPath();
519 path.append(coordinator->getPackagePath(packageFQName, false /* relative */));
Andreas Huberd2943e12016-08-05 11:59:31 -0700520 path.append("Android.mk");
521
522 CHECK(Coordinator::MakeParentHierarchy(path));
523 FILE *file = fopen(path.c_str(), "w");
524
525 if (file == NULL) {
526 return -errno;
527 }
528
Andreas Huberaa573272017-04-13 09:58:06 -0700529 const std::string libraryName = makeJavaLibraryName(packageFQName);
Andreas Huberd2943e12016-08-05 11:59:31 -0700530
531 Formatter out(file);
532
Dan Willemsen676abdc2016-09-28 19:42:22 -0700533 out << "# This file is autogenerated by hidl-gen. Do not edit manually.\n\n";
534 out << "LOCAL_PATH := $(call my-dir)\n";
Andreas Huberd2943e12016-08-05 11:59:31 -0700535
Dan Willemsen676abdc2016-09-28 19:42:22 -0700536 enum LibraryStyle {
537 LIBRARY_STYLE_REGULAR,
538 LIBRARY_STYLE_STATIC,
539 LIBRARY_STYLE_END,
540 };
Andreas Huberd2943e12016-08-05 11:59:31 -0700541
Andreas Huber1c507272016-10-05 14:33:21 -0700542 for (int style = LIBRARY_STYLE_REGULAR;
543 (packageIsJavaCompatible && style != LIBRARY_STYLE_END);
Dan Willemsen676abdc2016-09-28 19:42:22 -0700544 ++style) {
545 const std::string staticSuffix =
546 (style == LIBRARY_STYLE_STATIC) ? "-static" : "";
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700547
Dan Willemsen676abdc2016-09-28 19:42:22 -0700548 out << "\n"
549 << "########################################"
550 << "########################################\n\n";
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700551
Dan Willemsen676abdc2016-09-28 19:42:22 -0700552 out << "include $(CLEAR_VARS)\n"
553 << "LOCAL_MODULE := "
554 << libraryName
555 << "-java"
556 << staticSuffix
557 << "\nLOCAL_MODULE_CLASS := JAVA_LIBRARIES\n\n"
Andreas Huber177a8b12017-02-09 10:08:48 -0800558 << "intermediates := $(call local-generated-sources-dir, COMMON)"
559 << "\n\n"
Dan Willemsen676abdc2016-09-28 19:42:22 -0700560 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
561 << hidl_gen
562 << "$(HOST_EXECUTABLE_SUFFIX)";
Andreas Huberd2943e12016-08-05 11:59:31 -0700563
Dan Willemsen676abdc2016-09-28 19:42:22 -0700564 if (!importedPackages.empty()) {
Iliyan Malchev800273d2016-09-02 15:25:07 -0700565 out << "\n"
Dan Willemsen676abdc2016-09-28 19:42:22 -0700566 << "\nLOCAL_"
Andreas Huber782d45e2016-09-22 13:25:14 -0700567 << ((style == LIBRARY_STYLE_STATIC) ? "STATIC_" : "")
Dan Willemsen676abdc2016-09-28 19:42:22 -0700568 << "JAVA_LIBRARIES := \\";
569
570 out.indent();
571 for (const auto &importedPackage : importedPackages) {
572 out << "\n"
Andreas Huberaa573272017-04-13 09:58:06 -0700573 << makeJavaLibraryName(importedPackage)
Dan Willemsen676abdc2016-09-28 19:42:22 -0700574 << "-java"
575 << staticSuffix
576 << " \\";
577 }
578 out << "\n";
579 out.unindent();
Iliyan Malchev800273d2016-09-02 15:25:07 -0700580 }
Dan Willemsen676abdc2016-09-28 19:42:22 -0700581
582 generateMakefileSection(
583 out,
584 coordinator,
585 packageFQName,
586 packageInterfaces,
Steven Moreland5715fed2017-01-16 11:06:47 -0800587 importedPackages,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700588 typesAST);
589
590 out << "\ninclude $(BUILD_"
591 << ((style == LIBRARY_STYLE_STATIC) ? "STATIC_" : "")
592 << "JAVA_LIBRARY)\n\n";
Andreas Huber0fa9e392016-08-31 09:05:44 -0700593 }
594
Andreas Huber1c507272016-10-05 14:33:21 -0700595 if (haveJavaConstants) {
596 out << "\n"
597 << "########################################"
598 << "########################################\n\n";
599
600 out << "include $(CLEAR_VARS)\n"
601 << "LOCAL_MODULE := "
602 << libraryName
603 << "-java-constants"
604 << "\nLOCAL_MODULE_CLASS := JAVA_LIBRARIES\n\n"
Andreas Huber177a8b12017-02-09 10:08:48 -0800605 << "intermediates := $(call local-generated-sources-dir, COMMON)"
606 << "\n\n"
Andreas Huber1c507272016-10-05 14:33:21 -0700607 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
608 << hidl_gen
609 << "$(HOST_EXECUTABLE_SUFFIX)";
610
611 generateMakefileSectionForJavaConstants(
Steven Moreland5715fed2017-01-16 11:06:47 -0800612 out, coordinator, packageFQName, packageInterfaces, importedPackages);
Andreas Huber1c507272016-10-05 14:33:21 -0700613
614 out << "\n# Avoid dependency cycle of framework.jar -> this-library "
615 << "-> framework.jar\n"
616 << "LOCAL_NO_STANDARD_LIBRARIES := true\n"
617 << "LOCAL_JAVA_LIBRARIES := core-oj\n\n"
618 << "include $(BUILD_STATIC_JAVA_LIBRARY)\n\n";
619 }
620
Iliyan Malchev8be09552016-09-22 16:20:33 -0700621 out << "\n\n"
622 << "include $(call all-makefiles-under,$(LOCAL_PATH))\n";
623
Andreas Huberd2943e12016-08-05 11:59:31 -0700624 return OK;
625}
626
Andreas Huber0fa9e392016-08-31 09:05:44 -0700627OutputHandler::ValRes validateForMakefile(
628 const FQName &fqName, const std::string & /* language */) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700629 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700630 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700631 return OutputHandler::FAILED;
632 }
633
634 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700635 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700636 return OutputHandler::FAILED;
637 }
638
639 if (!fqName.name().empty()) {
640 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700641 "ERROR: Expecting only package name and version.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700642 return OutputHandler::FAILED;
643 }
644
645 return OutputHandler::PASS_PACKAGE;
646}
647
Dan Willemsen676abdc2016-09-28 19:42:22 -0700648static void generateAndroidBpGenSection(
649 Formatter &out,
650 const FQName &packageFQName,
651 const char *hidl_gen,
652 Coordinator *coordinator,
Tri Vo6a827fa2017-02-08 10:24:42 -0800653 const std::string &halFilegroupName,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700654 const std::string &genName,
655 const char *language,
656 const std::vector<FQName> &packageInterfaces,
Steven Moreland5715fed2017-01-16 11:06:47 -0800657 const std::set<FQName> &importedPackages,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700658 const std::function<void(Formatter&, const FQName)> outputFn) {
659
660 out << "genrule {\n";
661 out.indent();
662 out << "name: \"" << genName << "\",\n"
Colin Crossd5419bd2016-11-04 15:05:54 -0700663 << "tools: [\"" << hidl_gen << "\"],\n";
Dan Willemsen676abdc2016-09-28 19:42:22 -0700664
Colin Crossd5419bd2016-11-04 15:05:54 -0700665 out << "cmd: \"$(location " << hidl_gen << ") -o $(genDir)"
Steven Moreland5715fed2017-01-16 11:06:47 -0800666 << " -L" << language << " ";
667
668 generatePackagePathsSection(out, coordinator, packageFQName, importedPackages);
669
670 out << packageFQName.string() << "\",\n";
Dan Willemsen676abdc2016-09-28 19:42:22 -0700671
672 out << "srcs: [\n";
673 out.indent();
Tri Vo6a827fa2017-02-08 10:24:42 -0800674 out << "\":" << halFilegroupName << "\",\n";
Dan Willemsen676abdc2016-09-28 19:42:22 -0700675 out.unindent();
676 out << "],\n";
677
678 out << "out: [\n";
679 out.indent();
680 for (const auto &fqName : packageInterfaces) {
681 outputFn(out, fqName);
682 }
683 out.unindent();
684 out << "],\n";
685
686 out.unindent();
687 out << "}\n\n";
688}
689
Steven Moreland1b2167b2017-05-01 10:06:21 -0700690bool isHidlTransportPackage(const FQName &package) {
691 return package == gIBasePackageFqName ||
692 package == gIManagerPackageFqName;
693}
694
Dan Willemsen676abdc2016-09-28 19:42:22 -0700695static status_t generateAndroidBpForPackage(
696 const FQName &packageFQName,
697 const char *hidl_gen,
698 Coordinator *coordinator,
699 const std::string &) {
700
701 CHECK(packageFQName.isValid() &&
702 !packageFQName.isFullyQualified() &&
703 packageFQName.name().empty());
704
705 std::vector<FQName> packageInterfaces;
706
707 status_t err =
708 coordinator->appendPackageInterfacesToVector(packageFQName,
709 &packageInterfaces);
710
711 if (err != OK) {
712 return err;
713 }
714
Steven Morelandff5262b2017-03-20 06:59:03 -0700715 std::set<FQName> importedPackagesHierarchy;
Dan Willemsen676abdc2016-09-28 19:42:22 -0700716 AST *typesAST = nullptr;
717
718 for (const auto &fqName : packageInterfaces) {
719 AST *ast = coordinator->parse(fqName);
720
721 if (ast == NULL) {
722 fprintf(stderr,
723 "ERROR: Could not parse %s. Aborting.\n",
724 fqName.string().c_str());
725
726 return UNKNOWN_ERROR;
727 }
728
729 if (fqName.name() == "types") {
730 typesAST = ast;
731 }
732
Steven Morelandff5262b2017-03-20 06:59:03 -0700733 ast->getImportedPackagesHierarchy(&importedPackagesHierarchy);
Dan Willemsen676abdc2016-09-28 19:42:22 -0700734 }
735
Steven Morelandf7fa0682017-05-11 16:14:55 -0700736 std::string path = coordinator->getRootPath();
737 path.append(coordinator->getPackagePath(packageFQName, false /* relative */));
Dan Willemsen676abdc2016-09-28 19:42:22 -0700738 path.append("Android.bp");
739
740 CHECK(Coordinator::MakeParentHierarchy(path));
741 FILE *file = fopen(path.c_str(), "w");
742
743 if (file == NULL) {
744 return -errno;
745 }
746
747 const std::string libraryName = makeLibraryName(packageFQName);
Tri Vo15052c62017-02-06 10:04:07 -0800748 const std::string halFilegroupName = libraryName + "_hal";
Dan Willemsen676abdc2016-09-28 19:42:22 -0700749 const std::string genSourceName = libraryName + "_genc++";
750 const std::string genHeaderName = libraryName + "_genc++_headers";
751 const std::string pathPrefix =
752 coordinator->convertPackageRootToPath(packageFQName) +
753 coordinator->getPackagePath(packageFQName, true /* relative */);
754
755 Formatter out(file);
756
757 out << "// This file is autogenerated by hidl-gen. Do not edit manually.\n\n";
758
Tri Vo15052c62017-02-06 10:04:07 -0800759 // Rule to generate .hal filegroup
760 out << "filegroup {\n";
761 out.indent();
762 out << "name: \"" << halFilegroupName << "\",\n";
763 out << "srcs: [\n";
764 out.indent();
765 for (const auto &fqName : packageInterfaces) {
766 out << "\"" << fqName.name() << ".hal\",\n";
767 }
768 out.unindent();
769 out << "],\n";
770 out.unindent();
771 out << "}\n\n";
772
Dan Willemsen676abdc2016-09-28 19:42:22 -0700773 // Rule to generate the C++ source files
774 generateAndroidBpGenSection(
775 out,
776 packageFQName,
777 hidl_gen,
778 coordinator,
Tri Vo6a827fa2017-02-08 10:24:42 -0800779 halFilegroupName,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700780 genSourceName,
Steven Moreland1cbf0362017-05-09 14:32:53 -0700781 "c++-sources",
Dan Willemsen676abdc2016-09-28 19:42:22 -0700782 packageInterfaces,
Steven Morelandff5262b2017-03-20 06:59:03 -0700783 importedPackagesHierarchy,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700784 [&pathPrefix](Formatter &out, const FQName &fqName) {
785 if (fqName.name() == "types") {
786 out << "\"" << pathPrefix << "types.cpp\",\n";
787 } else {
788 out << "\"" << pathPrefix << fqName.name().substr(1) << "All.cpp\",\n";
789 }
790 });
791
792 // Rule to generate the C++ header files
793 generateAndroidBpGenSection(
794 out,
795 packageFQName,
796 hidl_gen,
797 coordinator,
Tri Vo6a827fa2017-02-08 10:24:42 -0800798 halFilegroupName,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700799 genHeaderName,
Steven Moreland1cbf0362017-05-09 14:32:53 -0700800 "c++-headers",
Dan Willemsen676abdc2016-09-28 19:42:22 -0700801 packageInterfaces,
Steven Morelandff5262b2017-03-20 06:59:03 -0700802 importedPackagesHierarchy,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700803 [&pathPrefix](Formatter &out, const FQName &fqName) {
804 out << "\"" << pathPrefix << fqName.name() << ".h\",\n";
805 if (fqName.name() != "types") {
Yifan Hongeefe4f22017-01-04 15:32:42 -0800806 out << "\"" << pathPrefix << fqName.getInterfaceHwName() << ".h\",\n";
807 out << "\"" << pathPrefix << fqName.getInterfaceStubName() << ".h\",\n";
808 out << "\"" << pathPrefix << fqName.getInterfaceProxyName() << ".h\",\n";
809 out << "\"" << pathPrefix << fqName.getInterfacePassthroughName() << ".h\",\n";
Steven Moreland9774d622017-03-24 21:51:45 -0700810 } else {
811 out << "\"" << pathPrefix << "hwtypes.h\",\n";
Dan Willemsen676abdc2016-09-28 19:42:22 -0700812 }
813 });
814
Steven Morelandf5f593f2017-05-02 13:13:00 -0700815 if (isHidlTransportPackage(packageFQName)) {
816 out << "// " << packageFQName.string() << " is exported from libhidltransport\n";
Steven Moreland0e875df2017-04-25 13:24:17 -0700817 } else {
Steven Morelandf5f593f2017-05-02 13:13:00 -0700818 // C++ library definition
819 out << "cc_library_shared {\n";
820 out.indent();
821 out << "name: \"" << libraryName << "\",\n"
822 << "generated_sources: [\"" << genSourceName << "\"],\n"
823 << "generated_headers: [\"" << genHeaderName << "\"],\n"
824 << "export_generated_headers: [\"" << genHeaderName << "\"],\n";
Dan Willemsen676abdc2016-09-28 19:42:22 -0700825
Steven Morelandf5f593f2017-05-02 13:13:00 -0700826 // TODO(b/35813011): make always vendor_available
827 // Explicitly mark libraries vendor until BOARD_VNDK_VERSION can
828 // be enabled.
829 if (packageFQName.inPackage("android.hidl") ||
830 packageFQName.inPackage("android.system") ||
831 packageFQName.inPackage("android.frameworks") ||
832 packageFQName.inPackage("android.hardware")) {
833 out << "vendor_available: true,\n";
834 } else {
835 out << "vendor: true,\n";
Steven Moreland1b2167b2017-05-01 10:06:21 -0700836 }
Steven Morelandf5f593f2017-05-02 13:13:00 -0700837 out << "shared_libs: [\n";
Steven Moreland1b2167b2017-05-01 10:06:21 -0700838
Steven Morelandf5f593f2017-05-02 13:13:00 -0700839 out.indent();
840 out << "\"libhidlbase\",\n"
841 << "\"libhidltransport\",\n"
842 << "\"libhwbinder\",\n"
843 << "\"liblog\",\n"
844 << "\"libutils\",\n"
845 << "\"libcutils\",\n";
846 for (const auto &importedPackage : importedPackagesHierarchy) {
847 if (isHidlTransportPackage(importedPackage)) {
848 continue;
849 }
Dan Willemsen676abdc2016-09-28 19:42:22 -0700850
Steven Morelandf5f593f2017-05-02 13:13:00 -0700851 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
Steven Moreland1b2167b2017-05-01 10:06:21 -0700852 }
Steven Morelandf5f593f2017-05-02 13:13:00 -0700853 out.unindent();
Steven Moreland1b2167b2017-05-01 10:06:21 -0700854
Steven Morelandf5f593f2017-05-02 13:13:00 -0700855 out << "],\n";
856
857 out << "export_shared_lib_headers: [\n";
858 out.indent();
859 out << "\"libhidlbase\",\n"
860 << "\"libhidltransport\",\n"
861 << "\"libhwbinder\",\n"
862 << "\"libutils\",\n";
863 for (const auto &importedPackage : importedPackagesHierarchy) {
864 if (isHidlTransportPackage(importedPackage)) {
865 continue;
866 }
867
868 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
869 }
870 out.unindent();
871 out << "],\n";
872 out.unindent();
873
874 out << "}\n";
Yifan Hongc1f9b8d2016-11-07 14:35:44 -0800875 }
Dan Willemsen676abdc2016-09-28 19:42:22 -0700876
Zhuoyao Zhangb85e8c22016-12-21 10:24:16 -0800877 return OK;
Dan Willemsen676abdc2016-09-28 19:42:22 -0700878}
879
Yifan Hong958ee462016-12-06 17:09:51 -0800880static status_t generateAndroidBpImplForPackage(
Steven Moreland197d56c2016-09-09 10:03:58 -0700881 const FQName &packageFQName,
882 const char *,
883 Coordinator *coordinator,
884 const std::string &outputDir) {
885
Iliyan Malchev4923f932016-09-09 13:04:59 -0700886 const std::string libraryName = makeLibraryName(packageFQName) + "-impl";
Steven Moreland197d56c2016-09-09 10:03:58 -0700887
888 std::vector<FQName> packageInterfaces;
889
890 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700891 coordinator->appendPackageInterfacesToVector(packageFQName,
892 &packageInterfaces);
Steven Moreland197d56c2016-09-09 10:03:58 -0700893
894 if (err != OK) {
895 return err;
896 }
897
898 std::set<FQName> importedPackages;
899
900 for (const auto &fqName : packageInterfaces) {
901 AST *ast = coordinator->parse(fqName);
902
903 if (ast == NULL) {
904 fprintf(stderr,
905 "ERROR: Could not parse %s. Aborting.\n",
906 fqName.string().c_str());
907
908 return UNKNOWN_ERROR;
909 }
910
911 ast->getImportedPackages(&importedPackages);
912 }
913
Yifan Hongaafed702016-12-14 12:59:47 -0800914 std::string path = outputDir + "Android.bp";
Steven Moreland197d56c2016-09-09 10:03:58 -0700915
916 CHECK(Coordinator::MakeParentHierarchy(path));
917 FILE *file = fopen(path.c_str(), "w");
918
919 if (file == NULL) {
920 return -errno;
921 }
922
923 Formatter out(file);
924
Yifan Hong958ee462016-12-06 17:09:51 -0800925 out << "cc_library_shared {\n";
Yifan Hong33223ca2016-12-13 15:07:35 -0800926 out.indent([&] {
Yifan Hong958ee462016-12-06 17:09:51 -0800927 out << "name: \"" << libraryName << "\",\n"
928 << "relative_install_path: \"hw\",\n"
Steven Morelandf8a22e92017-02-15 18:46:04 -0800929 << "proprietary: true,\n"
Yifan Hong958ee462016-12-06 17:09:51 -0800930 << "srcs: [\n";
Yifan Hong33223ca2016-12-13 15:07:35 -0800931 out.indent([&] {
Yifan Hong958ee462016-12-06 17:09:51 -0800932 for (const auto &fqName : packageInterfaces) {
933 if (fqName.name() == "types") {
934 continue;
935 }
936 out << "\"" << fqName.getInterfaceBaseName() << ".cpp\",\n";
937 }
938 });
939 out << "],\n"
940 << "shared_libs: [\n";
Yifan Hong33223ca2016-12-13 15:07:35 -0800941 out.indent([&] {
Yifan Hong958ee462016-12-06 17:09:51 -0800942 out << "\"libhidlbase\",\n"
943 << "\"libhidltransport\",\n"
Yifan Hong958ee462016-12-06 17:09:51 -0800944 << "\"libutils\",\n"
945 << "\"" << makeLibraryName(packageFQName) << "\",\n";
Yifan Honge0f7d692016-10-20 17:51:33 -0700946
Yifan Hong958ee462016-12-06 17:09:51 -0800947 for (const auto &importedPackage : importedPackages) {
Steven Morelanddadd1842017-05-09 13:24:54 -0700948 if (isHidlTransportPackage(importedPackage)) {
949 continue;
950 }
951
Yifan Hong958ee462016-12-06 17:09:51 -0800952 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
953 }
954 });
955 out << "],\n";
956 });
957 out << "}\n";
Steven Moreland197d56c2016-09-09 10:03:58 -0700958
959 return OK;
960}
961
Andreas Huber0fa9e392016-08-31 09:05:44 -0700962OutputHandler::ValRes validateForSource(
963 const FQName &fqName, const std::string &language) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700964 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700965 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700966 return OutputHandler::FAILED;
967 }
968
969 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700970 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700971 return OutputHandler::FAILED;
972 }
973
Andreas Huber0fa9e392016-08-31 09:05:44 -0700974 const std::string &name = fqName.name();
975 if (!name.empty()) {
976 if (name.find('.') == std::string::npos) {
977 return OutputHandler::PASS_FULL;
978 }
979
980 if (language != "java" || name.find("types.") != 0) {
981 // When generating java sources for "types.hal", output can be
982 // constrained to just one of the top-level types declared
983 // by using the extended syntax
984 // android.hardware.Foo@1.0::types.TopLevelTypeName.
985 // In all other cases (different language, not 'types') the dot
986 // notation in the name is illegal in this context.
987 return OutputHandler::FAILED;
988 }
989
990 return OutputHandler::PASS_FULL;
991 }
992
993 return OutputHandler::PASS_PACKAGE;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700994}
995
Andreas Huber019d21d2016-10-03 12:59:47 -0700996OutputHandler::ValRes validateForExportHeader(
997 const FQName &fqName, const std::string & /* language */) {
998 if (fqName.package().empty()) {
999 fprintf(stderr, "ERROR: Expecting package name\n");
1000 return OutputHandler::FAILED;
1001 }
1002
1003 if (fqName.version().empty()) {
1004 fprintf(stderr, "ERROR: Expecting package version\n");
1005 return OutputHandler::FAILED;
1006 }
1007
1008 if (!fqName.name().empty()) {
1009 fprintf(stderr,
1010 "ERROR: Expecting only package name and version.\n");
1011 return OutputHandler::FAILED;
1012 }
1013
1014 return OutputHandler::PASS_PACKAGE;
1015}
1016
1017
1018static status_t generateExportHeaderForPackage(
1019 const FQName &packageFQName,
1020 const char * /* hidl_gen */,
1021 Coordinator *coordinator,
Andreas Huber1c507272016-10-05 14:33:21 -07001022 const std::string &outputPath,
1023 bool forJava) {
Andreas Huber019d21d2016-10-03 12:59:47 -07001024
1025 CHECK(packageFQName.isValid()
1026 && !packageFQName.isFullyQualified()
1027 && packageFQName.name().empty());
1028
1029 std::vector<FQName> packageInterfaces;
1030
1031 status_t err = coordinator->appendPackageInterfacesToVector(
1032 packageFQName, &packageInterfaces);
1033
1034 if (err != OK) {
1035 return err;
1036 }
1037
1038 std::vector<const Type *> exportedTypes;
1039
1040 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
Andreas Huber1c507272016-10-05 14:33:21 -07001058 std::string path = outputPath;
1059
1060 if (forJava) {
1061 path.append(coordinator->convertPackageRootToPath(packageFQName));
1062
1063 path.append(coordinator->getPackagePath(
Yifan Hong97288ac2016-12-12 16:03:51 -08001064 packageFQName, true /* relative */, true /* sanitized */));
Andreas Huber1c507272016-10-05 14:33:21 -07001065
1066 path.append("Constants.java");
1067 }
1068
1069 CHECK(Coordinator::MakeParentHierarchy(path));
1070 FILE *file = fopen(path.c_str(), "w");
Andreas Huber019d21d2016-10-03 12:59:47 -07001071
1072 if (file == nullptr) {
1073 return -errno;
1074 }
1075
1076 Formatter out(file);
1077
Steven Morelandd177b122016-12-12 09:15:37 -08001078 out << "// This file is autogenerated by hidl-gen. Do not edit manually.\n"
Glenn Kastend18c3ba2017-02-23 16:35:24 -08001079 << "// Source: " << packageFQName.string() << "\n"
1080 << "// Root: " << coordinator->getPackageRootOption(packageFQName) << "\n\n";
Andreas Huber019d21d2016-10-03 12:59:47 -07001081
Andreas Huber1c507272016-10-05 14:33:21 -07001082 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_";
Steven Morelandd177b122016-12-12 09:15:37 -08001089 guard += StringHelper::Uppercase(packageFQName.tokenName());
Andreas Huber1c507272016-10-05 14:33:21 -07001090 guard += "_";
1091 guard += "EXPORTED_CONSTANTS_H_";
Andreas Huber019d21d2016-10-03 12:59:47 -07001092
Andreas Huber1c507272016-10-05 14:33:21 -07001093 out << "#ifndef "
1094 << guard
1095 << "\n#define "
1096 << guard
1097 << "\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n";
Andreas Huber019d21d2016-10-03 12:59:47 -07001098 }
1099
Andreas Huber1c507272016-10-05 14:33:21 -07001100 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 }
Andreas Huber019d21d2016-10-03 12:59:47 -07001112
1113 return OK;
1114}
1115
Steven Morelandf2e44692017-04-18 20:19:09 -07001116static status_t generateHashOutput(const FQName &fqName,
1117 const char* /*hidl_gen*/,
1118 Coordinator *coordinator,
1119 const std::string & /*outputDir*/) {
1120
1121 status_t err;
1122 std::vector<FQName> packageInterfaces;
1123
1124 if (fqName.isFullyQualified()) {
1125 packageInterfaces = {fqName};
1126 } else {
1127 err = coordinator->appendPackageInterfacesToVector(
1128 fqName, &packageInterfaces);
1129 if (err != OK) {
1130 return err;
1131 }
1132 }
1133
1134 for (const auto &currentFqName : packageInterfaces) {
1135 AST *ast = coordinator->parse(currentFqName);
1136
1137 if (ast == NULL) {
1138 fprintf(stderr,
1139 "ERROR: Could not parse %s. Aborting.\n",
1140 currentFqName.string().c_str());
1141
1142 return UNKNOWN_ERROR;
1143 }
1144
1145 printf("%s %s\n",
1146 Hash::getHash(ast->getFilename()).hexString().c_str(),
1147 currentFqName.string().c_str());
1148 }
1149
1150 return OK;
1151}
1152
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001153static std::vector<OutputHandler> formats = {
Steven Moreland3b1ce262017-04-21 14:19:59 -07001154 {"check",
1155 OutputHandler::NOT_NEEDED /* mOutputMode */,
1156 validateForSource,
Steven Morelandbbbbeb82017-05-09 14:20:50 -07001157 generationFunctionForFileOrPackage("check")
Steven Moreland3b1ce262017-04-21 14:19:59 -07001158 },
1159
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001160 {"c++",
Andreas Huber019d21d2016-10-03 12:59:47 -07001161 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001162 validateForSource,
Steven Morelandbbbbeb82017-05-09 14:20:50 -07001163 generationFunctionForFileOrPackage("c++")
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001164 },
1165
Steven Moreland1cbf0362017-05-09 14:32:53 -07001166 {"c++-headers",
1167 OutputHandler::NEEDS_DIR /* mOutputMode */,
1168 validateForSource,
1169 generationFunctionForFileOrPackage("c++-headers")
1170 },
1171
1172 {"c++-sources",
1173 OutputHandler::NEEDS_DIR /* mOutputMode */,
1174 validateForSource,
1175 generationFunctionForFileOrPackage("c++-sources")
1176 },
1177
Andreas Huber019d21d2016-10-03 12:59:47 -07001178 {"export-header",
1179 OutputHandler::NEEDS_FILE /* mOutputMode */,
1180 validateForExportHeader,
1181 [](const FQName &fqName,
1182 const char *hidl_gen,
1183 Coordinator *coordinator,
1184 const std::string &outputPath) -> status_t {
1185 CHECK(!fqName.isFullyQualified());
1186
1187 return generateExportHeaderForPackage(
1188 fqName,
1189 hidl_gen,
1190 coordinator,
Andreas Huber1c507272016-10-05 14:33:21 -07001191 outputPath,
1192 false /* forJava */);
Andreas Huber019d21d2016-10-03 12:59:47 -07001193 }
1194 },
1195
Steven Moreland9c387612016-09-07 09:54:26 -07001196 {"c++-impl",
Andreas Huber019d21d2016-10-03 12:59:47 -07001197 OutputHandler::NEEDS_DIR /* mOutputMode */,
Steven Moreland9c387612016-09-07 09:54:26 -07001198 validateForSource,
Steven Morelandbbbbeb82017-05-09 14:20:50 -07001199 generationFunctionForFileOrPackage("c++-impl")
Steven Moreland9c387612016-09-07 09:54:26 -07001200 },
1201
1202
Andreas Huber2831d512016-08-15 09:33:47 -07001203 {"java",
Andreas Huber019d21d2016-10-03 12:59:47 -07001204 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001205 validateForSource,
Steven Morelandbbbbeb82017-05-09 14:20:50 -07001206 generationFunctionForFileOrPackage("java")
Andreas Huber2831d512016-08-15 09:33:47 -07001207 },
1208
Andreas Huber1c507272016-10-05 14:33:21 -07001209 {"java-constants",
1210 OutputHandler::NEEDS_DIR /* mOutputMode */,
1211 validateForExportHeader,
1212 [](const FQName &fqName,
1213 const char *hidl_gen, Coordinator *coordinator,
1214 const std::string &outputDir) -> status_t {
1215 CHECK(!fqName.isFullyQualified());
1216 return generateExportHeaderForPackage(
1217 fqName,
1218 hidl_gen,
1219 coordinator,
1220 outputDir,
1221 true /* forJava */);
1222 }
1223 },
1224
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001225 {"vts",
Andreas Huber019d21d2016-10-03 12:59:47 -07001226 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001227 validateForSource,
Steven Morelandbbbbeb82017-05-09 14:20:50 -07001228 generationFunctionForFileOrPackage("vts")
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001229 },
1230
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001231 {"makefile",
Andreas Huber019d21d2016-10-03 12:59:47 -07001232 OutputHandler::NOT_NEEDED /* mOutputMode */,
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001233 validateForMakefile,
1234 generateMakefileForPackage,
1235 },
Steven Moreland197d56c2016-09-09 10:03:58 -07001236
Dan Willemsen676abdc2016-09-28 19:42:22 -07001237 {"androidbp",
Andreas Huber019d21d2016-10-03 12:59:47 -07001238 OutputHandler::NOT_NEEDED /* mOutputMode */,
Dan Willemsen676abdc2016-09-28 19:42:22 -07001239 validateForMakefile,
1240 generateAndroidBpForPackage,
1241 },
1242
Yifan Hong958ee462016-12-06 17:09:51 -08001243 {"androidbp-impl",
Yifan Hong94bcea02016-10-06 13:51:31 -07001244 OutputHandler::NEEDS_DIR /* mOutputMode */,
Steven Moreland197d56c2016-09-09 10:03:58 -07001245 validateForMakefile,
Yifan Hong958ee462016-12-06 17:09:51 -08001246 generateAndroidBpImplForPackage,
Steven Morelandf2e44692017-04-18 20:19:09 -07001247 },
1248
1249 {"hash",
1250 OutputHandler::NOT_NEEDED /* mOutputMode */,
1251 validateForSource,
1252 generateHashOutput,
1253 },
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001254};
1255
1256static void usage(const char *me) {
1257 fprintf(stderr,
Steven Morelandf7fa0682017-05-11 16:14:55 -07001258 "usage: %s [-p root-path] -o output-path -L <language> (-r interface-root)+ fqname+\n",
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001259 me);
1260
Steven Morelandf7fa0682017-05-11 16:14:55 -07001261 fprintf(stderr, " -p root path to android build system (defaults to $ANDROID_BUILD_TOP or pwd)\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001262 fprintf(stderr, " -o output path\n");
1263
1264 fprintf(stderr, " -L <language> (one of");
1265 for (auto &e : formats) {
Steven Morelanddd583842017-04-19 13:09:57 -07001266 fprintf(stderr, " %s", e.name().c_str());
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001267 }
1268 fprintf(stderr, ")\n");
1269
1270 fprintf(stderr,
1271 " -r package:path root "
1272 "(e.g., android.hardware:hardware/interfaces)\n");
1273}
1274
Andreas Gampec4ce9262017-04-27 21:03:20 -07001275// hidl is intentionally leaky. Turn off LeakSanitizer by default.
1276extern "C" const char *__asan_default_options() {
1277 return "detect_leaks=0";
1278}
1279
Andreas Huberb82318c2016-08-02 14:45:54 -07001280int main(int argc, char **argv) {
Andreas Huber019d21d2016-10-03 12:59:47 -07001281 std::string outputPath;
Steven Morelandf7fa0682017-05-11 16:14:55 -07001282 std::string rootPath;
Andreas Huberdca261f2016-08-04 13:47:51 -07001283 std::vector<std::string> packageRootPaths;
1284 std::vector<std::string> packageRoots;
Andreas Huberb82318c2016-08-02 14:45:54 -07001285
Andreas Huber737080b2016-08-02 15:38:04 -07001286 const char *me = argv[0];
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001287 OutputHandler *outputFormat = nullptr;
Andreas Huber737080b2016-08-02 15:38:04 -07001288
Steven Moreland3db99f22017-05-11 16:21:46 -07001289 if (argc == 1) {
1290 usage(me);
1291 exit(1);
1292 }
1293
Andreas Huberb82318c2016-08-02 14:45:54 -07001294 int res;
Steven Morelandf7fa0682017-05-11 16:14:55 -07001295 while ((res = getopt(argc, argv, "hp:o:r:L:")) >= 0) {
Andreas Huberb82318c2016-08-02 14:45:54 -07001296 switch (res) {
Steven Morelandf7fa0682017-05-11 16:14:55 -07001297 case 'p':
1298 {
1299 rootPath = optarg;
1300 break;
1301 }
1302
Andreas Huberb82318c2016-08-02 14:45:54 -07001303 case 'o':
1304 {
Andreas Huber019d21d2016-10-03 12:59:47 -07001305 outputPath = optarg;
Andreas Huberb82318c2016-08-02 14:45:54 -07001306 break;
1307 }
1308
Andreas Huberdca261f2016-08-04 13:47:51 -07001309 case 'r':
1310 {
1311 std::string val(optarg);
1312 auto index = val.find_first_of(':');
Steven Moreland4ff74202017-04-21 14:24:47 -07001313 if (index == std::string::npos) {
1314 fprintf(stderr, "ERROR: -r option must contain ':': %s\n", val.c_str());
1315 exit(1);
1316 }
Andreas Huberdca261f2016-08-04 13:47:51 -07001317
1318 auto package = val.substr(0, index);
1319 auto path = val.substr(index + 1);
1320 packageRootPaths.push_back(path);
1321 packageRoots.push_back(package);
1322 break;
1323 }
1324
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001325 case 'L':
1326 {
Steven Morelanddd583842017-04-19 13:09:57 -07001327 if (outputFormat != nullptr) {
1328 fprintf(stderr,
1329 "ERROR: only one -L option allowed. \"%s\" already specified.\n",
1330 outputFormat->name().c_str());
1331 exit(1);
1332 }
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001333 for (auto &e : formats) {
Steven Morelanddd583842017-04-19 13:09:57 -07001334 if (e.name() == optarg) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001335 outputFormat = &e;
1336 break;
1337 }
1338 }
Steven Morelanddd583842017-04-19 13:09:57 -07001339 if (outputFormat == nullptr) {
1340 fprintf(stderr,
1341 "ERROR: unrecognized -L option: \"%s\".\n",
1342 optarg);
1343 exit(1);
1344 }
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001345 break;
1346 }
1347
Andreas Huberb82318c2016-08-02 14:45:54 -07001348 case '?':
1349 case 'h':
1350 default:
1351 {
Andreas Huber737080b2016-08-02 15:38:04 -07001352 usage(me);
Andreas Huberb82318c2016-08-02 14:45:54 -07001353 exit(1);
1354 break;
1355 }
1356 }
1357 }
1358
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001359 if (outputFormat == nullptr) {
Steven Morelanddd583842017-04-19 13:09:57 -07001360 fprintf(stderr,
1361 "ERROR: no -L option provided.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001362 exit(1);
1363 }
1364
Andreas Huberb82318c2016-08-02 14:45:54 -07001365 argc -= optind;
1366 argv += optind;
1367
Steven Morelandf7fa0682017-05-11 16:14:55 -07001368 if (rootPath.empty()) {
1369 const char *ANDROID_BUILD_TOP = getenv("ANDROID_BUILD_TOP");
1370
1371 if (ANDROID_BUILD_TOP != nullptr) {
1372 rootPath = ANDROID_BUILD_TOP;
1373 }
1374
1375 // else default to pwd
1376 }
1377
1378 if (!rootPath.empty() && !StringHelper::EndsWith(rootPath, "/")) {
1379 rootPath += "/";
1380 }
1381
Andreas Huberdca261f2016-08-04 13:47:51 -07001382 if (packageRootPaths.empty()) {
1383 // Pick reasonable defaults.
1384
1385 packageRoots.push_back("android.hardware");
1386
1387 const char *TOP = getenv("TOP");
Steven Morelandaf330382016-11-09 15:48:03 -08001388 if (TOP == nullptr) {
1389 fprintf(stderr,
1390 "ERROR: No root path (-r) specified"
1391 " and $TOP environment variable not set.\n");
1392 exit(1);
1393 }
Andreas Huberdca261f2016-08-04 13:47:51 -07001394
1395 std::string path = TOP;
1396 path.append("/hardware/interfaces");
1397
1398 packageRootPaths.push_back(path);
1399 }
1400
Andreas Huber737080b2016-08-02 15:38:04 -07001401 // Valid options are now in argv[0] .. argv[argc - 1].
1402
Andreas Huber019d21d2016-10-03 12:59:47 -07001403 switch (outputFormat->mOutputMode) {
1404 case OutputHandler::NEEDS_DIR:
1405 case OutputHandler::NEEDS_FILE:
1406 {
1407 if (outputPath.empty()) {
1408 usage(me);
1409 exit(1);
1410 }
1411
1412 if (outputFormat->mOutputMode == OutputHandler::NEEDS_DIR) {
1413 const size_t len = outputPath.size();
1414 if (outputPath[len - 1] != '/') {
1415 outputPath += "/";
1416 }
1417 }
1418 break;
Andreas Huberb82318c2016-08-02 14:45:54 -07001419 }
Andreas Huber019d21d2016-10-03 12:59:47 -07001420
1421 default:
1422 outputPath.clear(); // Unused.
1423 break;
Andreas Huberb82318c2016-08-02 14:45:54 -07001424 }
1425
Steven Morelandf7fa0682017-05-11 16:14:55 -07001426 Coordinator coordinator(packageRootPaths, packageRoots, rootPath);
Andreas Huber5345ec22016-07-29 13:33:27 -07001427
Andreas Huber737080b2016-08-02 15:38:04 -07001428 for (int i = 0; i < argc; ++i) {
Andreas Huber68f24592016-07-29 14:53:48 -07001429 FQName fqName(argv[i]);
Andreas Huber68f24592016-07-29 14:53:48 -07001430
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001431 if (!fqName.isValid()) {
Andreas Hubere61e3f72016-08-03 10:22:03 -07001432 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -07001433 "ERROR: Invalid fully-qualified name.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001434 exit(1);
1435 }
Andreas Huber881227d2016-08-02 14:20:21 -07001436
Andreas Huber0fa9e392016-08-31 09:05:44 -07001437 OutputHandler::ValRes valid =
Steven Morelanddd583842017-04-19 13:09:57 -07001438 outputFormat->validate(fqName, outputFormat->name());
Andreas Huber0fa9e392016-08-31 09:05:44 -07001439
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001440 if (valid == OutputHandler::FAILED) {
Steven Morelandf2e44692017-04-18 20:19:09 -07001441 fprintf(stderr,
1442 "ERROR: output handler failed.\n");
Andreas Hubere61e3f72016-08-03 10:22:03 -07001443 exit(1);
1444 }
Andreas Huberd2943e12016-08-05 11:59:31 -07001445
1446 status_t err =
Andreas Huber019d21d2016-10-03 12:59:47 -07001447 outputFormat->generate(fqName, me, &coordinator, outputPath);
Andreas Huberd2943e12016-08-05 11:59:31 -07001448
1449 if (err != OK) {
Steven Moreland261370a2016-08-29 15:36:59 -07001450 exit(1);
Andreas Huberd2943e12016-08-05 11:59:31 -07001451 }
Andreas Hubereb1081f2016-07-28 13:13:24 -07001452 }
Andreas Huberc9410c72016-07-28 12:18:40 -07001453
Andreas Huberd2943e12016-08-05 11:59:31 -07001454 return 0;
Andreas Huberc9410c72016-07-28 12:18:40 -07001455}