blob: 91fc81cb18c058fa0c0bb83cf47f84c6bf11ca37 [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;
34 bool mNeedsOutputDir;
35 enum ValRes {
36 FAILED,
37 PASS_PACKAGE,
38 PASS_FULL
39 };
Andreas Huber0fa9e392016-08-31 09:05:44 -070040 ValRes (*validate)(const FQName &, const std::string &language);
Iliyan Malchev5bb14022016-08-09 15:04:39 -070041 status_t (*generate)(const FQName &fqName,
42 const char *hidl_gen,
43 Coordinator *coordinator,
44 const std::string &outputDir);
45};
Andreas Huberdca261f2016-08-04 13:47:51 -070046
Iliyan Malchev5bb14022016-08-09 15:04:39 -070047static status_t generateSourcesForFile(
48 const FQName &fqName,
49 const char *,
50 Coordinator *coordinator,
Andreas Huber2831d512016-08-15 09:33:47 -070051 const std::string &outputDir,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070052 const std::string &lang) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -070053 CHECK(fqName.isFullyQualified());
54
Andreas Huber0fa9e392016-08-31 09:05:44 -070055 AST *ast;
Andreas Huberd29724f2016-09-14 09:33:13 -070056 std::string limitToType;
Andreas Huber0fa9e392016-08-31 09:05:44 -070057
58 if (fqName.name().find("types.") == 0) {
59 CHECK(lang == "java"); // Already verified in validate().
60
Andreas Huberd29724f2016-09-14 09:33:13 -070061 limitToType = fqName.name().substr(strlen("types."));
Andreas Huber0fa9e392016-08-31 09:05:44 -070062
63 FQName typesName(fqName.package(), fqName.version(), "types");
64 ast = coordinator->parse(typesName);
65 } else {
66 ast = coordinator->parse(fqName);
67 }
Iliyan Malchev5bb14022016-08-09 15:04:39 -070068
69 if (ast == NULL) {
70 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -070071 "ERROR: Could not parse %s. Aborting.\n",
Iliyan Malchev5bb14022016-08-09 15:04:39 -070072 fqName.string().c_str());
73
74 return UNKNOWN_ERROR;
75 }
76
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070077 if (lang == "c++") {
78 return ast->generateCpp(outputDir);
79 }
Steven Moreland9c387612016-09-07 09:54:26 -070080 if (lang == "c++-impl") {
81 return ast->generateCppImpl(outputDir);
82 }
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070083 if (lang == "java") {
Andreas Huber0fa9e392016-08-31 09:05:44 -070084 return ast->generateJava(outputDir, limitToType);
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070085 }
86 if (lang == "vts") {
87 return ast->generateVts(outputDir);
88 }
89 // Unknown language.
90 return UNKNOWN_ERROR;
Iliyan Malchev5bb14022016-08-09 15:04:39 -070091}
92
93static status_t generateSourcesForPackage(
94 const FQName &packageFQName,
95 const char *hidl_gen,
96 Coordinator *coordinator,
Andreas Huber2831d512016-08-15 09:33:47 -070097 const std::string &outputDir,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070098 const std::string &lang) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -070099 CHECK(packageFQName.isValid() &&
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700100 !packageFQName.isFullyQualified() &&
101 packageFQName.name().empty());
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700102
103 std::vector<FQName> packageInterfaces;
104
105 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700106 coordinator->appendPackageInterfacesToVector(packageFQName,
107 &packageInterfaces);
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700108
109 if (err != OK) {
110 return err;
111 }
112
113 for (const auto &fqName : packageInterfaces) {
Andreas Huber2831d512016-08-15 09:33:47 -0700114 err = generateSourcesForFile(
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700115 fqName, hidl_gen, coordinator, outputDir, lang);
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700116 if (err != OK) {
117 return err;
118 }
119 }
120
121 return OK;
Andreas Huberb82318c2016-08-02 14:45:54 -0700122}
123
Andreas Huberd2943e12016-08-05 11:59:31 -0700124static std::string makeLibraryName(const FQName &packageFQName) {
Iliyan Malcheve2c595a2016-08-07 21:20:04 -0700125 return packageFQName.string();
Andreas Huberd2943e12016-08-05 11:59:31 -0700126}
127
Dan Willemsen676abdc2016-09-28 19:42:22 -0700128static void generateMakefileSectionForType(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700129 Formatter &out,
130 Coordinator *coordinator,
131 const FQName &packageFQName,
132 const FQName &fqName,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700133 const char *typeName) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700134 out << "\n"
135 << "\n#"
136 << "\n# Build " << fqName.name() << ".hal";
137
Dan Willemsen676abdc2016-09-28 19:42:22 -0700138 if (typeName != nullptr) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700139 out << " (" << typeName << ")";
140 }
141
142 out << "\n#"
143 << "\nGEN := $(intermediates)/"
144 << coordinator->convertPackageRootToPath(packageFQName)
145 << coordinator->getPackagePath(packageFQName, true /* relative */);
Dan Willemsen676abdc2016-09-28 19:42:22 -0700146 if (typeName == nullptr) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700147 out << fqName.name() << ".java";
148 } else {
149 out << typeName << ".java";
150 }
151
152 out << "\n$(GEN): $(HIDL)";
153 out << "\n$(GEN): PRIVATE_HIDL := $(HIDL)";
154 out << "\n$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/"
155 << fqName.name() << ".hal";
Iliyan Malchevb9819132016-09-07 12:38:31 -0700156
157 {
158 AST *ast = coordinator->parse(fqName);
159 CHECK(ast != nullptr);
160 const std::set<FQName>& refs = ast->getImportedNames();
161 for (auto depFQName : refs) {
162 // If the package of depFQName is the same as this fqName's package,
163 // then add it explicitly as a .hal dependency within the same
164 // package.
165 if (fqName.package() == depFQName.package() &&
166 fqName.version() == depFQName.version()) {
167 // PRIVATE_DEPS is not actually being used in the
168 // auto-generated file, but is necessary if the build rule
169 // ever needs to use the dependency information, since the
170 // built-in Make variables are not supported in the Android
171 // build system.
172 out << "\n$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/"
173 << depFQName.name() << ".hal";
174 // This is the actual dependency.
175 out << "\n$(GEN): $(LOCAL_PATH)/"
176 << depFQName.name() << ".hal";
177 }
178 }
179 }
180
Andreas Huber0fa9e392016-08-31 09:05:44 -0700181 out << "\n$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)"
182 << "\n$(GEN): PRIVATE_CUSTOM_TOOL = \\";
183 out.indent();
184 out.indent();
185 out << "\n$(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \\"
Dan Willemsen676abdc2016-09-28 19:42:22 -0700186 << "\n-Ljava"
Andreas Huber0fa9e392016-08-31 09:05:44 -0700187 << " -r"
188 << coordinator->getPackageRoot(packageFQName) << ":"
189 << coordinator->getPackageRootPath(packageFQName) << " \\\n";
190
191 out << packageFQName.string()
192 << "::"
193 << fqName.name();
194
Dan Willemsen676abdc2016-09-28 19:42:22 -0700195 if (typeName != nullptr) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700196 out << "." << typeName;
197 }
198
199 out << "\n";
200
201 out.unindent();
202 out.unindent();
203
204 out << "\n$(GEN): $(LOCAL_PATH)/" << fqName.name() << ".hal";
205 out << "\n\t$(transform-generated-source)";
206 out << "\nLOCAL_GENERATED_SOURCES += $(GEN)";
207}
208
Dan Willemsen676abdc2016-09-28 19:42:22 -0700209static void generateMakefileSection(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700210 Formatter &out,
211 Coordinator *coordinator,
212 const FQName &packageFQName,
213 const std::vector<FQName> &packageInterfaces,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700214 AST *typesAST) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700215 for (const auto &fqName : packageInterfaces) {
Dan Willemsen676abdc2016-09-28 19:42:22 -0700216 if (fqName.name() == "types") {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700217 CHECK(typesAST != nullptr);
218
219 Scope *rootScope = typesAST->scope();
Andreas Huber0fa9e392016-08-31 09:05:44 -0700220
Andreas Huberb747bd92016-09-26 15:55:31 -0700221 std::vector<NamedType *> subTypes = rootScope->getSubTypes();
222 std::sort(
223 subTypes.begin(),
224 subTypes.end(),
225 [](const NamedType *a, const NamedType *b) -> bool {
226 return a->fqName() < b->fqName();
227 });
228
229 for (const auto &type : subTypes) {
Andreas Huberdda25cc2016-09-22 10:39:47 -0700230 if (type->isTypeDef()) {
231 continue;
232 }
233
Dan Willemsen676abdc2016-09-28 19:42:22 -0700234 generateMakefileSectionForType(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700235 out,
236 coordinator,
237 packageFQName,
238 fqName,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700239 type->localName().c_str());
Andreas Huber0fa9e392016-08-31 09:05:44 -0700240 }
241
242 continue;
243 }
244
Dan Willemsen676abdc2016-09-28 19:42:22 -0700245 generateMakefileSectionForType(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700246 out,
247 coordinator,
248 packageFQName,
249 fqName,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700250 nullptr /* typeName */);
Andreas Huber0fa9e392016-08-31 09:05:44 -0700251 }
252}
253
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700254static status_t generateMakefileForPackage(
255 const FQName &packageFQName,
Iliyan Malchevb66c3992016-08-07 21:18:13 -0700256 const char *hidl_gen,
Andreas Huberd2943e12016-08-05 11:59:31 -0700257 Coordinator *coordinator,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700258 const std::string &) {
259
260 CHECK(packageFQName.isValid() &&
261 !packageFQName.isFullyQualified() &&
262 packageFQName.name().empty());
263
Andreas Huberd2943e12016-08-05 11:59:31 -0700264 std::vector<FQName> packageInterfaces;
265
266 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700267 coordinator->appendPackageInterfacesToVector(packageFQName,
268 &packageInterfaces);
Andreas Huberd2943e12016-08-05 11:59:31 -0700269
270 if (err != OK) {
271 return err;
272 }
273
274 std::set<FQName> importedPackages;
Andreas Huber0fa9e392016-08-31 09:05:44 -0700275 bool packageIsJavaCompatible = true;
276 AST *typesAST = nullptr;
277
Andreas Huberd2943e12016-08-05 11:59:31 -0700278 for (const auto &fqName : packageInterfaces) {
279 AST *ast = coordinator->parse(fqName);
280
281 if (ast == NULL) {
282 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700283 "ERROR: Could not parse %s. Aborting.\n",
Andreas Huberd2943e12016-08-05 11:59:31 -0700284 fqName.string().c_str());
285
286 return UNKNOWN_ERROR;
287 }
288
Andreas Huber0fa9e392016-08-31 09:05:44 -0700289 if (packageIsJavaCompatible && !ast->isJavaCompatible()) {
290 packageIsJavaCompatible = false;
291 }
292
293 if (fqName.name() == "types") {
294 typesAST = ast;
295 }
296
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700297 ast->getImportedPackages(&importedPackages);
Andreas Huberd2943e12016-08-05 11:59:31 -0700298 }
299
Dan Willemsen676abdc2016-09-28 19:42:22 -0700300 if (!packageIsJavaCompatible) {
301 return OK;
302 }
303
Andreas Huberd2943e12016-08-05 11:59:31 -0700304 std::string path =
305 coordinator->getPackagePath(packageFQName, false /* relative */);
306
307 path.append("Android.mk");
308
309 CHECK(Coordinator::MakeParentHierarchy(path));
310 FILE *file = fopen(path.c_str(), "w");
311
312 if (file == NULL) {
313 return -errno;
314 }
315
316 const std::string libraryName = makeLibraryName(packageFQName);
317
318 Formatter out(file);
319
Dan Willemsen676abdc2016-09-28 19:42:22 -0700320 out << "# This file is autogenerated by hidl-gen. Do not edit manually.\n\n";
321 out << "LOCAL_PATH := $(call my-dir)\n";
Andreas Huberd2943e12016-08-05 11:59:31 -0700322
Dan Willemsen676abdc2016-09-28 19:42:22 -0700323 enum LibraryStyle {
324 LIBRARY_STYLE_REGULAR,
325 LIBRARY_STYLE_STATIC,
326 LIBRARY_STYLE_END,
327 };
Andreas Huberd2943e12016-08-05 11:59:31 -0700328
Dan Willemsen676abdc2016-09-28 19:42:22 -0700329 for (int style = LIBRARY_STYLE_REGULAR; style != LIBRARY_STYLE_END;
330 ++style) {
331 const std::string staticSuffix =
332 (style == LIBRARY_STYLE_STATIC) ? "-static" : "";
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700333
Dan Willemsen676abdc2016-09-28 19:42:22 -0700334 out << "\n"
335 << "########################################"
336 << "########################################\n\n";
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700337
Dan Willemsen676abdc2016-09-28 19:42:22 -0700338 out << "include $(CLEAR_VARS)\n"
339 << "LOCAL_MODULE := "
340 << libraryName
341 << "-java"
342 << staticSuffix
343 << "\nLOCAL_MODULE_CLASS := JAVA_LIBRARIES\n\n"
344 << "intermediates := $(local-generated-sources-dir)\n\n"
345 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
346 << hidl_gen
347 << "$(HOST_EXECUTABLE_SUFFIX)";
Andreas Huberd2943e12016-08-05 11:59:31 -0700348
Dan Willemsen676abdc2016-09-28 19:42:22 -0700349 if (!importedPackages.empty()) {
Iliyan Malchev800273d2016-09-02 15:25:07 -0700350 out << "\n"
Dan Willemsen676abdc2016-09-28 19:42:22 -0700351 << "\nLOCAL_"
Andreas Huber782d45e2016-09-22 13:25:14 -0700352 << ((style == LIBRARY_STYLE_STATIC) ? "STATIC_" : "")
Dan Willemsen676abdc2016-09-28 19:42:22 -0700353 << "JAVA_LIBRARIES := \\";
354
355 out.indent();
356 for (const auto &importedPackage : importedPackages) {
357 out << "\n"
358 << makeLibraryName(importedPackage)
359 << "-java"
360 << staticSuffix
361 << " \\";
362 }
363 out << "\n";
364 out.unindent();
Iliyan Malchev800273d2016-09-02 15:25:07 -0700365 }
Dan Willemsen676abdc2016-09-28 19:42:22 -0700366
367 generateMakefileSection(
368 out,
369 coordinator,
370 packageFQName,
371 packageInterfaces,
372 typesAST);
373
374 out << "\ninclude $(BUILD_"
375 << ((style == LIBRARY_STYLE_STATIC) ? "STATIC_" : "")
376 << "JAVA_LIBRARY)\n\n";
Andreas Huber0fa9e392016-08-31 09:05:44 -0700377 }
378
Iliyan Malchev8be09552016-09-22 16:20:33 -0700379 out << "\n\n"
380 << "include $(call all-makefiles-under,$(LOCAL_PATH))\n";
381
Andreas Huberd2943e12016-08-05 11:59:31 -0700382 return OK;
383}
384
Andreas Huber0fa9e392016-08-31 09:05:44 -0700385OutputHandler::ValRes validateForMakefile(
386 const FQName &fqName, const std::string & /* language */) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700387 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700388 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700389 return OutputHandler::FAILED;
390 }
391
392 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700393 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700394 return OutputHandler::FAILED;
395 }
396
397 if (!fqName.name().empty()) {
398 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700399 "ERROR: Expecting only package name and version.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700400 return OutputHandler::FAILED;
401 }
402
403 return OutputHandler::PASS_PACKAGE;
404}
405
Dan Willemsen676abdc2016-09-28 19:42:22 -0700406static void generateAndroidBpGenSection(
407 Formatter &out,
408 const FQName &packageFQName,
409 const char *hidl_gen,
410 Coordinator *coordinator,
411 const std::string &genName,
412 const char *language,
413 const std::vector<FQName> &packageInterfaces,
414 const std::function<void(Formatter&, const FQName)> outputFn) {
415
416 out << "genrule {\n";
417 out.indent();
418 out << "name: \"" << genName << "\",\n"
419 << "tool: \"" << hidl_gen << "\",\n";
420
421 out << "cmd: \"$tool -o $genDir"
422 << " -L" << language
423 << " -r"
424 << coordinator->getPackageRoot(packageFQName) << ":"
425 << coordinator->getPackageRootPath(packageFQName)
426 << " " << packageFQName.string() << "\",\n";
427
428 out << "srcs: [\n";
429 out.indent();
430 for (const auto &fqName : packageInterfaces) {
431 out << "\"" << fqName.name() << ".hal\",\n";
432 }
433 out.unindent();
434 out << "],\n";
435
436 out << "out: [\n";
437 out.indent();
438 for (const auto &fqName : packageInterfaces) {
439 outputFn(out, fqName);
440 }
441 out.unindent();
442 out << "],\n";
443
444 out.unindent();
445 out << "}\n\n";
446}
447
448static status_t generateAndroidBpForPackage(
449 const FQName &packageFQName,
450 const char *hidl_gen,
451 Coordinator *coordinator,
452 const std::string &) {
453
454 CHECK(packageFQName.isValid() &&
455 !packageFQName.isFullyQualified() &&
456 packageFQName.name().empty());
457
458 std::vector<FQName> packageInterfaces;
459
460 status_t err =
461 coordinator->appendPackageInterfacesToVector(packageFQName,
462 &packageInterfaces);
463
464 if (err != OK) {
465 return err;
466 }
467
468 std::set<FQName> importedPackages;
469 AST *typesAST = nullptr;
470
471 for (const auto &fqName : packageInterfaces) {
472 AST *ast = coordinator->parse(fqName);
473
474 if (ast == NULL) {
475 fprintf(stderr,
476 "ERROR: Could not parse %s. Aborting.\n",
477 fqName.string().c_str());
478
479 return UNKNOWN_ERROR;
480 }
481
482 if (fqName.name() == "types") {
483 typesAST = ast;
484 }
485
486 ast->getImportedPackages(&importedPackages);
487 }
488
489 std::string path =
490 coordinator->getPackagePath(packageFQName, false /* relative */);
491
492 path.append("Android.bp");
493
494 CHECK(Coordinator::MakeParentHierarchy(path));
495 FILE *file = fopen(path.c_str(), "w");
496
497 if (file == NULL) {
498 return -errno;
499 }
500
501 const std::string libraryName = makeLibraryName(packageFQName);
502 const std::string genSourceName = libraryName + "_genc++";
503 const std::string genHeaderName = libraryName + "_genc++_headers";
504 const std::string pathPrefix =
505 coordinator->convertPackageRootToPath(packageFQName) +
506 coordinator->getPackagePath(packageFQName, true /* relative */);
507
508 Formatter out(file);
509
510 out << "// This file is autogenerated by hidl-gen. Do not edit manually.\n\n";
511
512 // Rule to generate the C++ source files
513 generateAndroidBpGenSection(
514 out,
515 packageFQName,
516 hidl_gen,
517 coordinator,
518 genSourceName,
519 "c++",
520 packageInterfaces,
521 [&pathPrefix](Formatter &out, const FQName &fqName) {
522 if (fqName.name() == "types") {
523 out << "\"" << pathPrefix << "types.cpp\",\n";
524 } else {
525 out << "\"" << pathPrefix << fqName.name().substr(1) << "All.cpp\",\n";
526 }
527 });
528
529 // Rule to generate the C++ header files
530 generateAndroidBpGenSection(
531 out,
532 packageFQName,
533 hidl_gen,
534 coordinator,
535 genHeaderName,
536 "c++",
537 packageInterfaces,
538 [&pathPrefix](Formatter &out, const FQName &fqName) {
539 out << "\"" << pathPrefix << fqName.name() << ".h\",\n";
540 if (fqName.name() != "types") {
541 out << "\"" << pathPrefix << "IHw" << fqName.name().substr(1) << ".h\",\n";
542 out << "\"" << pathPrefix << "Bn" << fqName.name().substr(1) << ".h\",\n";
543 out << "\"" << pathPrefix << "Bp" << fqName.name().substr(1) << ".h\",\n";
544 out << "\"" << pathPrefix << "Bs" << fqName.name().substr(1) << ".h\",\n";
545 }
546 });
547
548 // C++ library definition
549 out << "cc_library_shared {\n";
550 out.indent();
551 out << "name: \"" << libraryName << "\",\n"
552 << "generated_sources: [\"" << genSourceName << "\"],\n"
553 << "generated_headers: [\"" << genHeaderName << "\"],\n"
554 << "export_generated_headers: [\"" << genHeaderName << "\"],\n"
555 << "shared_libs: [\n";
556
557 out.indent();
558 out << "\"libhidl\",\n"
559 << "\"libhwbinder\",\n"
560 << "\"libutils\",\n"
561 << "\"libcutils\",\n";
562 for (const auto &importedPackage : importedPackages) {
563 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
564 }
565 out.unindent();
566
567 out << "],\n";
568 out.unindent();
569 out << "}\n";
570
571 return OK;
572}
573
Steven Moreland197d56c2016-09-09 10:03:58 -0700574static status_t generateMakefileImplForPackage(
575 const FQName &packageFQName,
576 const char *,
577 Coordinator *coordinator,
578 const std::string &outputDir) {
579
Iliyan Malchev4923f932016-09-09 13:04:59 -0700580 const std::string libraryName = makeLibraryName(packageFQName) + "-impl";
Steven Moreland197d56c2016-09-09 10:03:58 -0700581
582 std::vector<FQName> packageInterfaces;
583
584 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700585 coordinator->appendPackageInterfacesToVector(packageFQName,
586 &packageInterfaces);
Steven Moreland197d56c2016-09-09 10:03:58 -0700587
588 if (err != OK) {
589 return err;
590 }
591
592 std::set<FQName> importedPackages;
593
594 for (const auto &fqName : packageInterfaces) {
595 AST *ast = coordinator->parse(fqName);
596
597 if (ast == NULL) {
598 fprintf(stderr,
599 "ERROR: Could not parse %s. Aborting.\n",
600 fqName.string().c_str());
601
602 return UNKNOWN_ERROR;
603 }
604
605 ast->getImportedPackages(&importedPackages);
606 }
607
608 std::string path = outputDir + "Android.mk";
609
610 CHECK(Coordinator::MakeParentHierarchy(path));
611 FILE *file = fopen(path.c_str(), "w");
612
613 if (file == NULL) {
614 return -errno;
615 }
616
617 Formatter out(file);
618
619 out << "LOCAL_PATH := $(call my-dir)\n\n"
620 << "include $(CLEAR_VARS)\n"
621 << "LOCAL_MODULE := " << libraryName << "\n"
622 << "LOCAL_MODULE_RELATIVE_PATH := hw\n"
623 << "LOCAL_SRC_FILES := \\\n";
624 out.indent();
625 for (const auto &fqName : packageInterfaces) {
626 if (fqName.name() == "types") {
627 continue;
628 }
629 out << fqName.getInterfaceBaseName() << ".cpp \\\n";
630 }
631 out.unindent();
632 out << "\n";
633 out << "LOCAL_SHARED_LIBRARIES := \\\n";
634 out.indent();
635 out << "libhidl \\\n"
636 << "libhwbinder \\\n"
637 << "libutils \\\n"
638 << makeLibraryName(packageFQName) << " \\\n";
639 out.unindent();
640 out << "\n";
641
642 out << "include $(BUILD_SHARED_LIBRARY)\n";
643
644 return OK;
645}
646
Andreas Huber0fa9e392016-08-31 09:05:44 -0700647OutputHandler::ValRes validateForSource(
648 const FQName &fqName, const std::string &language) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700649 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700650 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700651 return OutputHandler::FAILED;
652 }
653
654 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700655 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700656 return OutputHandler::FAILED;
657 }
658
Andreas Huber0fa9e392016-08-31 09:05:44 -0700659 const std::string &name = fqName.name();
660 if (!name.empty()) {
661 if (name.find('.') == std::string::npos) {
662 return OutputHandler::PASS_FULL;
663 }
664
665 if (language != "java" || name.find("types.") != 0) {
666 // When generating java sources for "types.hal", output can be
667 // constrained to just one of the top-level types declared
668 // by using the extended syntax
669 // android.hardware.Foo@1.0::types.TopLevelTypeName.
670 // In all other cases (different language, not 'types') the dot
671 // notation in the name is illegal in this context.
672 return OutputHandler::FAILED;
673 }
674
675 return OutputHandler::PASS_FULL;
676 }
677
678 return OutputHandler::PASS_PACKAGE;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700679}
680
681static std::vector<OutputHandler> formats = {
682 {"c++",
Andreas Huber2831d512016-08-15 09:33:47 -0700683 true /* mNeedsOutputDir */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700684 validateForSource,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700685 [](const FQName &fqName,
686 const char *hidl_gen, Coordinator *coordinator,
687 const std::string &outputDir) -> status_t {
688 if (fqName.isFullyQualified()) {
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700689 return generateSourcesForFile(fqName,
690 hidl_gen,
691 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700692 outputDir,
693 "c++");
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700694 } else {
695 return generateSourcesForPackage(fqName,
696 hidl_gen,
697 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700698 outputDir,
699 "c++");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700700 }
701 }
702 },
703
Steven Moreland9c387612016-09-07 09:54:26 -0700704 {"c++-impl",
705 true /* mNeedsOutputDir */,
706 validateForSource,
707 [](const FQName &fqName,
708 const char *hidl_gen, Coordinator *coordinator,
709 const std::string &outputDir) -> status_t {
710 if (fqName.isFullyQualified()) {
711 return generateSourcesForFile(fqName,
712 hidl_gen,
713 coordinator,
714 outputDir, "c++-impl");
715 } else {
716 return generateSourcesForPackage(fqName,
717 hidl_gen,
718 coordinator,
719 outputDir, "c++-impl");
720 }
721 }
722 },
723
724
Andreas Huber2831d512016-08-15 09:33:47 -0700725 {"java",
726 true /* mNeedsOutputDir */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700727 validateForSource,
Andreas Huber2831d512016-08-15 09:33:47 -0700728 [](const FQName &fqName,
729 const char *hidl_gen, Coordinator *coordinator,
730 const std::string &outputDir) -> status_t {
731 if (fqName.isFullyQualified()) {
732 return generateSourcesForFile(fqName,
733 hidl_gen,
734 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700735 outputDir,
736 "java");
Andreas Huber2831d512016-08-15 09:33:47 -0700737 }
738 else {
739 return generateSourcesForPackage(fqName,
740 hidl_gen,
741 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700742 outputDir,
743 "java");
Andreas Huber2831d512016-08-15 09:33:47 -0700744 }
745 }
746 },
747
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700748 {"vts",
749 true,
750 validateForSource,
751 [](const FQName &fqName,
752 const char * hidl_gen,
753 Coordinator *coordinator,
754 const std::string &outputDir) -> status_t {
755 if (fqName.isFullyQualified()) {
756 return generateSourcesForFile(fqName,
757 hidl_gen,
758 coordinator,
759 outputDir, "vts");
760 } else {
761 return generateSourcesForPackage(fqName,
762 hidl_gen,
763 coordinator,
764 outputDir, "vts");
765 }
766 }
767 },
768
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700769 {"makefile",
Andreas Huber2831d512016-08-15 09:33:47 -0700770 false /* mNeedsOutputDir */,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700771 validateForMakefile,
772 generateMakefileForPackage,
773 },
Steven Moreland197d56c2016-09-09 10:03:58 -0700774
Dan Willemsen676abdc2016-09-28 19:42:22 -0700775 {"androidbp",
776 false /* mNeedsOutputDir */,
777 validateForMakefile,
778 generateAndroidBpForPackage,
779 },
780
Steven Moreland197d56c2016-09-09 10:03:58 -0700781 {"makefile-impl",
782 true /* mNeedsOutputDir */,
783 validateForMakefile,
784 generateMakefileImplForPackage,
785 }
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700786};
787
788static void usage(const char *me) {
789 fprintf(stderr,
790 "usage: %s -o output-path -L <language> (-r interface-root)+ fqname+\n",
791 me);
792
793 fprintf(stderr, " -o output path\n");
794
795 fprintf(stderr, " -L <language> (one of");
796 for (auto &e : formats) {
797 fprintf(stderr, " %s", e.mKey.c_str());
798 }
799 fprintf(stderr, ")\n");
800
801 fprintf(stderr,
802 " -r package:path root "
803 "(e.g., android.hardware:hardware/interfaces)\n");
804}
805
Andreas Huberb82318c2016-08-02 14:45:54 -0700806int main(int argc, char **argv) {
807 std::string outputDir;
Andreas Huberdca261f2016-08-04 13:47:51 -0700808 std::vector<std::string> packageRootPaths;
809 std::vector<std::string> packageRoots;
Andreas Huberb82318c2016-08-02 14:45:54 -0700810
Andreas Huber737080b2016-08-02 15:38:04 -0700811 const char *me = argv[0];
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700812 OutputHandler *outputFormat = nullptr;
Andreas Huber737080b2016-08-02 15:38:04 -0700813
Andreas Huberb82318c2016-08-02 14:45:54 -0700814 int res;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700815 while ((res = getopt(argc, argv, "ho:r:L:")) >= 0) {
Andreas Huberb82318c2016-08-02 14:45:54 -0700816 switch (res) {
817 case 'o':
818 {
819 outputDir = optarg;
820 break;
821 }
822
Andreas Huberdca261f2016-08-04 13:47:51 -0700823 case 'r':
824 {
825 std::string val(optarg);
826 auto index = val.find_first_of(':');
827 CHECK(index != std::string::npos);
828
829 auto package = val.substr(0, index);
830 auto path = val.substr(index + 1);
831 packageRootPaths.push_back(path);
832 packageRoots.push_back(package);
833 break;
834 }
835
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700836 case 'L':
837 {
838 CHECK(outputFormat == nullptr); // only one -L option
839 for (auto &e : formats) {
840 if (e.mKey == optarg) {
841 outputFormat = &e;
842 break;
843 }
844 }
845 CHECK(outputFormat != nullptr);
846 break;
847 }
848
Andreas Huberb82318c2016-08-02 14:45:54 -0700849 case '?':
850 case 'h':
851 default:
852 {
Andreas Huber737080b2016-08-02 15:38:04 -0700853 usage(me);
Andreas Huberb82318c2016-08-02 14:45:54 -0700854 exit(1);
855 break;
856 }
857 }
858 }
859
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700860 if (outputFormat == nullptr) {
861 usage(me);
862 exit(1);
863 }
864
Andreas Huberb82318c2016-08-02 14:45:54 -0700865 argc -= optind;
866 argv += optind;
867
Andreas Huberdca261f2016-08-04 13:47:51 -0700868 if (packageRootPaths.empty()) {
869 // Pick reasonable defaults.
870
871 packageRoots.push_back("android.hardware");
872
873 const char *TOP = getenv("TOP");
874 CHECK(TOP != NULL);
875
876 std::string path = TOP;
877 path.append("/hardware/interfaces");
878
879 packageRootPaths.push_back(path);
880 }
881
Andreas Huber737080b2016-08-02 15:38:04 -0700882 // Valid options are now in argv[0] .. argv[argc - 1].
883
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700884 if (!outputFormat->mNeedsOutputDir) {
Andreas Huberd2943e12016-08-05 11:59:31 -0700885 outputDir.clear(); // Unused.
886 } else if (outputDir.empty()) {
Andreas Huber737080b2016-08-02 15:38:04 -0700887 usage(me);
Andreas Huberb82318c2016-08-02 14:45:54 -0700888 exit(1);
889 } else {
890 const size_t len = outputDir.size();
891 if (outputDir[len - 1] != '/') {
892 outputDir += "/";
893 }
894 }
895
Andreas Huberdca261f2016-08-04 13:47:51 -0700896 Coordinator coordinator(packageRootPaths, packageRoots);
Andreas Huber5345ec22016-07-29 13:33:27 -0700897
Andreas Huber737080b2016-08-02 15:38:04 -0700898 for (int i = 0; i < argc; ++i) {
Andreas Huber68f24592016-07-29 14:53:48 -0700899 FQName fqName(argv[i]);
Andreas Huber68f24592016-07-29 14:53:48 -0700900
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700901 if (!fqName.isValid()) {
Andreas Hubere61e3f72016-08-03 10:22:03 -0700902 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700903 "ERROR: Invalid fully-qualified name.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700904 exit(1);
905 }
Andreas Huber881227d2016-08-02 14:20:21 -0700906
Andreas Huber0fa9e392016-08-31 09:05:44 -0700907 OutputHandler::ValRes valid =
908 outputFormat->validate(fqName, outputFormat->mKey);
909
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700910 if (valid == OutputHandler::FAILED) {
Andreas Hubere61e3f72016-08-03 10:22:03 -0700911 exit(1);
912 }
Andreas Huberd2943e12016-08-05 11:59:31 -0700913
914 status_t err =
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700915 outputFormat->generate(fqName, me, &coordinator, outputDir);
Andreas Huberd2943e12016-08-05 11:59:31 -0700916
917 if (err != OK) {
Steven Moreland261370a2016-08-29 15:36:59 -0700918 exit(1);
Andreas Huberd2943e12016-08-05 11:59:31 -0700919 }
Andreas Hubereb1081f2016-07-28 13:13:24 -0700920 }
Andreas Huberc9410c72016-07-28 12:18:40 -0700921
Andreas Huberd2943e12016-08-05 11:59:31 -0700922 return 0;
Andreas Huberc9410c72016-07-28 12:18:40 -0700923}