blob: c33ce5e6edd944ab95f9a719d162f959531264f3 [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
Andreas Huber1c507272016-10-05 14:33:21 -0700346static void generateMakefileSectionForJavaConstants(
347 Formatter &out,
348 Coordinator *coordinator,
349 const FQName &packageFQName,
350 const std::vector<FQName> &packageInterfaces) {
351 out << "\n#"
352 << "\nGEN := $(intermediates)/"
353 << coordinator->convertPackageRootToPath(packageFQName)
354 << coordinator->getPackagePath(packageFQName, true /* relative */)
355 << "Constants.java";
356
357 out << "\n$(GEN): $(HIDL)\n";
358 for (const auto &iface : packageInterfaces) {
359 out << "$(GEN): $(LOCAL_PATH)/" << iface.name() << ".hal\n";
360 }
361 out << "\n$(GEN): PRIVATE_HIDL := $(HIDL)";
362 out << "\n$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)"
363 << "\n$(GEN): PRIVATE_CUSTOM_TOOL = \\";
364 out.indent();
365 out.indent();
366 out << "\n$(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \\"
367 << "\n-Ljava-constants"
368 << " -r"
369 << coordinator->getPackageRoot(packageFQName) << ":"
370 << coordinator->getPackageRootPath(packageFQName) << " \\\n";
371
372 out << packageFQName.string();
373 out << "\n";
374
375 out.unindent();
376 out.unindent();
377
378 out << "\n$(GEN):";
379 out << "\n\t$(transform-generated-source)";
380 out << "\nLOCAL_GENERATED_SOURCES += $(GEN)";
381}
382
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700383static status_t generateMakefileForPackage(
384 const FQName &packageFQName,
Iliyan Malchevb66c3992016-08-07 21:18:13 -0700385 const char *hidl_gen,
Andreas Huberd2943e12016-08-05 11:59:31 -0700386 Coordinator *coordinator,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700387 const std::string &) {
388
389 CHECK(packageFQName.isValid() &&
390 !packageFQName.isFullyQualified() &&
391 packageFQName.name().empty());
392
Andreas Huberd2943e12016-08-05 11:59:31 -0700393 std::vector<FQName> packageInterfaces;
394
395 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700396 coordinator->appendPackageInterfacesToVector(packageFQName,
397 &packageInterfaces);
Andreas Huberd2943e12016-08-05 11:59:31 -0700398
399 if (err != OK) {
400 return err;
401 }
402
403 std::set<FQName> importedPackages;
Andreas Huber0fa9e392016-08-31 09:05:44 -0700404 AST *typesAST = nullptr;
Andreas Huber1c507272016-10-05 14:33:21 -0700405 std::vector<const Type *> exportedTypes;
Andreas Huber0fa9e392016-08-31 09:05:44 -0700406
Andreas Huberd2943e12016-08-05 11:59:31 -0700407 for (const auto &fqName : packageInterfaces) {
408 AST *ast = coordinator->parse(fqName);
409
410 if (ast == NULL) {
411 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700412 "ERROR: Could not parse %s. Aborting.\n",
Andreas Huberd2943e12016-08-05 11:59:31 -0700413 fqName.string().c_str());
414
415 return UNKNOWN_ERROR;
416 }
417
Andreas Huber0fa9e392016-08-31 09:05:44 -0700418 if (fqName.name() == "types") {
419 typesAST = ast;
420 }
421
Yifan Hong40a373d2016-11-30 15:16:47 -0800422 ast->getImportedPackagesHierarchy(&importedPackages);
Andreas Huber1c507272016-10-05 14:33:21 -0700423 ast->appendToExportedTypesVector(&exportedTypes);
Andreas Huberd2943e12016-08-05 11:59:31 -0700424 }
425
Andreas Huber75ae95d2016-10-12 16:08:26 -0700426 bool packageIsJavaCompatible;
427 err = isPackageJavaCompatible(
428 packageFQName, coordinator, &packageIsJavaCompatible);
429
430 if (err != OK) {
431 return err;
432 }
433
Andreas Huber1c507272016-10-05 14:33:21 -0700434 bool haveJavaConstants = !exportedTypes.empty();
435
436 if (!packageIsJavaCompatible && !haveJavaConstants) {
Dan Willemsen676abdc2016-09-28 19:42:22 -0700437 return OK;
438 }
439
Andreas Huber5a9fe2c2016-10-13 15:31:10 -0700440 if (!packageNeedsJavaCode(packageInterfaces, typesAST)) {
441 return OK;
442 }
443
Andreas Huberd2943e12016-08-05 11:59:31 -0700444 std::string path =
445 coordinator->getPackagePath(packageFQName, false /* relative */);
446
447 path.append("Android.mk");
448
449 CHECK(Coordinator::MakeParentHierarchy(path));
450 FILE *file = fopen(path.c_str(), "w");
451
452 if (file == NULL) {
453 return -errno;
454 }
455
456 const std::string libraryName = makeLibraryName(packageFQName);
457
458 Formatter out(file);
459
Dan Willemsen676abdc2016-09-28 19:42:22 -0700460 out << "# This file is autogenerated by hidl-gen. Do not edit manually.\n\n";
461 out << "LOCAL_PATH := $(call my-dir)\n";
Andreas Huberd2943e12016-08-05 11:59:31 -0700462
Dan Willemsen676abdc2016-09-28 19:42:22 -0700463 enum LibraryStyle {
464 LIBRARY_STYLE_REGULAR,
465 LIBRARY_STYLE_STATIC,
466 LIBRARY_STYLE_END,
467 };
Andreas Huberd2943e12016-08-05 11:59:31 -0700468
Andreas Huber1c507272016-10-05 14:33:21 -0700469 for (int style = LIBRARY_STYLE_REGULAR;
470 (packageIsJavaCompatible && style != LIBRARY_STYLE_END);
Dan Willemsen676abdc2016-09-28 19:42:22 -0700471 ++style) {
472 const std::string staticSuffix =
473 (style == LIBRARY_STYLE_STATIC) ? "-static" : "";
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700474
Dan Willemsen676abdc2016-09-28 19:42:22 -0700475 out << "\n"
476 << "########################################"
477 << "########################################\n\n";
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700478
Dan Willemsen676abdc2016-09-28 19:42:22 -0700479 out << "include $(CLEAR_VARS)\n"
480 << "LOCAL_MODULE := "
481 << libraryName
482 << "-java"
483 << staticSuffix
484 << "\nLOCAL_MODULE_CLASS := JAVA_LIBRARIES\n\n"
485 << "intermediates := $(local-generated-sources-dir)\n\n"
486 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
487 << hidl_gen
488 << "$(HOST_EXECUTABLE_SUFFIX)";
Andreas Huberd2943e12016-08-05 11:59:31 -0700489
Dan Willemsen676abdc2016-09-28 19:42:22 -0700490 if (!importedPackages.empty()) {
Iliyan Malchev800273d2016-09-02 15:25:07 -0700491 out << "\n"
Dan Willemsen676abdc2016-09-28 19:42:22 -0700492 << "\nLOCAL_"
Andreas Huber782d45e2016-09-22 13:25:14 -0700493 << ((style == LIBRARY_STYLE_STATIC) ? "STATIC_" : "")
Dan Willemsen676abdc2016-09-28 19:42:22 -0700494 << "JAVA_LIBRARIES := \\";
495
496 out.indent();
497 for (const auto &importedPackage : importedPackages) {
498 out << "\n"
499 << makeLibraryName(importedPackage)
500 << "-java"
501 << staticSuffix
502 << " \\";
503 }
504 out << "\n";
505 out.unindent();
Iliyan Malchev800273d2016-09-02 15:25:07 -0700506 }
Dan Willemsen676abdc2016-09-28 19:42:22 -0700507
508 generateMakefileSection(
509 out,
510 coordinator,
511 packageFQName,
512 packageInterfaces,
513 typesAST);
514
515 out << "\ninclude $(BUILD_"
516 << ((style == LIBRARY_STYLE_STATIC) ? "STATIC_" : "")
517 << "JAVA_LIBRARY)\n\n";
Andreas Huber0fa9e392016-08-31 09:05:44 -0700518 }
519
Andreas Huber1c507272016-10-05 14:33:21 -0700520 if (haveJavaConstants) {
521 out << "\n"
522 << "########################################"
523 << "########################################\n\n";
524
525 out << "include $(CLEAR_VARS)\n"
526 << "LOCAL_MODULE := "
527 << libraryName
528 << "-java-constants"
529 << "\nLOCAL_MODULE_CLASS := JAVA_LIBRARIES\n\n"
530 << "intermediates := $(local-generated-sources-dir)\n\n"
531 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
532 << hidl_gen
533 << "$(HOST_EXECUTABLE_SUFFIX)";
534
535 generateMakefileSectionForJavaConstants(
536 out, coordinator, packageFQName, packageInterfaces);
537
538 out << "\n# Avoid dependency cycle of framework.jar -> this-library "
539 << "-> framework.jar\n"
540 << "LOCAL_NO_STANDARD_LIBRARIES := true\n"
541 << "LOCAL_JAVA_LIBRARIES := core-oj\n\n"
542 << "include $(BUILD_STATIC_JAVA_LIBRARY)\n\n";
543 }
544
Iliyan Malchev8be09552016-09-22 16:20:33 -0700545 out << "\n\n"
546 << "include $(call all-makefiles-under,$(LOCAL_PATH))\n";
547
Andreas Huberd2943e12016-08-05 11:59:31 -0700548 return OK;
549}
550
Andreas Huber0fa9e392016-08-31 09:05:44 -0700551OutputHandler::ValRes validateForMakefile(
552 const FQName &fqName, const std::string & /* language */) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700553 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700554 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700555 return OutputHandler::FAILED;
556 }
557
558 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700559 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700560 return OutputHandler::FAILED;
561 }
562
563 if (!fqName.name().empty()) {
564 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700565 "ERROR: Expecting only package name and version.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700566 return OutputHandler::FAILED;
567 }
568
569 return OutputHandler::PASS_PACKAGE;
570}
571
Dan Willemsen676abdc2016-09-28 19:42:22 -0700572static void generateAndroidBpGenSection(
573 Formatter &out,
574 const FQName &packageFQName,
575 const char *hidl_gen,
576 Coordinator *coordinator,
577 const std::string &genName,
578 const char *language,
579 const std::vector<FQName> &packageInterfaces,
580 const std::function<void(Formatter&, const FQName)> outputFn) {
581
582 out << "genrule {\n";
583 out.indent();
584 out << "name: \"" << genName << "\",\n"
Colin Crossd5419bd2016-11-04 15:05:54 -0700585 << "tools: [\"" << hidl_gen << "\"],\n";
Dan Willemsen676abdc2016-09-28 19:42:22 -0700586
Colin Crossd5419bd2016-11-04 15:05:54 -0700587 out << "cmd: \"$(location " << hidl_gen << ") -o $(genDir)"
Dan Willemsen676abdc2016-09-28 19:42:22 -0700588 << " -L" << language
589 << " -r"
590 << coordinator->getPackageRoot(packageFQName) << ":"
591 << coordinator->getPackageRootPath(packageFQName)
592 << " " << packageFQName.string() << "\",\n";
593
594 out << "srcs: [\n";
595 out.indent();
596 for (const auto &fqName : packageInterfaces) {
597 out << "\"" << fqName.name() << ".hal\",\n";
598 }
599 out.unindent();
600 out << "],\n";
601
602 out << "out: [\n";
603 out.indent();
604 for (const auto &fqName : packageInterfaces) {
605 outputFn(out, fqName);
606 }
607 out.unindent();
608 out << "],\n";
609
610 out.unindent();
611 out << "}\n\n";
612}
613
614static status_t generateAndroidBpForPackage(
615 const FQName &packageFQName,
616 const char *hidl_gen,
617 Coordinator *coordinator,
618 const std::string &) {
619
620 CHECK(packageFQName.isValid() &&
621 !packageFQName.isFullyQualified() &&
622 packageFQName.name().empty());
623
624 std::vector<FQName> packageInterfaces;
625
626 status_t err =
627 coordinator->appendPackageInterfacesToVector(packageFQName,
628 &packageInterfaces);
629
630 if (err != OK) {
631 return err;
632 }
633
634 std::set<FQName> importedPackages;
635 AST *typesAST = nullptr;
636
637 for (const auto &fqName : packageInterfaces) {
638 AST *ast = coordinator->parse(fqName);
639
640 if (ast == NULL) {
641 fprintf(stderr,
642 "ERROR: Could not parse %s. Aborting.\n",
643 fqName.string().c_str());
644
645 return UNKNOWN_ERROR;
646 }
647
648 if (fqName.name() == "types") {
649 typesAST = ast;
650 }
651
652 ast->getImportedPackages(&importedPackages);
653 }
654
655 std::string path =
656 coordinator->getPackagePath(packageFQName, false /* relative */);
657
658 path.append("Android.bp");
659
660 CHECK(Coordinator::MakeParentHierarchy(path));
661 FILE *file = fopen(path.c_str(), "w");
662
663 if (file == NULL) {
664 return -errno;
665 }
666
667 const std::string libraryName = makeLibraryName(packageFQName);
668 const std::string genSourceName = libraryName + "_genc++";
669 const std::string genHeaderName = libraryName + "_genc++_headers";
670 const std::string pathPrefix =
671 coordinator->convertPackageRootToPath(packageFQName) +
672 coordinator->getPackagePath(packageFQName, true /* relative */);
673
674 Formatter out(file);
675
676 out << "// This file is autogenerated by hidl-gen. Do not edit manually.\n\n";
677
678 // Rule to generate the C++ source files
679 generateAndroidBpGenSection(
680 out,
681 packageFQName,
682 hidl_gen,
683 coordinator,
684 genSourceName,
685 "c++",
686 packageInterfaces,
687 [&pathPrefix](Formatter &out, const FQName &fqName) {
688 if (fqName.name() == "types") {
689 out << "\"" << pathPrefix << "types.cpp\",\n";
690 } else {
691 out << "\"" << pathPrefix << fqName.name().substr(1) << "All.cpp\",\n";
692 }
693 });
694
695 // Rule to generate the C++ header files
696 generateAndroidBpGenSection(
697 out,
698 packageFQName,
699 hidl_gen,
700 coordinator,
701 genHeaderName,
702 "c++",
703 packageInterfaces,
704 [&pathPrefix](Formatter &out, const FQName &fqName) {
705 out << "\"" << pathPrefix << fqName.name() << ".h\",\n";
706 if (fqName.name() != "types") {
707 out << "\"" << pathPrefix << "IHw" << fqName.name().substr(1) << ".h\",\n";
708 out << "\"" << pathPrefix << "Bn" << fqName.name().substr(1) << ".h\",\n";
709 out << "\"" << pathPrefix << "Bp" << fqName.name().substr(1) << ".h\",\n";
710 out << "\"" << pathPrefix << "Bs" << fqName.name().substr(1) << ".h\",\n";
711 }
712 });
713
714 // C++ library definition
715 out << "cc_library_shared {\n";
716 out.indent();
717 out << "name: \"" << libraryName << "\",\n"
718 << "generated_sources: [\"" << genSourceName << "\"],\n"
719 << "generated_headers: [\"" << genHeaderName << "\"],\n"
720 << "export_generated_headers: [\"" << genHeaderName << "\"],\n"
721 << "shared_libs: [\n";
722
723 out.indent();
Yifan Honga5abe922016-11-16 14:18:37 -0800724 out << "\"libhidlbase\",\n"
725 << "\"libhidltransport\",\n"
Dan Willemsen676abdc2016-09-28 19:42:22 -0700726 << "\"libhwbinder\",\n"
Steven Moreland05cd4232016-11-21 16:01:12 -0800727 << "\"liblog\",\n"
Dan Willemsen676abdc2016-09-28 19:42:22 -0700728 << "\"libutils\",\n"
729 << "\"libcutils\",\n";
730 for (const auto &importedPackage : importedPackages) {
731 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
732 }
733 out.unindent();
734
735 out << "],\n";
Steven Morelandb8a26c02016-10-21 13:40:14 -0700736
737 out << "export_shared_lib_headers: [\n";
738 out.indent();
Yifan Honga5abe922016-11-16 14:18:37 -0800739 out << "\"libhidlbase\",\n"
740 << "\"libhidltransport\",\n"
Steven Morelandb8a26c02016-10-21 13:40:14 -0700741 << "\"libhwbinder\",\n"
Steven Moreland865243c2016-11-01 13:05:24 -0700742 << "\"libutils\",\n";
Yifan Hongc1f9b8d2016-11-07 14:35:44 -0800743 for (const auto &importedPackage : importedPackages) {
744 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
745 }
Steven Moreland865243c2016-11-01 13:05:24 -0700746 out.unindent();
747 out << "],\n";
Steven Morelandb8a26c02016-10-21 13:40:14 -0700748 out.unindent();
749
Dan Willemsen676abdc2016-09-28 19:42:22 -0700750 out << "}\n";
751
752 return OK;
753}
754
Steven Moreland197d56c2016-09-09 10:03:58 -0700755static status_t generateMakefileImplForPackage(
756 const FQName &packageFQName,
757 const char *,
758 Coordinator *coordinator,
759 const std::string &outputDir) {
760
Iliyan Malchev4923f932016-09-09 13:04:59 -0700761 const std::string libraryName = makeLibraryName(packageFQName) + "-impl";
Steven Moreland197d56c2016-09-09 10:03:58 -0700762
763 std::vector<FQName> packageInterfaces;
764
765 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700766 coordinator->appendPackageInterfacesToVector(packageFQName,
767 &packageInterfaces);
Steven Moreland197d56c2016-09-09 10:03:58 -0700768
769 if (err != OK) {
770 return err;
771 }
772
773 std::set<FQName> importedPackages;
774
775 for (const auto &fqName : packageInterfaces) {
776 AST *ast = coordinator->parse(fqName);
777
778 if (ast == NULL) {
779 fprintf(stderr,
780 "ERROR: Could not parse %s. Aborting.\n",
781 fqName.string().c_str());
782
783 return UNKNOWN_ERROR;
784 }
785
786 ast->getImportedPackages(&importedPackages);
787 }
788
789 std::string path = outputDir + "Android.mk";
790
791 CHECK(Coordinator::MakeParentHierarchy(path));
792 FILE *file = fopen(path.c_str(), "w");
793
794 if (file == NULL) {
795 return -errno;
796 }
797
798 Formatter out(file);
799
800 out << "LOCAL_PATH := $(call my-dir)\n\n"
801 << "include $(CLEAR_VARS)\n"
802 << "LOCAL_MODULE := " << libraryName << "\n"
803 << "LOCAL_MODULE_RELATIVE_PATH := hw\n"
804 << "LOCAL_SRC_FILES := \\\n";
805 out.indent();
806 for (const auto &fqName : packageInterfaces) {
807 if (fqName.name() == "types") {
808 continue;
809 }
810 out << fqName.getInterfaceBaseName() << ".cpp \\\n";
811 }
812 out.unindent();
813 out << "\n";
814 out << "LOCAL_SHARED_LIBRARIES := \\\n";
815 out.indent();
Yifan Honga5abe922016-11-16 14:18:37 -0800816 out << "libhidlbase \\\n"
817 << "libhidltransport \\\n"
Steven Moreland197d56c2016-09-09 10:03:58 -0700818 << "libhwbinder \\\n"
819 << "libutils \\\n"
820 << makeLibraryName(packageFQName) << " \\\n";
Yifan Honge0f7d692016-10-20 17:51:33 -0700821
822 for (const auto &importedPackage : importedPackages) {
823 out << makeLibraryName(importedPackage)
824 << " \\\n";
825 }
Steven Moreland197d56c2016-09-09 10:03:58 -0700826 out.unindent();
827 out << "\n";
828
829 out << "include $(BUILD_SHARED_LIBRARY)\n";
830
831 return OK;
832}
833
Andreas Huber0fa9e392016-08-31 09:05:44 -0700834OutputHandler::ValRes validateForSource(
835 const FQName &fqName, const std::string &language) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700836 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700837 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700838 return OutputHandler::FAILED;
839 }
840
841 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700842 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700843 return OutputHandler::FAILED;
844 }
845
Andreas Huber0fa9e392016-08-31 09:05:44 -0700846 const std::string &name = fqName.name();
847 if (!name.empty()) {
848 if (name.find('.') == std::string::npos) {
849 return OutputHandler::PASS_FULL;
850 }
851
852 if (language != "java" || name.find("types.") != 0) {
853 // When generating java sources for "types.hal", output can be
854 // constrained to just one of the top-level types declared
855 // by using the extended syntax
856 // android.hardware.Foo@1.0::types.TopLevelTypeName.
857 // In all other cases (different language, not 'types') the dot
858 // notation in the name is illegal in this context.
859 return OutputHandler::FAILED;
860 }
861
862 return OutputHandler::PASS_FULL;
863 }
864
865 return OutputHandler::PASS_PACKAGE;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700866}
867
Andreas Huber019d21d2016-10-03 12:59:47 -0700868OutputHandler::ValRes validateForExportHeader(
869 const FQName &fqName, const std::string & /* language */) {
870 if (fqName.package().empty()) {
871 fprintf(stderr, "ERROR: Expecting package name\n");
872 return OutputHandler::FAILED;
873 }
874
875 if (fqName.version().empty()) {
876 fprintf(stderr, "ERROR: Expecting package version\n");
877 return OutputHandler::FAILED;
878 }
879
880 if (!fqName.name().empty()) {
881 fprintf(stderr,
882 "ERROR: Expecting only package name and version.\n");
883 return OutputHandler::FAILED;
884 }
885
886 return OutputHandler::PASS_PACKAGE;
887}
888
889
890static status_t generateExportHeaderForPackage(
891 const FQName &packageFQName,
892 const char * /* hidl_gen */,
893 Coordinator *coordinator,
Andreas Huber1c507272016-10-05 14:33:21 -0700894 const std::string &outputPath,
895 bool forJava) {
Andreas Huber019d21d2016-10-03 12:59:47 -0700896
897 CHECK(packageFQName.isValid()
898 && !packageFQName.isFullyQualified()
899 && packageFQName.name().empty());
900
901 std::vector<FQName> packageInterfaces;
902
903 status_t err = coordinator->appendPackageInterfacesToVector(
904 packageFQName, &packageInterfaces);
905
906 if (err != OK) {
907 return err;
908 }
909
910 std::vector<const Type *> exportedTypes;
911
912 for (const auto &fqName : packageInterfaces) {
913 AST *ast = coordinator->parse(fqName);
914
915 if (ast == NULL) {
916 fprintf(stderr,
917 "ERROR: Could not parse %s. Aborting.\n",
918 fqName.string().c_str());
919
920 return UNKNOWN_ERROR;
921 }
922
923 ast->appendToExportedTypesVector(&exportedTypes);
924 }
925
926 if (exportedTypes.empty()) {
927 return OK;
928 }
929
Andreas Huber1c507272016-10-05 14:33:21 -0700930 std::string path = outputPath;
931
932 if (forJava) {
933 path.append(coordinator->convertPackageRootToPath(packageFQName));
934
935 path.append(coordinator->getPackagePath(
936 packageFQName, true /* relative */));
937
938 path.append("Constants.java");
939 }
940
941 CHECK(Coordinator::MakeParentHierarchy(path));
942 FILE *file = fopen(path.c_str(), "w");
Andreas Huber019d21d2016-10-03 12:59:47 -0700943
944 if (file == nullptr) {
945 return -errno;
946 }
947
948 Formatter out(file);
949
950 out << "// This file is autogenerated by hidl-gen. Do not edit manually."
951 "\n\n";
952
Andreas Huber1c507272016-10-05 14:33:21 -0700953 std::string guard;
954 if (forJava) {
955 out << "package " << packageFQName.javaPackage() << ";\n\n";
956 out << "public class Constants {\n";
957 out.indent();
958 } else {
959 guard = "HIDL_GENERATED_";
960 guard += packageFQName.tokenName();
961 guard += "_";
962 guard += "EXPORTED_CONSTANTS_H_";
Andreas Huber019d21d2016-10-03 12:59:47 -0700963
Andreas Huber1c507272016-10-05 14:33:21 -0700964 out << "#ifndef "
965 << guard
966 << "\n#define "
967 << guard
968 << "\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n";
Andreas Huber019d21d2016-10-03 12:59:47 -0700969 }
970
Andreas Huber1c507272016-10-05 14:33:21 -0700971 for (const auto &type : exportedTypes) {
972 type->emitExportedHeader(out, forJava);
973 }
974
975 if (forJava) {
976 out.unindent();
977 out << "}\n";
978 } else {
979 out << "#ifdef __cplusplus\n}\n#endif\n\n#endif // "
980 << guard
981 << "\n";
982 }
Andreas Huber019d21d2016-10-03 12:59:47 -0700983
984 return OK;
985}
986
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700987static std::vector<OutputHandler> formats = {
988 {"c++",
Andreas Huber019d21d2016-10-03 12:59:47 -0700989 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700990 validateForSource,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700991 [](const FQName &fqName,
992 const char *hidl_gen, Coordinator *coordinator,
993 const std::string &outputDir) -> status_t {
994 if (fqName.isFullyQualified()) {
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700995 return generateSourcesForFile(fqName,
996 hidl_gen,
997 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700998 outputDir,
999 "c++");
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001000 } else {
1001 return generateSourcesForPackage(fqName,
1002 hidl_gen,
1003 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -07001004 outputDir,
1005 "c++");
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001006 }
1007 }
1008 },
1009
Andreas Huber019d21d2016-10-03 12:59:47 -07001010 {"export-header",
1011 OutputHandler::NEEDS_FILE /* mOutputMode */,
1012 validateForExportHeader,
1013 [](const FQName &fqName,
1014 const char *hidl_gen,
1015 Coordinator *coordinator,
1016 const std::string &outputPath) -> status_t {
1017 CHECK(!fqName.isFullyQualified());
1018
1019 return generateExportHeaderForPackage(
1020 fqName,
1021 hidl_gen,
1022 coordinator,
Andreas Huber1c507272016-10-05 14:33:21 -07001023 outputPath,
1024 false /* forJava */);
Andreas Huber019d21d2016-10-03 12:59:47 -07001025 }
1026 },
1027
Steven Moreland9c387612016-09-07 09:54:26 -07001028 {"c++-impl",
Andreas Huber019d21d2016-10-03 12:59:47 -07001029 OutputHandler::NEEDS_DIR /* mOutputMode */,
Steven Moreland9c387612016-09-07 09:54:26 -07001030 validateForSource,
1031 [](const FQName &fqName,
1032 const char *hidl_gen, Coordinator *coordinator,
1033 const std::string &outputDir) -> status_t {
1034 if (fqName.isFullyQualified()) {
1035 return generateSourcesForFile(fqName,
1036 hidl_gen,
1037 coordinator,
1038 outputDir, "c++-impl");
1039 } else {
1040 return generateSourcesForPackage(fqName,
1041 hidl_gen,
1042 coordinator,
1043 outputDir, "c++-impl");
1044 }
1045 }
1046 },
1047
1048
Andreas Huber2831d512016-08-15 09:33:47 -07001049 {"java",
Andreas Huber019d21d2016-10-03 12:59:47 -07001050 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001051 validateForSource,
Andreas Huber2831d512016-08-15 09:33:47 -07001052 [](const FQName &fqName,
1053 const char *hidl_gen, Coordinator *coordinator,
1054 const std::string &outputDir) -> status_t {
1055 if (fqName.isFullyQualified()) {
1056 return generateSourcesForFile(fqName,
1057 hidl_gen,
1058 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -07001059 outputDir,
1060 "java");
Andreas Huber2831d512016-08-15 09:33:47 -07001061 }
1062 else {
1063 return generateSourcesForPackage(fqName,
1064 hidl_gen,
1065 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -07001066 outputDir,
1067 "java");
Andreas Huber2831d512016-08-15 09:33:47 -07001068 }
1069 }
1070 },
1071
Andreas Huber1c507272016-10-05 14:33:21 -07001072 {"java-constants",
1073 OutputHandler::NEEDS_DIR /* mOutputMode */,
1074 validateForExportHeader,
1075 [](const FQName &fqName,
1076 const char *hidl_gen, Coordinator *coordinator,
1077 const std::string &outputDir) -> status_t {
1078 CHECK(!fqName.isFullyQualified());
1079 return generateExportHeaderForPackage(
1080 fqName,
1081 hidl_gen,
1082 coordinator,
1083 outputDir,
1084 true /* forJava */);
1085 }
1086 },
1087
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001088 {"vts",
Andreas Huber019d21d2016-10-03 12:59:47 -07001089 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001090 validateForSource,
1091 [](const FQName &fqName,
1092 const char * hidl_gen,
1093 Coordinator *coordinator,
1094 const std::string &outputDir) -> status_t {
1095 if (fqName.isFullyQualified()) {
1096 return generateSourcesForFile(fqName,
1097 hidl_gen,
1098 coordinator,
1099 outputDir, "vts");
1100 } else {
1101 return generateSourcesForPackage(fqName,
1102 hidl_gen,
1103 coordinator,
1104 outputDir, "vts");
1105 }
1106 }
1107 },
1108
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001109 {"makefile",
Andreas Huber019d21d2016-10-03 12:59:47 -07001110 OutputHandler::NOT_NEEDED /* mOutputMode */,
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001111 validateForMakefile,
1112 generateMakefileForPackage,
1113 },
Steven Moreland197d56c2016-09-09 10:03:58 -07001114
Dan Willemsen676abdc2016-09-28 19:42:22 -07001115 {"androidbp",
Andreas Huber019d21d2016-10-03 12:59:47 -07001116 OutputHandler::NOT_NEEDED /* mOutputMode */,
Dan Willemsen676abdc2016-09-28 19:42:22 -07001117 validateForMakefile,
1118 generateAndroidBpForPackage,
1119 },
1120
Steven Moreland197d56c2016-09-09 10:03:58 -07001121 {"makefile-impl",
Yifan Hong94bcea02016-10-06 13:51:31 -07001122 OutputHandler::NEEDS_DIR /* mOutputMode */,
Steven Moreland197d56c2016-09-09 10:03:58 -07001123 validateForMakefile,
1124 generateMakefileImplForPackage,
1125 }
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001126};
1127
1128static void usage(const char *me) {
1129 fprintf(stderr,
1130 "usage: %s -o output-path -L <language> (-r interface-root)+ fqname+\n",
1131 me);
1132
1133 fprintf(stderr, " -o output path\n");
1134
1135 fprintf(stderr, " -L <language> (one of");
1136 for (auto &e : formats) {
1137 fprintf(stderr, " %s", e.mKey.c_str());
1138 }
1139 fprintf(stderr, ")\n");
1140
1141 fprintf(stderr,
1142 " -r package:path root "
1143 "(e.g., android.hardware:hardware/interfaces)\n");
1144}
1145
Andreas Huberb82318c2016-08-02 14:45:54 -07001146int main(int argc, char **argv) {
Andreas Huber019d21d2016-10-03 12:59:47 -07001147 std::string outputPath;
Andreas Huberdca261f2016-08-04 13:47:51 -07001148 std::vector<std::string> packageRootPaths;
1149 std::vector<std::string> packageRoots;
Andreas Huberb82318c2016-08-02 14:45:54 -07001150
Andreas Huber737080b2016-08-02 15:38:04 -07001151 const char *me = argv[0];
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001152 OutputHandler *outputFormat = nullptr;
Andreas Huber737080b2016-08-02 15:38:04 -07001153
Andreas Huberb82318c2016-08-02 14:45:54 -07001154 int res;
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001155 while ((res = getopt(argc, argv, "ho:r:L:")) >= 0) {
Andreas Huberb82318c2016-08-02 14:45:54 -07001156 switch (res) {
1157 case 'o':
1158 {
Andreas Huber019d21d2016-10-03 12:59:47 -07001159 outputPath = optarg;
Andreas Huberb82318c2016-08-02 14:45:54 -07001160 break;
1161 }
1162
Andreas Huberdca261f2016-08-04 13:47:51 -07001163 case 'r':
1164 {
1165 std::string val(optarg);
1166 auto index = val.find_first_of(':');
1167 CHECK(index != std::string::npos);
1168
1169 auto package = val.substr(0, index);
1170 auto path = val.substr(index + 1);
1171 packageRootPaths.push_back(path);
1172 packageRoots.push_back(package);
1173 break;
1174 }
1175
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001176 case 'L':
1177 {
Steven Morelande429a262016-11-15 09:54:32 -08001178 CHECK(outputFormat == nullptr) << "Only one -L option allowed.";
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001179 for (auto &e : formats) {
1180 if (e.mKey == optarg) {
1181 outputFormat = &e;
1182 break;
1183 }
1184 }
Steven Morelande429a262016-11-15 09:54:32 -08001185 CHECK(outputFormat != nullptr) << "Output format not recognized.";
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001186 break;
1187 }
1188
Andreas Huberb82318c2016-08-02 14:45:54 -07001189 case '?':
1190 case 'h':
1191 default:
1192 {
Andreas Huber737080b2016-08-02 15:38:04 -07001193 usage(me);
Andreas Huberb82318c2016-08-02 14:45:54 -07001194 exit(1);
1195 break;
1196 }
1197 }
1198 }
1199
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001200 if (outputFormat == nullptr) {
1201 usage(me);
1202 exit(1);
1203 }
1204
Andreas Huberb82318c2016-08-02 14:45:54 -07001205 argc -= optind;
1206 argv += optind;
1207
Andreas Huberdca261f2016-08-04 13:47:51 -07001208 if (packageRootPaths.empty()) {
1209 // Pick reasonable defaults.
1210
1211 packageRoots.push_back("android.hardware");
1212
1213 const char *TOP = getenv("TOP");
Steven Morelandaf330382016-11-09 15:48:03 -08001214 if (TOP == nullptr) {
1215 fprintf(stderr,
1216 "ERROR: No root path (-r) specified"
1217 " and $TOP environment variable not set.\n");
1218 exit(1);
1219 }
Andreas Huberdca261f2016-08-04 13:47:51 -07001220
1221 std::string path = TOP;
1222 path.append("/hardware/interfaces");
1223
1224 packageRootPaths.push_back(path);
1225 }
1226
Andreas Huber737080b2016-08-02 15:38:04 -07001227 // Valid options are now in argv[0] .. argv[argc - 1].
1228
Andreas Huber019d21d2016-10-03 12:59:47 -07001229 switch (outputFormat->mOutputMode) {
1230 case OutputHandler::NEEDS_DIR:
1231 case OutputHandler::NEEDS_FILE:
1232 {
1233 if (outputPath.empty()) {
1234 usage(me);
1235 exit(1);
1236 }
1237
1238 if (outputFormat->mOutputMode == OutputHandler::NEEDS_DIR) {
1239 const size_t len = outputPath.size();
1240 if (outputPath[len - 1] != '/') {
1241 outputPath += "/";
1242 }
1243 }
1244 break;
Andreas Huberb82318c2016-08-02 14:45:54 -07001245 }
Andreas Huber019d21d2016-10-03 12:59:47 -07001246
1247 default:
1248 outputPath.clear(); // Unused.
1249 break;
Andreas Huberb82318c2016-08-02 14:45:54 -07001250 }
1251
Andreas Huberdca261f2016-08-04 13:47:51 -07001252 Coordinator coordinator(packageRootPaths, packageRoots);
Andreas Huber5345ec22016-07-29 13:33:27 -07001253
Andreas Huber737080b2016-08-02 15:38:04 -07001254 for (int i = 0; i < argc; ++i) {
Andreas Huber68f24592016-07-29 14:53:48 -07001255 FQName fqName(argv[i]);
Andreas Huber68f24592016-07-29 14:53:48 -07001256
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001257 if (!fqName.isValid()) {
Andreas Hubere61e3f72016-08-03 10:22:03 -07001258 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -07001259 "ERROR: Invalid fully-qualified name.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001260 exit(1);
1261 }
Andreas Huber881227d2016-08-02 14:20:21 -07001262
Andreas Huber0fa9e392016-08-31 09:05:44 -07001263 OutputHandler::ValRes valid =
1264 outputFormat->validate(fqName, outputFormat->mKey);
1265
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001266 if (valid == OutputHandler::FAILED) {
Andreas Hubere61e3f72016-08-03 10:22:03 -07001267 exit(1);
1268 }
Andreas Huberd2943e12016-08-05 11:59:31 -07001269
1270 status_t err =
Andreas Huber019d21d2016-10-03 12:59:47 -07001271 outputFormat->generate(fqName, me, &coordinator, outputPath);
Andreas Huberd2943e12016-08-05 11:59:31 -07001272
1273 if (err != OK) {
Steven Moreland261370a2016-08-29 15:36:59 -07001274 exit(1);
Andreas Huberd2943e12016-08-05 11:59:31 -07001275 }
Andreas Hubereb1081f2016-07-28 13:13:24 -07001276 }
Andreas Huberc9410c72016-07-28 12:18:40 -07001277
Andreas Huberd2943e12016-08-05 11:59:31 -07001278 return 0;
Andreas Huberc9410c72016-07-28 12:18:40 -07001279}