blob: 28a6b8f91071d68e43fb619092fc9614e20568d6 [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
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700259static status_t generateMakefileForPackage(
260 const FQName &packageFQName,
Iliyan Malchevb66c3992016-08-07 21:18:13 -0700261 const char *hidl_gen,
Andreas Huberd2943e12016-08-05 11:59:31 -0700262 Coordinator *coordinator,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700263 const std::string &) {
264
265 CHECK(packageFQName.isValid() &&
266 !packageFQName.isFullyQualified() &&
267 packageFQName.name().empty());
268
Andreas Huberd2943e12016-08-05 11:59:31 -0700269 std::vector<FQName> packageInterfaces;
270
271 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700272 coordinator->appendPackageInterfacesToVector(packageFQName,
273 &packageInterfaces);
Andreas Huberd2943e12016-08-05 11:59:31 -0700274
275 if (err != OK) {
276 return err;
277 }
278
279 std::set<FQName> importedPackages;
Andreas Huber0fa9e392016-08-31 09:05:44 -0700280 bool packageIsJavaCompatible = true;
281 AST *typesAST = nullptr;
282
Andreas Huberd2943e12016-08-05 11:59:31 -0700283 for (const auto &fqName : packageInterfaces) {
284 AST *ast = coordinator->parse(fqName);
285
286 if (ast == NULL) {
287 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700288 "ERROR: Could not parse %s. Aborting.\n",
Andreas Huberd2943e12016-08-05 11:59:31 -0700289 fqName.string().c_str());
290
291 return UNKNOWN_ERROR;
292 }
293
Andreas Huber0fa9e392016-08-31 09:05:44 -0700294 if (packageIsJavaCompatible && !ast->isJavaCompatible()) {
295 packageIsJavaCompatible = false;
296 }
297
298 if (fqName.name() == "types") {
299 typesAST = ast;
300 }
301
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700302 ast->getImportedPackages(&importedPackages);
Andreas Huberd2943e12016-08-05 11:59:31 -0700303 }
304
Dan Willemsen676abdc2016-09-28 19:42:22 -0700305 if (!packageIsJavaCompatible) {
306 return OK;
307 }
308
Andreas Huberd2943e12016-08-05 11:59:31 -0700309 std::string path =
310 coordinator->getPackagePath(packageFQName, false /* relative */);
311
312 path.append("Android.mk");
313
314 CHECK(Coordinator::MakeParentHierarchy(path));
315 FILE *file = fopen(path.c_str(), "w");
316
317 if (file == NULL) {
318 return -errno;
319 }
320
321 const std::string libraryName = makeLibraryName(packageFQName);
322
323 Formatter out(file);
324
Dan Willemsen676abdc2016-09-28 19:42:22 -0700325 out << "# This file is autogenerated by hidl-gen. Do not edit manually.\n\n";
326 out << "LOCAL_PATH := $(call my-dir)\n";
Andreas Huberd2943e12016-08-05 11:59:31 -0700327
Dan Willemsen676abdc2016-09-28 19:42:22 -0700328 enum LibraryStyle {
329 LIBRARY_STYLE_REGULAR,
330 LIBRARY_STYLE_STATIC,
331 LIBRARY_STYLE_END,
332 };
Andreas Huberd2943e12016-08-05 11:59:31 -0700333
Dan Willemsen676abdc2016-09-28 19:42:22 -0700334 for (int style = LIBRARY_STYLE_REGULAR; style != LIBRARY_STYLE_END;
335 ++style) {
336 const std::string staticSuffix =
337 (style == LIBRARY_STYLE_STATIC) ? "-static" : "";
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700338
Dan Willemsen676abdc2016-09-28 19:42:22 -0700339 out << "\n"
340 << "########################################"
341 << "########################################\n\n";
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700342
Dan Willemsen676abdc2016-09-28 19:42:22 -0700343 out << "include $(CLEAR_VARS)\n"
344 << "LOCAL_MODULE := "
345 << libraryName
346 << "-java"
347 << staticSuffix
348 << "\nLOCAL_MODULE_CLASS := JAVA_LIBRARIES\n\n"
349 << "intermediates := $(local-generated-sources-dir)\n\n"
350 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
351 << hidl_gen
352 << "$(HOST_EXECUTABLE_SUFFIX)";
Andreas Huberd2943e12016-08-05 11:59:31 -0700353
Dan Willemsen676abdc2016-09-28 19:42:22 -0700354 if (!importedPackages.empty()) {
Iliyan Malchev800273d2016-09-02 15:25:07 -0700355 out << "\n"
Dan Willemsen676abdc2016-09-28 19:42:22 -0700356 << "\nLOCAL_"
Andreas Huber782d45e2016-09-22 13:25:14 -0700357 << ((style == LIBRARY_STYLE_STATIC) ? "STATIC_" : "")
Dan Willemsen676abdc2016-09-28 19:42:22 -0700358 << "JAVA_LIBRARIES := \\";
359
360 out.indent();
361 for (const auto &importedPackage : importedPackages) {
362 out << "\n"
363 << makeLibraryName(importedPackage)
364 << "-java"
365 << staticSuffix
366 << " \\";
367 }
368 out << "\n";
369 out.unindent();
Iliyan Malchev800273d2016-09-02 15:25:07 -0700370 }
Dan Willemsen676abdc2016-09-28 19:42:22 -0700371
372 generateMakefileSection(
373 out,
374 coordinator,
375 packageFQName,
376 packageInterfaces,
377 typesAST);
378
379 out << "\ninclude $(BUILD_"
380 << ((style == LIBRARY_STYLE_STATIC) ? "STATIC_" : "")
381 << "JAVA_LIBRARY)\n\n";
Andreas Huber0fa9e392016-08-31 09:05:44 -0700382 }
383
Iliyan Malchev8be09552016-09-22 16:20:33 -0700384 out << "\n\n"
385 << "include $(call all-makefiles-under,$(LOCAL_PATH))\n";
386
Andreas Huberd2943e12016-08-05 11:59:31 -0700387 return OK;
388}
389
Andreas Huber0fa9e392016-08-31 09:05:44 -0700390OutputHandler::ValRes validateForMakefile(
391 const FQName &fqName, const std::string & /* language */) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700392 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700393 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700394 return OutputHandler::FAILED;
395 }
396
397 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700398 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700399 return OutputHandler::FAILED;
400 }
401
402 if (!fqName.name().empty()) {
403 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700404 "ERROR: Expecting only package name and version.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700405 return OutputHandler::FAILED;
406 }
407
408 return OutputHandler::PASS_PACKAGE;
409}
410
Dan Willemsen676abdc2016-09-28 19:42:22 -0700411static void generateAndroidBpGenSection(
412 Formatter &out,
413 const FQName &packageFQName,
414 const char *hidl_gen,
415 Coordinator *coordinator,
416 const std::string &genName,
417 const char *language,
418 const std::vector<FQName> &packageInterfaces,
419 const std::function<void(Formatter&, const FQName)> outputFn) {
420
421 out << "genrule {\n";
422 out.indent();
423 out << "name: \"" << genName << "\",\n"
424 << "tool: \"" << hidl_gen << "\",\n";
425
426 out << "cmd: \"$tool -o $genDir"
427 << " -L" << language
428 << " -r"
429 << coordinator->getPackageRoot(packageFQName) << ":"
430 << coordinator->getPackageRootPath(packageFQName)
431 << " " << packageFQName.string() << "\",\n";
432
433 out << "srcs: [\n";
434 out.indent();
435 for (const auto &fqName : packageInterfaces) {
436 out << "\"" << fqName.name() << ".hal\",\n";
437 }
438 out.unindent();
439 out << "],\n";
440
441 out << "out: [\n";
442 out.indent();
443 for (const auto &fqName : packageInterfaces) {
444 outputFn(out, fqName);
445 }
446 out.unindent();
447 out << "],\n";
448
449 out.unindent();
450 out << "}\n\n";
451}
452
453static status_t generateAndroidBpForPackage(
454 const FQName &packageFQName,
455 const char *hidl_gen,
456 Coordinator *coordinator,
457 const std::string &) {
458
459 CHECK(packageFQName.isValid() &&
460 !packageFQName.isFullyQualified() &&
461 packageFQName.name().empty());
462
463 std::vector<FQName> packageInterfaces;
464
465 status_t err =
466 coordinator->appendPackageInterfacesToVector(packageFQName,
467 &packageInterfaces);
468
469 if (err != OK) {
470 return err;
471 }
472
473 std::set<FQName> importedPackages;
474 AST *typesAST = nullptr;
475
476 for (const auto &fqName : packageInterfaces) {
477 AST *ast = coordinator->parse(fqName);
478
479 if (ast == NULL) {
480 fprintf(stderr,
481 "ERROR: Could not parse %s. Aborting.\n",
482 fqName.string().c_str());
483
484 return UNKNOWN_ERROR;
485 }
486
487 if (fqName.name() == "types") {
488 typesAST = ast;
489 }
490
491 ast->getImportedPackages(&importedPackages);
492 }
493
494 std::string path =
495 coordinator->getPackagePath(packageFQName, false /* relative */);
496
497 path.append("Android.bp");
498
499 CHECK(Coordinator::MakeParentHierarchy(path));
500 FILE *file = fopen(path.c_str(), "w");
501
502 if (file == NULL) {
503 return -errno;
504 }
505
506 const std::string libraryName = makeLibraryName(packageFQName);
507 const std::string genSourceName = libraryName + "_genc++";
508 const std::string genHeaderName = libraryName + "_genc++_headers";
509 const std::string pathPrefix =
510 coordinator->convertPackageRootToPath(packageFQName) +
511 coordinator->getPackagePath(packageFQName, true /* relative */);
512
513 Formatter out(file);
514
515 out << "// This file is autogenerated by hidl-gen. Do not edit manually.\n\n";
516
517 // Rule to generate the C++ source files
518 generateAndroidBpGenSection(
519 out,
520 packageFQName,
521 hidl_gen,
522 coordinator,
523 genSourceName,
524 "c++",
525 packageInterfaces,
526 [&pathPrefix](Formatter &out, const FQName &fqName) {
527 if (fqName.name() == "types") {
528 out << "\"" << pathPrefix << "types.cpp\",\n";
529 } else {
530 out << "\"" << pathPrefix << fqName.name().substr(1) << "All.cpp\",\n";
531 }
532 });
533
534 // Rule to generate the C++ header files
535 generateAndroidBpGenSection(
536 out,
537 packageFQName,
538 hidl_gen,
539 coordinator,
540 genHeaderName,
541 "c++",
542 packageInterfaces,
543 [&pathPrefix](Formatter &out, const FQName &fqName) {
544 out << "\"" << pathPrefix << fqName.name() << ".h\",\n";
545 if (fqName.name() != "types") {
546 out << "\"" << pathPrefix << "IHw" << fqName.name().substr(1) << ".h\",\n";
547 out << "\"" << pathPrefix << "Bn" << fqName.name().substr(1) << ".h\",\n";
548 out << "\"" << pathPrefix << "Bp" << fqName.name().substr(1) << ".h\",\n";
549 out << "\"" << pathPrefix << "Bs" << fqName.name().substr(1) << ".h\",\n";
550 }
551 });
552
553 // C++ library definition
554 out << "cc_library_shared {\n";
555 out.indent();
556 out << "name: \"" << libraryName << "\",\n"
557 << "generated_sources: [\"" << genSourceName << "\"],\n"
558 << "generated_headers: [\"" << genHeaderName << "\"],\n"
559 << "export_generated_headers: [\"" << genHeaderName << "\"],\n"
560 << "shared_libs: [\n";
561
562 out.indent();
563 out << "\"libhidl\",\n"
564 << "\"libhwbinder\",\n"
565 << "\"libutils\",\n"
566 << "\"libcutils\",\n";
567 for (const auto &importedPackage : importedPackages) {
568 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
569 }
570 out.unindent();
571
572 out << "],\n";
573 out.unindent();
574 out << "}\n";
575
576 return OK;
577}
578
Steven Moreland197d56c2016-09-09 10:03:58 -0700579static status_t generateMakefileImplForPackage(
580 const FQName &packageFQName,
581 const char *,
582 Coordinator *coordinator,
583 const std::string &outputDir) {
584
Iliyan Malchev4923f932016-09-09 13:04:59 -0700585 const std::string libraryName = makeLibraryName(packageFQName) + "-impl";
Steven Moreland197d56c2016-09-09 10:03:58 -0700586
587 std::vector<FQName> packageInterfaces;
588
589 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700590 coordinator->appendPackageInterfacesToVector(packageFQName,
591 &packageInterfaces);
Steven Moreland197d56c2016-09-09 10:03:58 -0700592
593 if (err != OK) {
594 return err;
595 }
596
597 std::set<FQName> importedPackages;
598
599 for (const auto &fqName : packageInterfaces) {
600 AST *ast = coordinator->parse(fqName);
601
602 if (ast == NULL) {
603 fprintf(stderr,
604 "ERROR: Could not parse %s. Aborting.\n",
605 fqName.string().c_str());
606
607 return UNKNOWN_ERROR;
608 }
609
610 ast->getImportedPackages(&importedPackages);
611 }
612
613 std::string path = outputDir + "Android.mk";
614
615 CHECK(Coordinator::MakeParentHierarchy(path));
616 FILE *file = fopen(path.c_str(), "w");
617
618 if (file == NULL) {
619 return -errno;
620 }
621
622 Formatter out(file);
623
624 out << "LOCAL_PATH := $(call my-dir)\n\n"
625 << "include $(CLEAR_VARS)\n"
626 << "LOCAL_MODULE := " << libraryName << "\n"
627 << "LOCAL_MODULE_RELATIVE_PATH := hw\n"
628 << "LOCAL_SRC_FILES := \\\n";
629 out.indent();
630 for (const auto &fqName : packageInterfaces) {
631 if (fqName.name() == "types") {
632 continue;
633 }
634 out << fqName.getInterfaceBaseName() << ".cpp \\\n";
635 }
636 out.unindent();
637 out << "\n";
638 out << "LOCAL_SHARED_LIBRARIES := \\\n";
639 out.indent();
640 out << "libhidl \\\n"
641 << "libhwbinder \\\n"
642 << "libutils \\\n"
643 << makeLibraryName(packageFQName) << " \\\n";
644 out.unindent();
645 out << "\n";
646
647 out << "include $(BUILD_SHARED_LIBRARY)\n";
648
649 return OK;
650}
651
Andreas Huber0fa9e392016-08-31 09:05:44 -0700652OutputHandler::ValRes validateForSource(
653 const FQName &fqName, const std::string &language) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700654 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700655 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700656 return OutputHandler::FAILED;
657 }
658
659 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700660 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700661 return OutputHandler::FAILED;
662 }
663
Andreas Huber0fa9e392016-08-31 09:05:44 -0700664 const std::string &name = fqName.name();
665 if (!name.empty()) {
666 if (name.find('.') == std::string::npos) {
667 return OutputHandler::PASS_FULL;
668 }
669
670 if (language != "java" || name.find("types.") != 0) {
671 // When generating java sources for "types.hal", output can be
672 // constrained to just one of the top-level types declared
673 // by using the extended syntax
674 // android.hardware.Foo@1.0::types.TopLevelTypeName.
675 // In all other cases (different language, not 'types') the dot
676 // notation in the name is illegal in this context.
677 return OutputHandler::FAILED;
678 }
679
680 return OutputHandler::PASS_FULL;
681 }
682
683 return OutputHandler::PASS_PACKAGE;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700684}
685
Andreas Huber019d21d2016-10-03 12:59:47 -0700686OutputHandler::ValRes validateForExportHeader(
687 const FQName &fqName, const std::string & /* language */) {
688 if (fqName.package().empty()) {
689 fprintf(stderr, "ERROR: Expecting package name\n");
690 return OutputHandler::FAILED;
691 }
692
693 if (fqName.version().empty()) {
694 fprintf(stderr, "ERROR: Expecting package version\n");
695 return OutputHandler::FAILED;
696 }
697
698 if (!fqName.name().empty()) {
699 fprintf(stderr,
700 "ERROR: Expecting only package name and version.\n");
701 return OutputHandler::FAILED;
702 }
703
704 return OutputHandler::PASS_PACKAGE;
705}
706
707
708static status_t generateExportHeaderForPackage(
709 const FQName &packageFQName,
710 const char * /* hidl_gen */,
711 Coordinator *coordinator,
712 const std::string &outputPath) {
713
714 CHECK(packageFQName.isValid()
715 && !packageFQName.isFullyQualified()
716 && packageFQName.name().empty());
717
718 std::vector<FQName> packageInterfaces;
719
720 status_t err = coordinator->appendPackageInterfacesToVector(
721 packageFQName, &packageInterfaces);
722
723 if (err != OK) {
724 return err;
725 }
726
727 std::vector<const Type *> exportedTypes;
728
729 for (const auto &fqName : packageInterfaces) {
730 AST *ast = coordinator->parse(fqName);
731
732 if (ast == NULL) {
733 fprintf(stderr,
734 "ERROR: Could not parse %s. Aborting.\n",
735 fqName.string().c_str());
736
737 return UNKNOWN_ERROR;
738 }
739
740 ast->appendToExportedTypesVector(&exportedTypes);
741 }
742
743 if (exportedTypes.empty()) {
744 return OK;
745 }
746
747 CHECK(Coordinator::MakeParentHierarchy(outputPath));
748 FILE *file = fopen(outputPath.c_str(), "w");
749
750 if (file == nullptr) {
751 return -errno;
752 }
753
754 Formatter out(file);
755
756 out << "// This file is autogenerated by hidl-gen. Do not edit manually."
757 "\n\n";
758
759 std::string guard = "HIDL_GENERATED_";
760 guard += packageFQName.tokenName();
761 guard += "_";
762 guard += "EXPORTED_CONSTANTS_H_";
763
764 out << "#ifndef "
765 << guard
766 << "\n#define "
767 << guard
768 << "\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n";
769
770 for (const auto &type : exportedTypes) {
771 type->emitExportedHeader(out);
772 }
773
774 out << "#ifdef __cplusplus\n}\n#endif\n\n#endif // "
775 << guard
776 << "\n";
777
778 return OK;
779}
780
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700781static std::vector<OutputHandler> formats = {
782 {"c++",
Andreas Huber019d21d2016-10-03 12:59:47 -0700783 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700784 validateForSource,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700785 [](const FQName &fqName,
786 const char *hidl_gen, Coordinator *coordinator,
787 const std::string &outputDir) -> status_t {
788 if (fqName.isFullyQualified()) {
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700789 return generateSourcesForFile(fqName,
790 hidl_gen,
791 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700792 outputDir,
793 "c++");
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700794 } else {
795 return generateSourcesForPackage(fqName,
796 hidl_gen,
797 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700798 outputDir,
799 "c++");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700800 }
801 }
802 },
803
Andreas Huber019d21d2016-10-03 12:59:47 -0700804 {"export-header",
805 OutputHandler::NEEDS_FILE /* mOutputMode */,
806 validateForExportHeader,
807 [](const FQName &fqName,
808 const char *hidl_gen,
809 Coordinator *coordinator,
810 const std::string &outputPath) -> status_t {
811 CHECK(!fqName.isFullyQualified());
812
813 return generateExportHeaderForPackage(
814 fqName,
815 hidl_gen,
816 coordinator,
817 outputPath);
818 }
819 },
820
Steven Moreland9c387612016-09-07 09:54:26 -0700821 {"c++-impl",
Andreas Huber019d21d2016-10-03 12:59:47 -0700822 OutputHandler::NEEDS_DIR /* mOutputMode */,
Steven Moreland9c387612016-09-07 09:54:26 -0700823 validateForSource,
824 [](const FQName &fqName,
825 const char *hidl_gen, Coordinator *coordinator,
826 const std::string &outputDir) -> status_t {
827 if (fqName.isFullyQualified()) {
828 return generateSourcesForFile(fqName,
829 hidl_gen,
830 coordinator,
831 outputDir, "c++-impl");
832 } else {
833 return generateSourcesForPackage(fqName,
834 hidl_gen,
835 coordinator,
836 outputDir, "c++-impl");
837 }
838 }
839 },
840
841
Andreas Huber2831d512016-08-15 09:33:47 -0700842 {"java",
Andreas Huber019d21d2016-10-03 12:59:47 -0700843 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700844 validateForSource,
Andreas Huber2831d512016-08-15 09:33:47 -0700845 [](const FQName &fqName,
846 const char *hidl_gen, Coordinator *coordinator,
847 const std::string &outputDir) -> status_t {
848 if (fqName.isFullyQualified()) {
849 return generateSourcesForFile(fqName,
850 hidl_gen,
851 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700852 outputDir,
853 "java");
Andreas Huber2831d512016-08-15 09:33:47 -0700854 }
855 else {
856 return generateSourcesForPackage(fqName,
857 hidl_gen,
858 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700859 outputDir,
860 "java");
Andreas Huber2831d512016-08-15 09:33:47 -0700861 }
862 }
863 },
864
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700865 {"vts",
Andreas Huber019d21d2016-10-03 12:59:47 -0700866 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700867 validateForSource,
868 [](const FQName &fqName,
869 const char * hidl_gen,
870 Coordinator *coordinator,
871 const std::string &outputDir) -> status_t {
872 if (fqName.isFullyQualified()) {
873 return generateSourcesForFile(fqName,
874 hidl_gen,
875 coordinator,
876 outputDir, "vts");
877 } else {
878 return generateSourcesForPackage(fqName,
879 hidl_gen,
880 coordinator,
881 outputDir, "vts");
882 }
883 }
884 },
885
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700886 {"makefile",
Andreas Huber019d21d2016-10-03 12:59:47 -0700887 OutputHandler::NOT_NEEDED /* mOutputMode */,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700888 validateForMakefile,
889 generateMakefileForPackage,
890 },
Steven Moreland197d56c2016-09-09 10:03:58 -0700891
Dan Willemsen676abdc2016-09-28 19:42:22 -0700892 {"androidbp",
Andreas Huber019d21d2016-10-03 12:59:47 -0700893 OutputHandler::NOT_NEEDED /* mOutputMode */,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700894 validateForMakefile,
895 generateAndroidBpForPackage,
896 },
897
Steven Moreland197d56c2016-09-09 10:03:58 -0700898 {"makefile-impl",
Yifan Hong94bcea02016-10-06 13:51:31 -0700899 OutputHandler::NEEDS_DIR /* mOutputMode */,
Steven Moreland197d56c2016-09-09 10:03:58 -0700900 validateForMakefile,
901 generateMakefileImplForPackage,
902 }
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700903};
904
905static void usage(const char *me) {
906 fprintf(stderr,
907 "usage: %s -o output-path -L <language> (-r interface-root)+ fqname+\n",
908 me);
909
910 fprintf(stderr, " -o output path\n");
911
912 fprintf(stderr, " -L <language> (one of");
913 for (auto &e : formats) {
914 fprintf(stderr, " %s", e.mKey.c_str());
915 }
916 fprintf(stderr, ")\n");
917
918 fprintf(stderr,
919 " -r package:path root "
920 "(e.g., android.hardware:hardware/interfaces)\n");
921}
922
Andreas Huberb82318c2016-08-02 14:45:54 -0700923int main(int argc, char **argv) {
Andreas Huber019d21d2016-10-03 12:59:47 -0700924 std::string outputPath;
Andreas Huberdca261f2016-08-04 13:47:51 -0700925 std::vector<std::string> packageRootPaths;
926 std::vector<std::string> packageRoots;
Andreas Huberb82318c2016-08-02 14:45:54 -0700927
Andreas Huber737080b2016-08-02 15:38:04 -0700928 const char *me = argv[0];
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700929 OutputHandler *outputFormat = nullptr;
Andreas Huber737080b2016-08-02 15:38:04 -0700930
Andreas Huberb82318c2016-08-02 14:45:54 -0700931 int res;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700932 while ((res = getopt(argc, argv, "ho:r:L:")) >= 0) {
Andreas Huberb82318c2016-08-02 14:45:54 -0700933 switch (res) {
934 case 'o':
935 {
Andreas Huber019d21d2016-10-03 12:59:47 -0700936 outputPath = optarg;
Andreas Huberb82318c2016-08-02 14:45:54 -0700937 break;
938 }
939
Andreas Huberdca261f2016-08-04 13:47:51 -0700940 case 'r':
941 {
942 std::string val(optarg);
943 auto index = val.find_first_of(':');
944 CHECK(index != std::string::npos);
945
946 auto package = val.substr(0, index);
947 auto path = val.substr(index + 1);
948 packageRootPaths.push_back(path);
949 packageRoots.push_back(package);
950 break;
951 }
952
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700953 case 'L':
954 {
955 CHECK(outputFormat == nullptr); // only one -L option
956 for (auto &e : formats) {
957 if (e.mKey == optarg) {
958 outputFormat = &e;
959 break;
960 }
961 }
962 CHECK(outputFormat != nullptr);
963 break;
964 }
965
Andreas Huberb82318c2016-08-02 14:45:54 -0700966 case '?':
967 case 'h':
968 default:
969 {
Andreas Huber737080b2016-08-02 15:38:04 -0700970 usage(me);
Andreas Huberb82318c2016-08-02 14:45:54 -0700971 exit(1);
972 break;
973 }
974 }
975 }
976
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700977 if (outputFormat == nullptr) {
978 usage(me);
979 exit(1);
980 }
981
Andreas Huberb82318c2016-08-02 14:45:54 -0700982 argc -= optind;
983 argv += optind;
984
Andreas Huberdca261f2016-08-04 13:47:51 -0700985 if (packageRootPaths.empty()) {
986 // Pick reasonable defaults.
987
988 packageRoots.push_back("android.hardware");
989
990 const char *TOP = getenv("TOP");
991 CHECK(TOP != NULL);
992
993 std::string path = TOP;
994 path.append("/hardware/interfaces");
995
996 packageRootPaths.push_back(path);
997 }
998
Andreas Huber737080b2016-08-02 15:38:04 -0700999 // Valid options are now in argv[0] .. argv[argc - 1].
1000
Andreas Huber019d21d2016-10-03 12:59:47 -07001001 switch (outputFormat->mOutputMode) {
1002 case OutputHandler::NEEDS_DIR:
1003 case OutputHandler::NEEDS_FILE:
1004 {
1005 if (outputPath.empty()) {
1006 usage(me);
1007 exit(1);
1008 }
1009
1010 if (outputFormat->mOutputMode == OutputHandler::NEEDS_DIR) {
1011 const size_t len = outputPath.size();
1012 if (outputPath[len - 1] != '/') {
1013 outputPath += "/";
1014 }
1015 }
1016 break;
Andreas Huberb82318c2016-08-02 14:45:54 -07001017 }
Andreas Huber019d21d2016-10-03 12:59:47 -07001018
1019 default:
1020 outputPath.clear(); // Unused.
1021 break;
Andreas Huberb82318c2016-08-02 14:45:54 -07001022 }
1023
Andreas Huberdca261f2016-08-04 13:47:51 -07001024 Coordinator coordinator(packageRootPaths, packageRoots);
Andreas Huber5345ec22016-07-29 13:33:27 -07001025
Andreas Huber737080b2016-08-02 15:38:04 -07001026 for (int i = 0; i < argc; ++i) {
Andreas Huber68f24592016-07-29 14:53:48 -07001027 FQName fqName(argv[i]);
Andreas Huber68f24592016-07-29 14:53:48 -07001028
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001029 if (!fqName.isValid()) {
Andreas Hubere61e3f72016-08-03 10:22:03 -07001030 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -07001031 "ERROR: Invalid fully-qualified name.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001032 exit(1);
1033 }
Andreas Huber881227d2016-08-02 14:20:21 -07001034
Andreas Huber0fa9e392016-08-31 09:05:44 -07001035 OutputHandler::ValRes valid =
1036 outputFormat->validate(fqName, outputFormat->mKey);
1037
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001038 if (valid == OutputHandler::FAILED) {
Andreas Hubere61e3f72016-08-03 10:22:03 -07001039 exit(1);
1040 }
Andreas Huberd2943e12016-08-05 11:59:31 -07001041
1042 status_t err =
Andreas Huber019d21d2016-10-03 12:59:47 -07001043 outputFormat->generate(fqName, me, &coordinator, outputPath);
Andreas Huberd2943e12016-08-05 11:59:31 -07001044
1045 if (err != OK) {
Steven Moreland261370a2016-08-29 15:36:59 -07001046 exit(1);
Andreas Huberd2943e12016-08-05 11:59:31 -07001047 }
Andreas Hubereb1081f2016-07-28 13:13:24 -07001048 }
Andreas Huberc9410c72016-07-28 12:18:40 -07001049
Andreas Huberd2943e12016-08-05 11:59:31 -07001050 return 0;
Andreas Huberc9410c72016-07-28 12:18:40 -07001051}