blob: cef969ed501ae6710476bb9adf8672fdff746eba [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 Huber84f89de2016-07-28 15:39:51 -070019#include "FQName.h"
Andreas Huber0fa9e392016-08-31 09:05:44 -070020#include "Scope.h"
Andreas Huberc9410c72016-07-28 12:18:40 -070021
Iliyan Malcheva72e0d22016-09-09 11:03:08 -070022#include <hidl-util/Formatter.h>
Andreas Huber68f24592016-07-29 14:53:48 -070023#include <android-base/logging.h>
Iliyan Malchev5bb14022016-08-09 15:04:39 -070024#include <set>
Andreas Huberc9410c72016-07-28 12:18:40 -070025#include <stdio.h>
Andreas Huberdca261f2016-08-04 13:47:51 -070026#include <string>
Andreas Huberb82318c2016-08-02 14:45:54 -070027#include <unistd.h>
Andreas Huberdca261f2016-08-04 13:47:51 -070028#include <vector>
Andreas Huberc9410c72016-07-28 12:18:40 -070029
30using namespace android;
31
Iliyan Malchev5bb14022016-08-09 15:04:39 -070032struct OutputHandler {
33 std::string mKey;
Andreas Huber019d21d2016-10-03 12:59:47 -070034 enum OutputMode {
35 NEEDS_DIR,
36 NEEDS_FILE,
37 NOT_NEEDED
38 } mOutputMode;
39
Iliyan Malchev5bb14022016-08-09 15:04:39 -070040 enum ValRes {
41 FAILED,
42 PASS_PACKAGE,
43 PASS_FULL
44 };
Andreas Huber0fa9e392016-08-31 09:05:44 -070045 ValRes (*validate)(const FQName &, const std::string &language);
Iliyan Malchev5bb14022016-08-09 15:04:39 -070046 status_t (*generate)(const FQName &fqName,
47 const char *hidl_gen,
48 Coordinator *coordinator,
49 const std::string &outputDir);
50};
Andreas Huberdca261f2016-08-04 13:47:51 -070051
Iliyan Malchev5bb14022016-08-09 15:04:39 -070052static status_t generateSourcesForFile(
53 const FQName &fqName,
54 const char *,
55 Coordinator *coordinator,
Andreas Huber2831d512016-08-15 09:33:47 -070056 const std::string &outputDir,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070057 const std::string &lang) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -070058 CHECK(fqName.isFullyQualified());
59
Andreas Huber0fa9e392016-08-31 09:05:44 -070060 AST *ast;
Andreas Huberd29724f2016-09-14 09:33:13 -070061 std::string limitToType;
Andreas Huber0fa9e392016-08-31 09:05:44 -070062
63 if (fqName.name().find("types.") == 0) {
64 CHECK(lang == "java"); // Already verified in validate().
65
Andreas Huberd29724f2016-09-14 09:33:13 -070066 limitToType = fqName.name().substr(strlen("types."));
Andreas Huber0fa9e392016-08-31 09:05:44 -070067
68 FQName typesName(fqName.package(), fqName.version(), "types");
69 ast = coordinator->parse(typesName);
70 } else {
71 ast = coordinator->parse(fqName);
72 }
Iliyan Malchev5bb14022016-08-09 15:04:39 -070073
74 if (ast == NULL) {
75 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -070076 "ERROR: Could not parse %s. Aborting.\n",
Iliyan Malchev5bb14022016-08-09 15:04:39 -070077 fqName.string().c_str());
78
79 return UNKNOWN_ERROR;
80 }
81
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070082 if (lang == "c++") {
83 return ast->generateCpp(outputDir);
84 }
Steven Moreland9c387612016-09-07 09:54:26 -070085 if (lang == "c++-impl") {
86 return ast->generateCppImpl(outputDir);
87 }
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070088 if (lang == "java") {
Andreas Huber0fa9e392016-08-31 09:05:44 -070089 return ast->generateJava(outputDir, limitToType);
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070090 }
91 if (lang == "vts") {
92 return ast->generateVts(outputDir);
93 }
94 // Unknown language.
95 return UNKNOWN_ERROR;
Iliyan Malchev5bb14022016-08-09 15:04:39 -070096}
97
98static status_t generateSourcesForPackage(
99 const FQName &packageFQName,
100 const char *hidl_gen,
101 Coordinator *coordinator,
Andreas Huber2831d512016-08-15 09:33:47 -0700102 const std::string &outputDir,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700103 const std::string &lang) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700104 CHECK(packageFQName.isValid() &&
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700105 !packageFQName.isFullyQualified() &&
106 packageFQName.name().empty());
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700107
108 std::vector<FQName> packageInterfaces;
109
110 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700111 coordinator->appendPackageInterfacesToVector(packageFQName,
112 &packageInterfaces);
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700113
114 if (err != OK) {
115 return err;
116 }
117
118 for (const auto &fqName : packageInterfaces) {
Andreas Huber2831d512016-08-15 09:33:47 -0700119 err = generateSourcesForFile(
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700120 fqName, hidl_gen, coordinator, outputDir, lang);
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700121 if (err != OK) {
122 return err;
123 }
124 }
125
126 return OK;
Andreas Huberb82318c2016-08-02 14:45:54 -0700127}
128
Andreas Huberd2943e12016-08-05 11:59:31 -0700129static std::string makeLibraryName(const FQName &packageFQName) {
Iliyan Malcheve2c595a2016-08-07 21:20:04 -0700130 return packageFQName.string();
Andreas Huberd2943e12016-08-05 11:59:31 -0700131}
132
Dan Willemsen676abdc2016-09-28 19:42:22 -0700133static void generateMakefileSectionForType(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700134 Formatter &out,
135 Coordinator *coordinator,
136 const FQName &packageFQName,
137 const FQName &fqName,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700138 const char *typeName) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700139 out << "\n"
140 << "\n#"
141 << "\n# Build " << fqName.name() << ".hal";
142
Dan Willemsen676abdc2016-09-28 19:42:22 -0700143 if (typeName != nullptr) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700144 out << " (" << typeName << ")";
145 }
146
147 out << "\n#"
148 << "\nGEN := $(intermediates)/"
149 << coordinator->convertPackageRootToPath(packageFQName)
150 << coordinator->getPackagePath(packageFQName, true /* relative */);
Dan Willemsen676abdc2016-09-28 19:42:22 -0700151 if (typeName == nullptr) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700152 out << fqName.name() << ".java";
153 } else {
154 out << typeName << ".java";
155 }
156
157 out << "\n$(GEN): $(HIDL)";
158 out << "\n$(GEN): PRIVATE_HIDL := $(HIDL)";
159 out << "\n$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/"
160 << fqName.name() << ".hal";
Iliyan Malchevb9819132016-09-07 12:38:31 -0700161
162 {
163 AST *ast = coordinator->parse(fqName);
164 CHECK(ast != nullptr);
165 const std::set<FQName>& refs = ast->getImportedNames();
166 for (auto depFQName : refs) {
167 // If the package of depFQName is the same as this fqName's package,
168 // then add it explicitly as a .hal dependency within the same
169 // package.
170 if (fqName.package() == depFQName.package() &&
171 fqName.version() == depFQName.version()) {
172 // PRIVATE_DEPS is not actually being used in the
173 // auto-generated file, but is necessary if the build rule
174 // ever needs to use the dependency information, since the
175 // built-in Make variables are not supported in the Android
176 // build system.
177 out << "\n$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/"
178 << depFQName.name() << ".hal";
179 // This is the actual dependency.
180 out << "\n$(GEN): $(LOCAL_PATH)/"
181 << depFQName.name() << ".hal";
182 }
183 }
184 }
185
Andreas Huber0fa9e392016-08-31 09:05:44 -0700186 out << "\n$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)"
187 << "\n$(GEN): PRIVATE_CUSTOM_TOOL = \\";
188 out.indent();
189 out.indent();
190 out << "\n$(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \\"
Dan Willemsen676abdc2016-09-28 19:42:22 -0700191 << "\n-Ljava"
Andreas Huber0fa9e392016-08-31 09:05:44 -0700192 << " -r"
193 << coordinator->getPackageRoot(packageFQName) << ":"
194 << coordinator->getPackageRootPath(packageFQName) << " \\\n";
195
196 out << packageFQName.string()
197 << "::"
198 << fqName.name();
199
Dan Willemsen676abdc2016-09-28 19:42:22 -0700200 if (typeName != nullptr) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700201 out << "." << typeName;
202 }
203
204 out << "\n";
205
206 out.unindent();
207 out.unindent();
208
209 out << "\n$(GEN): $(LOCAL_PATH)/" << fqName.name() << ".hal";
210 out << "\n\t$(transform-generated-source)";
211 out << "\nLOCAL_GENERATED_SOURCES += $(GEN)";
212}
213
Dan Willemsen676abdc2016-09-28 19:42:22 -0700214static void generateMakefileSection(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700215 Formatter &out,
216 Coordinator *coordinator,
217 const FQName &packageFQName,
218 const std::vector<FQName> &packageInterfaces,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700219 AST *typesAST) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700220 for (const auto &fqName : packageInterfaces) {
Dan Willemsen676abdc2016-09-28 19:42:22 -0700221 if (fqName.name() == "types") {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700222 CHECK(typesAST != nullptr);
223
224 Scope *rootScope = typesAST->scope();
Andreas Huber0fa9e392016-08-31 09:05:44 -0700225
Andreas Huberb747bd92016-09-26 15:55:31 -0700226 std::vector<NamedType *> subTypes = rootScope->getSubTypes();
227 std::sort(
228 subTypes.begin(),
229 subTypes.end(),
230 [](const NamedType *a, const NamedType *b) -> bool {
231 return a->fqName() < b->fqName();
232 });
233
234 for (const auto &type : subTypes) {
Andreas Huberdda25cc2016-09-22 10:39:47 -0700235 if (type->isTypeDef()) {
236 continue;
237 }
238
Dan Willemsen676abdc2016-09-28 19:42:22 -0700239 generateMakefileSectionForType(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700240 out,
241 coordinator,
242 packageFQName,
243 fqName,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700244 type->localName().c_str());
Andreas Huber0fa9e392016-08-31 09:05:44 -0700245 }
246
247 continue;
248 }
249
Dan Willemsen676abdc2016-09-28 19:42:22 -0700250 generateMakefileSectionForType(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700251 out,
252 coordinator,
253 packageFQName,
254 fqName,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700255 nullptr /* typeName */);
Andreas Huber0fa9e392016-08-31 09:05:44 -0700256 }
257}
258
Andreas Huber75ae95d2016-10-12 16:08:26 -0700259static status_t isPackageJavaCompatible(
260 const FQName &packageFQName,
261 Coordinator *coordinator,
262 bool *compatible) {
263 std::vector<FQName> todo;
264 status_t err =
265 coordinator->appendPackageInterfacesToVector(packageFQName, &todo);
266
267 if (err != OK) {
268 return err;
269 }
270
271 std::set<FQName> seen;
272 for (const auto &iface : todo) {
273 seen.insert(iface);
274 }
275
276 // Form the transitive closure of all imported interfaces (and types.hal-s)
277 // If any one of them is not java compatible, this package isn't either.
278 while (!todo.empty()) {
279 const FQName fqName = todo.back();
280 todo.pop_back();
281
282 AST *ast = coordinator->parse(fqName);
283
284 if (ast == nullptr) {
285 return UNKNOWN_ERROR;
286 }
287
288 if (!ast->isJavaCompatible()) {
289 *compatible = false;
290 return OK;
291 }
292
293 std::set<FQName> importedPackages;
294 ast->getImportedPackages(&importedPackages);
295
296 for (const auto &package : importedPackages) {
297 std::vector<FQName> packageInterfaces;
298 status_t err = coordinator->appendPackageInterfacesToVector(
299 package, &packageInterfaces);
300
301 if (err != OK) {
302 return err;
303 }
304
305 for (const auto &iface : packageInterfaces) {
306 if (seen.find(iface) != seen.end()) {
307 continue;
308 }
309
310 todo.push_back(iface);
311 seen.insert(iface);
312 }
313 }
314 }
315
316 *compatible = true;
317 return OK;
318}
319
Andreas Huber5a9fe2c2016-10-13 15:31:10 -0700320static bool packageNeedsJavaCode(
321 const std::vector<FQName> &packageInterfaces, AST *typesAST) {
322 // If there is more than just a types.hal file to this package we'll
323 // definitely need to generate Java code.
324 if (packageInterfaces.size() > 1
325 || packageInterfaces[0].name() != "types") {
326 return true;
327 }
328
329 CHECK(typesAST != nullptr);
330
331 // We'll have to generate Java code if types.hal contains any non-typedef
332 // type declarations.
333
334 Scope *rootScope = typesAST->scope();
335 std::vector<NamedType *> subTypes = rootScope->getSubTypes();
336
337 for (const auto &subType : subTypes) {
338 if (!subType->isTypeDef()) {
339 return true;
340 }
341 }
342
343 return false;
344}
345
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700346static status_t generateMakefileForPackage(
347 const FQName &packageFQName,
Iliyan Malchevb66c3992016-08-07 21:18:13 -0700348 const char *hidl_gen,
Andreas Huberd2943e12016-08-05 11:59:31 -0700349 Coordinator *coordinator,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700350 const std::string &) {
351
352 CHECK(packageFQName.isValid() &&
353 !packageFQName.isFullyQualified() &&
354 packageFQName.name().empty());
355
Andreas Huberd2943e12016-08-05 11:59:31 -0700356 std::vector<FQName> packageInterfaces;
357
358 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700359 coordinator->appendPackageInterfacesToVector(packageFQName,
360 &packageInterfaces);
Andreas Huberd2943e12016-08-05 11:59:31 -0700361
362 if (err != OK) {
363 return err;
364 }
365
366 std::set<FQName> importedPackages;
Andreas Huber0fa9e392016-08-31 09:05:44 -0700367 AST *typesAST = nullptr;
368
Andreas Huberd2943e12016-08-05 11:59:31 -0700369 for (const auto &fqName : packageInterfaces) {
370 AST *ast = coordinator->parse(fqName);
371
372 if (ast == NULL) {
373 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700374 "ERROR: Could not parse %s. Aborting.\n",
Andreas Huberd2943e12016-08-05 11:59:31 -0700375 fqName.string().c_str());
376
377 return UNKNOWN_ERROR;
378 }
379
Andreas Huber0fa9e392016-08-31 09:05:44 -0700380 if (fqName.name() == "types") {
381 typesAST = ast;
382 }
383
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700384 ast->getImportedPackages(&importedPackages);
Andreas Huberd2943e12016-08-05 11:59:31 -0700385 }
386
Andreas Huber75ae95d2016-10-12 16:08:26 -0700387 bool packageIsJavaCompatible;
388 err = isPackageJavaCompatible(
389 packageFQName, coordinator, &packageIsJavaCompatible);
390
391 if (err != OK) {
392 return err;
393 }
394
Dan Willemsen676abdc2016-09-28 19:42:22 -0700395 if (!packageIsJavaCompatible) {
396 return OK;
397 }
398
Andreas Huber5a9fe2c2016-10-13 15:31:10 -0700399 if (!packageNeedsJavaCode(packageInterfaces, typesAST)) {
400 return OK;
401 }
402
Andreas Huberd2943e12016-08-05 11:59:31 -0700403 std::string path =
404 coordinator->getPackagePath(packageFQName, false /* relative */);
405
406 path.append("Android.mk");
407
408 CHECK(Coordinator::MakeParentHierarchy(path));
409 FILE *file = fopen(path.c_str(), "w");
410
411 if (file == NULL) {
412 return -errno;
413 }
414
415 const std::string libraryName = makeLibraryName(packageFQName);
416
417 Formatter out(file);
418
Dan Willemsen676abdc2016-09-28 19:42:22 -0700419 out << "# This file is autogenerated by hidl-gen. Do not edit manually.\n\n";
420 out << "LOCAL_PATH := $(call my-dir)\n";
Andreas Huberd2943e12016-08-05 11:59:31 -0700421
Dan Willemsen676abdc2016-09-28 19:42:22 -0700422 enum LibraryStyle {
423 LIBRARY_STYLE_REGULAR,
424 LIBRARY_STYLE_STATIC,
425 LIBRARY_STYLE_END,
426 };
Andreas Huberd2943e12016-08-05 11:59:31 -0700427
Dan Willemsen676abdc2016-09-28 19:42:22 -0700428 for (int style = LIBRARY_STYLE_REGULAR; style != LIBRARY_STYLE_END;
429 ++style) {
430 const std::string staticSuffix =
431 (style == LIBRARY_STYLE_STATIC) ? "-static" : "";
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700432
Dan Willemsen676abdc2016-09-28 19:42:22 -0700433 out << "\n"
434 << "########################################"
435 << "########################################\n\n";
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700436
Dan Willemsen676abdc2016-09-28 19:42:22 -0700437 out << "include $(CLEAR_VARS)\n"
438 << "LOCAL_MODULE := "
439 << libraryName
440 << "-java"
441 << staticSuffix
442 << "\nLOCAL_MODULE_CLASS := JAVA_LIBRARIES\n\n"
443 << "intermediates := $(local-generated-sources-dir)\n\n"
444 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
445 << hidl_gen
446 << "$(HOST_EXECUTABLE_SUFFIX)";
Andreas Huberd2943e12016-08-05 11:59:31 -0700447
Dan Willemsen676abdc2016-09-28 19:42:22 -0700448 if (!importedPackages.empty()) {
Iliyan Malchev800273d2016-09-02 15:25:07 -0700449 out << "\n"
Dan Willemsen676abdc2016-09-28 19:42:22 -0700450 << "\nLOCAL_"
Andreas Huber782d45e2016-09-22 13:25:14 -0700451 << ((style == LIBRARY_STYLE_STATIC) ? "STATIC_" : "")
Dan Willemsen676abdc2016-09-28 19:42:22 -0700452 << "JAVA_LIBRARIES := \\";
453
454 out.indent();
455 for (const auto &importedPackage : importedPackages) {
456 out << "\n"
457 << makeLibraryName(importedPackage)
458 << "-java"
459 << staticSuffix
460 << " \\";
461 }
462 out << "\n";
463 out.unindent();
Iliyan Malchev800273d2016-09-02 15:25:07 -0700464 }
Dan Willemsen676abdc2016-09-28 19:42:22 -0700465
466 generateMakefileSection(
467 out,
468 coordinator,
469 packageFQName,
470 packageInterfaces,
471 typesAST);
472
473 out << "\ninclude $(BUILD_"
474 << ((style == LIBRARY_STYLE_STATIC) ? "STATIC_" : "")
475 << "JAVA_LIBRARY)\n\n";
Andreas Huber0fa9e392016-08-31 09:05:44 -0700476 }
477
Iliyan Malchev8be09552016-09-22 16:20:33 -0700478 out << "\n\n"
479 << "include $(call all-makefiles-under,$(LOCAL_PATH))\n";
480
Andreas Huberd2943e12016-08-05 11:59:31 -0700481 return OK;
482}
483
Andreas Huber0fa9e392016-08-31 09:05:44 -0700484OutputHandler::ValRes validateForMakefile(
485 const FQName &fqName, const std::string & /* language */) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700486 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700487 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700488 return OutputHandler::FAILED;
489 }
490
491 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700492 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700493 return OutputHandler::FAILED;
494 }
495
496 if (!fqName.name().empty()) {
497 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700498 "ERROR: Expecting only package name and version.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700499 return OutputHandler::FAILED;
500 }
501
502 return OutputHandler::PASS_PACKAGE;
503}
504
Dan Willemsen676abdc2016-09-28 19:42:22 -0700505static void generateAndroidBpGenSection(
506 Formatter &out,
507 const FQName &packageFQName,
508 const char *hidl_gen,
509 Coordinator *coordinator,
510 const std::string &genName,
511 const char *language,
512 const std::vector<FQName> &packageInterfaces,
513 const std::function<void(Formatter&, const FQName)> outputFn) {
514
515 out << "genrule {\n";
516 out.indent();
517 out << "name: \"" << genName << "\",\n"
518 << "tool: \"" << hidl_gen << "\",\n";
519
520 out << "cmd: \"$tool -o $genDir"
521 << " -L" << language
522 << " -r"
523 << coordinator->getPackageRoot(packageFQName) << ":"
524 << coordinator->getPackageRootPath(packageFQName)
525 << " " << packageFQName.string() << "\",\n";
526
527 out << "srcs: [\n";
528 out.indent();
529 for (const auto &fqName : packageInterfaces) {
530 out << "\"" << fqName.name() << ".hal\",\n";
531 }
532 out.unindent();
533 out << "],\n";
534
535 out << "out: [\n";
536 out.indent();
537 for (const auto &fqName : packageInterfaces) {
538 outputFn(out, fqName);
539 }
540 out.unindent();
541 out << "],\n";
542
543 out.unindent();
544 out << "}\n\n";
545}
546
547static status_t generateAndroidBpForPackage(
548 const FQName &packageFQName,
549 const char *hidl_gen,
550 Coordinator *coordinator,
551 const std::string &) {
552
553 CHECK(packageFQName.isValid() &&
554 !packageFQName.isFullyQualified() &&
555 packageFQName.name().empty());
556
557 std::vector<FQName> packageInterfaces;
558
559 status_t err =
560 coordinator->appendPackageInterfacesToVector(packageFQName,
561 &packageInterfaces);
562
563 if (err != OK) {
564 return err;
565 }
566
567 std::set<FQName> importedPackages;
568 AST *typesAST = nullptr;
569
570 for (const auto &fqName : packageInterfaces) {
571 AST *ast = coordinator->parse(fqName);
572
573 if (ast == NULL) {
574 fprintf(stderr,
575 "ERROR: Could not parse %s. Aborting.\n",
576 fqName.string().c_str());
577
578 return UNKNOWN_ERROR;
579 }
580
581 if (fqName.name() == "types") {
582 typesAST = ast;
583 }
584
585 ast->getImportedPackages(&importedPackages);
586 }
587
588 std::string path =
589 coordinator->getPackagePath(packageFQName, false /* relative */);
590
591 path.append("Android.bp");
592
593 CHECK(Coordinator::MakeParentHierarchy(path));
594 FILE *file = fopen(path.c_str(), "w");
595
596 if (file == NULL) {
597 return -errno;
598 }
599
600 const std::string libraryName = makeLibraryName(packageFQName);
601 const std::string genSourceName = libraryName + "_genc++";
602 const std::string genHeaderName = libraryName + "_genc++_headers";
603 const std::string pathPrefix =
604 coordinator->convertPackageRootToPath(packageFQName) +
605 coordinator->getPackagePath(packageFQName, true /* relative */);
606
607 Formatter out(file);
608
609 out << "// This file is autogenerated by hidl-gen. Do not edit manually.\n\n";
610
611 // Rule to generate the C++ source files
612 generateAndroidBpGenSection(
613 out,
614 packageFQName,
615 hidl_gen,
616 coordinator,
617 genSourceName,
618 "c++",
619 packageInterfaces,
620 [&pathPrefix](Formatter &out, const FQName &fqName) {
621 if (fqName.name() == "types") {
622 out << "\"" << pathPrefix << "types.cpp\",\n";
623 } else {
624 out << "\"" << pathPrefix << fqName.name().substr(1) << "All.cpp\",\n";
625 }
626 });
627
628 // Rule to generate the C++ header files
629 generateAndroidBpGenSection(
630 out,
631 packageFQName,
632 hidl_gen,
633 coordinator,
634 genHeaderName,
635 "c++",
636 packageInterfaces,
637 [&pathPrefix](Formatter &out, const FQName &fqName) {
638 out << "\"" << pathPrefix << fqName.name() << ".h\",\n";
639 if (fqName.name() != "types") {
640 out << "\"" << pathPrefix << "IHw" << fqName.name().substr(1) << ".h\",\n";
641 out << "\"" << pathPrefix << "Bn" << fqName.name().substr(1) << ".h\",\n";
642 out << "\"" << pathPrefix << "Bp" << fqName.name().substr(1) << ".h\",\n";
643 out << "\"" << pathPrefix << "Bs" << fqName.name().substr(1) << ".h\",\n";
644 }
645 });
646
647 // C++ library definition
648 out << "cc_library_shared {\n";
649 out.indent();
650 out << "name: \"" << libraryName << "\",\n"
651 << "generated_sources: [\"" << genSourceName << "\"],\n"
652 << "generated_headers: [\"" << genHeaderName << "\"],\n"
653 << "export_generated_headers: [\"" << genHeaderName << "\"],\n"
654 << "shared_libs: [\n";
655
656 out.indent();
657 out << "\"libhidl\",\n"
658 << "\"libhwbinder\",\n"
659 << "\"libutils\",\n"
660 << "\"libcutils\",\n";
661 for (const auto &importedPackage : importedPackages) {
662 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
663 }
664 out.unindent();
665
666 out << "],\n";
667 out.unindent();
Steven Morelandb8a26c02016-10-21 13:40:14 -0700668
669 out << "export_shared_lib_headers: [\n";
670 out.indent();
671 out << "\"libhidl\",\n"
672 << "\"libhwbinder\",\n"
673 << "\"libutils\",\n"
674 << "],\n";
675 out.unindent();
676
Dan Willemsen676abdc2016-09-28 19:42:22 -0700677 out << "}\n";
678
679 return OK;
680}
681
Steven Moreland197d56c2016-09-09 10:03:58 -0700682static status_t generateMakefileImplForPackage(
683 const FQName &packageFQName,
684 const char *,
685 Coordinator *coordinator,
686 const std::string &outputDir) {
687
Iliyan Malchev4923f932016-09-09 13:04:59 -0700688 const std::string libraryName = makeLibraryName(packageFQName) + "-impl";
Steven Moreland197d56c2016-09-09 10:03:58 -0700689
690 std::vector<FQName> packageInterfaces;
691
692 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700693 coordinator->appendPackageInterfacesToVector(packageFQName,
694 &packageInterfaces);
Steven Moreland197d56c2016-09-09 10:03:58 -0700695
696 if (err != OK) {
697 return err;
698 }
699
700 std::set<FQName> importedPackages;
701
702 for (const auto &fqName : packageInterfaces) {
703 AST *ast = coordinator->parse(fqName);
704
705 if (ast == NULL) {
706 fprintf(stderr,
707 "ERROR: Could not parse %s. Aborting.\n",
708 fqName.string().c_str());
709
710 return UNKNOWN_ERROR;
711 }
712
713 ast->getImportedPackages(&importedPackages);
714 }
715
716 std::string path = outputDir + "Android.mk";
717
718 CHECK(Coordinator::MakeParentHierarchy(path));
719 FILE *file = fopen(path.c_str(), "w");
720
721 if (file == NULL) {
722 return -errno;
723 }
724
725 Formatter out(file);
726
727 out << "LOCAL_PATH := $(call my-dir)\n\n"
728 << "include $(CLEAR_VARS)\n"
729 << "LOCAL_MODULE := " << libraryName << "\n"
730 << "LOCAL_MODULE_RELATIVE_PATH := hw\n"
731 << "LOCAL_SRC_FILES := \\\n";
732 out.indent();
733 for (const auto &fqName : packageInterfaces) {
734 if (fqName.name() == "types") {
735 continue;
736 }
737 out << fqName.getInterfaceBaseName() << ".cpp \\\n";
738 }
739 out.unindent();
740 out << "\n";
741 out << "LOCAL_SHARED_LIBRARIES := \\\n";
742 out.indent();
743 out << "libhidl \\\n"
744 << "libhwbinder \\\n"
745 << "libutils \\\n"
746 << makeLibraryName(packageFQName) << " \\\n";
Yifan Honge0f7d692016-10-20 17:51:33 -0700747
748 for (const auto &importedPackage : importedPackages) {
749 out << makeLibraryName(importedPackage)
750 << " \\\n";
751 }
Steven Moreland197d56c2016-09-09 10:03:58 -0700752 out.unindent();
753 out << "\n";
754
755 out << "include $(BUILD_SHARED_LIBRARY)\n";
756
757 return OK;
758}
759
Andreas Huber0fa9e392016-08-31 09:05:44 -0700760OutputHandler::ValRes validateForSource(
761 const FQName &fqName, const std::string &language) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700762 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700763 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700764 return OutputHandler::FAILED;
765 }
766
767 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700768 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700769 return OutputHandler::FAILED;
770 }
771
Andreas Huber0fa9e392016-08-31 09:05:44 -0700772 const std::string &name = fqName.name();
773 if (!name.empty()) {
774 if (name.find('.') == std::string::npos) {
775 return OutputHandler::PASS_FULL;
776 }
777
778 if (language != "java" || name.find("types.") != 0) {
779 // When generating java sources for "types.hal", output can be
780 // constrained to just one of the top-level types declared
781 // by using the extended syntax
782 // android.hardware.Foo@1.0::types.TopLevelTypeName.
783 // In all other cases (different language, not 'types') the dot
784 // notation in the name is illegal in this context.
785 return OutputHandler::FAILED;
786 }
787
788 return OutputHandler::PASS_FULL;
789 }
790
791 return OutputHandler::PASS_PACKAGE;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700792}
793
Andreas Huber019d21d2016-10-03 12:59:47 -0700794OutputHandler::ValRes validateForExportHeader(
795 const FQName &fqName, const std::string & /* language */) {
796 if (fqName.package().empty()) {
797 fprintf(stderr, "ERROR: Expecting package name\n");
798 return OutputHandler::FAILED;
799 }
800
801 if (fqName.version().empty()) {
802 fprintf(stderr, "ERROR: Expecting package version\n");
803 return OutputHandler::FAILED;
804 }
805
806 if (!fqName.name().empty()) {
807 fprintf(stderr,
808 "ERROR: Expecting only package name and version.\n");
809 return OutputHandler::FAILED;
810 }
811
812 return OutputHandler::PASS_PACKAGE;
813}
814
815
816static status_t generateExportHeaderForPackage(
817 const FQName &packageFQName,
818 const char * /* hidl_gen */,
819 Coordinator *coordinator,
820 const std::string &outputPath) {
821
822 CHECK(packageFQName.isValid()
823 && !packageFQName.isFullyQualified()
824 && packageFQName.name().empty());
825
826 std::vector<FQName> packageInterfaces;
827
828 status_t err = coordinator->appendPackageInterfacesToVector(
829 packageFQName, &packageInterfaces);
830
831 if (err != OK) {
832 return err;
833 }
834
835 std::vector<const Type *> exportedTypes;
836
837 for (const auto &fqName : packageInterfaces) {
838 AST *ast = coordinator->parse(fqName);
839
840 if (ast == NULL) {
841 fprintf(stderr,
842 "ERROR: Could not parse %s. Aborting.\n",
843 fqName.string().c_str());
844
845 return UNKNOWN_ERROR;
846 }
847
848 ast->appendToExportedTypesVector(&exportedTypes);
849 }
850
851 if (exportedTypes.empty()) {
852 return OK;
853 }
854
855 CHECK(Coordinator::MakeParentHierarchy(outputPath));
856 FILE *file = fopen(outputPath.c_str(), "w");
857
858 if (file == nullptr) {
859 return -errno;
860 }
861
862 Formatter out(file);
863
864 out << "// This file is autogenerated by hidl-gen. Do not edit manually."
865 "\n\n";
866
867 std::string guard = "HIDL_GENERATED_";
868 guard += packageFQName.tokenName();
869 guard += "_";
870 guard += "EXPORTED_CONSTANTS_H_";
871
872 out << "#ifndef "
873 << guard
874 << "\n#define "
875 << guard
876 << "\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n";
877
878 for (const auto &type : exportedTypes) {
879 type->emitExportedHeader(out);
880 }
881
882 out << "#ifdef __cplusplus\n}\n#endif\n\n#endif // "
883 << guard
884 << "\n";
885
886 return OK;
887}
888
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700889static std::vector<OutputHandler> formats = {
890 {"c++",
Andreas Huber019d21d2016-10-03 12:59:47 -0700891 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700892 validateForSource,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700893 [](const FQName &fqName,
894 const char *hidl_gen, Coordinator *coordinator,
895 const std::string &outputDir) -> status_t {
896 if (fqName.isFullyQualified()) {
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700897 return generateSourcesForFile(fqName,
898 hidl_gen,
899 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700900 outputDir,
901 "c++");
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700902 } else {
903 return generateSourcesForPackage(fqName,
904 hidl_gen,
905 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700906 outputDir,
907 "c++");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700908 }
909 }
910 },
911
Andreas Huber019d21d2016-10-03 12:59:47 -0700912 {"export-header",
913 OutputHandler::NEEDS_FILE /* mOutputMode */,
914 validateForExportHeader,
915 [](const FQName &fqName,
916 const char *hidl_gen,
917 Coordinator *coordinator,
918 const std::string &outputPath) -> status_t {
919 CHECK(!fqName.isFullyQualified());
920
921 return generateExportHeaderForPackage(
922 fqName,
923 hidl_gen,
924 coordinator,
925 outputPath);
926 }
927 },
928
Steven Moreland9c387612016-09-07 09:54:26 -0700929 {"c++-impl",
Andreas Huber019d21d2016-10-03 12:59:47 -0700930 OutputHandler::NEEDS_DIR /* mOutputMode */,
Steven Moreland9c387612016-09-07 09:54:26 -0700931 validateForSource,
932 [](const FQName &fqName,
933 const char *hidl_gen, Coordinator *coordinator,
934 const std::string &outputDir) -> status_t {
935 if (fqName.isFullyQualified()) {
936 return generateSourcesForFile(fqName,
937 hidl_gen,
938 coordinator,
939 outputDir, "c++-impl");
940 } else {
941 return generateSourcesForPackage(fqName,
942 hidl_gen,
943 coordinator,
944 outputDir, "c++-impl");
945 }
946 }
947 },
948
949
Andreas Huber2831d512016-08-15 09:33:47 -0700950 {"java",
Andreas Huber019d21d2016-10-03 12:59:47 -0700951 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700952 validateForSource,
Andreas Huber2831d512016-08-15 09:33:47 -0700953 [](const FQName &fqName,
954 const char *hidl_gen, Coordinator *coordinator,
955 const std::string &outputDir) -> status_t {
956 if (fqName.isFullyQualified()) {
957 return generateSourcesForFile(fqName,
958 hidl_gen,
959 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700960 outputDir,
961 "java");
Andreas Huber2831d512016-08-15 09:33:47 -0700962 }
963 else {
964 return generateSourcesForPackage(fqName,
965 hidl_gen,
966 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700967 outputDir,
968 "java");
Andreas Huber2831d512016-08-15 09:33:47 -0700969 }
970 }
971 },
972
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700973 {"vts",
Andreas Huber019d21d2016-10-03 12:59:47 -0700974 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700975 validateForSource,
976 [](const FQName &fqName,
977 const char * hidl_gen,
978 Coordinator *coordinator,
979 const std::string &outputDir) -> status_t {
980 if (fqName.isFullyQualified()) {
981 return generateSourcesForFile(fqName,
982 hidl_gen,
983 coordinator,
984 outputDir, "vts");
985 } else {
986 return generateSourcesForPackage(fqName,
987 hidl_gen,
988 coordinator,
989 outputDir, "vts");
990 }
991 }
992 },
993
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700994 {"makefile",
Andreas Huber019d21d2016-10-03 12:59:47 -0700995 OutputHandler::NOT_NEEDED /* mOutputMode */,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700996 validateForMakefile,
997 generateMakefileForPackage,
998 },
Steven Moreland197d56c2016-09-09 10:03:58 -0700999
Dan Willemsen676abdc2016-09-28 19:42:22 -07001000 {"androidbp",
Andreas Huber019d21d2016-10-03 12:59:47 -07001001 OutputHandler::NOT_NEEDED /* mOutputMode */,
Dan Willemsen676abdc2016-09-28 19:42:22 -07001002 validateForMakefile,
1003 generateAndroidBpForPackage,
1004 },
1005
Steven Moreland197d56c2016-09-09 10:03:58 -07001006 {"makefile-impl",
Yifan Hong94bcea02016-10-06 13:51:31 -07001007 OutputHandler::NEEDS_DIR /* mOutputMode */,
Steven Moreland197d56c2016-09-09 10:03:58 -07001008 validateForMakefile,
1009 generateMakefileImplForPackage,
1010 }
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001011};
1012
1013static void usage(const char *me) {
1014 fprintf(stderr,
1015 "usage: %s -o output-path -L <language> (-r interface-root)+ fqname+\n",
1016 me);
1017
1018 fprintf(stderr, " -o output path\n");
1019
1020 fprintf(stderr, " -L <language> (one of");
1021 for (auto &e : formats) {
1022 fprintf(stderr, " %s", e.mKey.c_str());
1023 }
1024 fprintf(stderr, ")\n");
1025
1026 fprintf(stderr,
1027 " -r package:path root "
1028 "(e.g., android.hardware:hardware/interfaces)\n");
1029}
1030
Andreas Huberb82318c2016-08-02 14:45:54 -07001031int main(int argc, char **argv) {
Andreas Huber019d21d2016-10-03 12:59:47 -07001032 std::string outputPath;
Andreas Huberdca261f2016-08-04 13:47:51 -07001033 std::vector<std::string> packageRootPaths;
1034 std::vector<std::string> packageRoots;
Andreas Huberb82318c2016-08-02 14:45:54 -07001035
Andreas Huber737080b2016-08-02 15:38:04 -07001036 const char *me = argv[0];
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001037 OutputHandler *outputFormat = nullptr;
Andreas Huber737080b2016-08-02 15:38:04 -07001038
Andreas Huberb82318c2016-08-02 14:45:54 -07001039 int res;
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001040 while ((res = getopt(argc, argv, "ho:r:L:")) >= 0) {
Andreas Huberb82318c2016-08-02 14:45:54 -07001041 switch (res) {
1042 case 'o':
1043 {
Andreas Huber019d21d2016-10-03 12:59:47 -07001044 outputPath = optarg;
Andreas Huberb82318c2016-08-02 14:45:54 -07001045 break;
1046 }
1047
Andreas Huberdca261f2016-08-04 13:47:51 -07001048 case 'r':
1049 {
1050 std::string val(optarg);
1051 auto index = val.find_first_of(':');
1052 CHECK(index != std::string::npos);
1053
1054 auto package = val.substr(0, index);
1055 auto path = val.substr(index + 1);
1056 packageRootPaths.push_back(path);
1057 packageRoots.push_back(package);
1058 break;
1059 }
1060
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001061 case 'L':
1062 {
1063 CHECK(outputFormat == nullptr); // only one -L option
1064 for (auto &e : formats) {
1065 if (e.mKey == optarg) {
1066 outputFormat = &e;
1067 break;
1068 }
1069 }
1070 CHECK(outputFormat != nullptr);
1071 break;
1072 }
1073
Andreas Huberb82318c2016-08-02 14:45:54 -07001074 case '?':
1075 case 'h':
1076 default:
1077 {
Andreas Huber737080b2016-08-02 15:38:04 -07001078 usage(me);
Andreas Huberb82318c2016-08-02 14:45:54 -07001079 exit(1);
1080 break;
1081 }
1082 }
1083 }
1084
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001085 if (outputFormat == nullptr) {
1086 usage(me);
1087 exit(1);
1088 }
1089
Andreas Huberb82318c2016-08-02 14:45:54 -07001090 argc -= optind;
1091 argv += optind;
1092
Andreas Huberdca261f2016-08-04 13:47:51 -07001093 if (packageRootPaths.empty()) {
1094 // Pick reasonable defaults.
1095
1096 packageRoots.push_back("android.hardware");
1097
1098 const char *TOP = getenv("TOP");
1099 CHECK(TOP != NULL);
1100
1101 std::string path = TOP;
1102 path.append("/hardware/interfaces");
1103
1104 packageRootPaths.push_back(path);
1105 }
1106
Andreas Huber737080b2016-08-02 15:38:04 -07001107 // Valid options are now in argv[0] .. argv[argc - 1].
1108
Andreas Huber019d21d2016-10-03 12:59:47 -07001109 switch (outputFormat->mOutputMode) {
1110 case OutputHandler::NEEDS_DIR:
1111 case OutputHandler::NEEDS_FILE:
1112 {
1113 if (outputPath.empty()) {
1114 usage(me);
1115 exit(1);
1116 }
1117
1118 if (outputFormat->mOutputMode == OutputHandler::NEEDS_DIR) {
1119 const size_t len = outputPath.size();
1120 if (outputPath[len - 1] != '/') {
1121 outputPath += "/";
1122 }
1123 }
1124 break;
Andreas Huberb82318c2016-08-02 14:45:54 -07001125 }
Andreas Huber019d21d2016-10-03 12:59:47 -07001126
1127 default:
1128 outputPath.clear(); // Unused.
1129 break;
Andreas Huberb82318c2016-08-02 14:45:54 -07001130 }
1131
Andreas Huberdca261f2016-08-04 13:47:51 -07001132 Coordinator coordinator(packageRootPaths, packageRoots);
Andreas Huber5345ec22016-07-29 13:33:27 -07001133
Andreas Huber737080b2016-08-02 15:38:04 -07001134 for (int i = 0; i < argc; ++i) {
Andreas Huber68f24592016-07-29 14:53:48 -07001135 FQName fqName(argv[i]);
Andreas Huber68f24592016-07-29 14:53:48 -07001136
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001137 if (!fqName.isValid()) {
Andreas Hubere61e3f72016-08-03 10:22:03 -07001138 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -07001139 "ERROR: Invalid fully-qualified name.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001140 exit(1);
1141 }
Andreas Huber881227d2016-08-02 14:20:21 -07001142
Andreas Huber0fa9e392016-08-31 09:05:44 -07001143 OutputHandler::ValRes valid =
1144 outputFormat->validate(fqName, outputFormat->mKey);
1145
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001146 if (valid == OutputHandler::FAILED) {
Andreas Hubere61e3f72016-08-03 10:22:03 -07001147 exit(1);
1148 }
Andreas Huberd2943e12016-08-05 11:59:31 -07001149
1150 status_t err =
Andreas Huber019d21d2016-10-03 12:59:47 -07001151 outputFormat->generate(fqName, me, &coordinator, outputPath);
Andreas Huberd2943e12016-08-05 11:59:31 -07001152
1153 if (err != OK) {
Steven Moreland261370a2016-08-29 15:36:59 -07001154 exit(1);
Andreas Huberd2943e12016-08-05 11:59:31 -07001155 }
Andreas Hubereb1081f2016-07-28 13:13:24 -07001156 }
Andreas Huberc9410c72016-07-28 12:18:40 -07001157
Andreas Huberd2943e12016-08-05 11:59:31 -07001158 return 0;
Andreas Huberc9410c72016-07-28 12:18:40 -07001159}