blob: f36577828e1d93bdab4c8ded00e70340650facdc [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>
Steven Morelandd177b122016-12-12 09:15:37 -080023#include <hidl-util/StringHelper.h>
Andreas Huber68f24592016-07-29 14:53:48 -070024#include <android-base/logging.h>
Iliyan Malchev5bb14022016-08-09 15:04:39 -070025#include <set>
Andreas Huberc9410c72016-07-28 12:18:40 -070026#include <stdio.h>
Andreas Huberdca261f2016-08-04 13:47:51 -070027#include <string>
Andreas Huberb82318c2016-08-02 14:45:54 -070028#include <unistd.h>
Andreas Huberdca261f2016-08-04 13:47:51 -070029#include <vector>
Andreas Huberc9410c72016-07-28 12:18:40 -070030
31using namespace android;
32
Iliyan Malchev5bb14022016-08-09 15:04:39 -070033struct OutputHandler {
34 std::string mKey;
Andreas Huber019d21d2016-10-03 12:59:47 -070035 enum OutputMode {
36 NEEDS_DIR,
37 NEEDS_FILE,
38 NOT_NEEDED
39 } mOutputMode;
40
Iliyan Malchev5bb14022016-08-09 15:04:39 -070041 enum ValRes {
42 FAILED,
43 PASS_PACKAGE,
44 PASS_FULL
45 };
Andreas Huber0fa9e392016-08-31 09:05:44 -070046 ValRes (*validate)(const FQName &, const std::string &language);
Iliyan Malchev5bb14022016-08-09 15:04:39 -070047 status_t (*generate)(const FQName &fqName,
48 const char *hidl_gen,
49 Coordinator *coordinator,
50 const std::string &outputDir);
51};
Andreas Huberdca261f2016-08-04 13:47:51 -070052
Iliyan Malchev5bb14022016-08-09 15:04:39 -070053static status_t generateSourcesForFile(
54 const FQName &fqName,
55 const char *,
56 Coordinator *coordinator,
Andreas Huber2831d512016-08-15 09:33:47 -070057 const std::string &outputDir,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070058 const std::string &lang) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -070059 CHECK(fqName.isFullyQualified());
60
Andreas Huber0fa9e392016-08-31 09:05:44 -070061 AST *ast;
Andreas Huberd29724f2016-09-14 09:33:13 -070062 std::string limitToType;
Andreas Huber0fa9e392016-08-31 09:05:44 -070063
64 if (fqName.name().find("types.") == 0) {
65 CHECK(lang == "java"); // Already verified in validate().
66
Andreas Huberd29724f2016-09-14 09:33:13 -070067 limitToType = fqName.name().substr(strlen("types."));
Andreas Huber0fa9e392016-08-31 09:05:44 -070068
69 FQName typesName(fqName.package(), fqName.version(), "types");
70 ast = coordinator->parse(typesName);
71 } else {
72 ast = coordinator->parse(fqName);
73 }
Iliyan Malchev5bb14022016-08-09 15:04:39 -070074
75 if (ast == NULL) {
76 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -070077 "ERROR: Could not parse %s. Aborting.\n",
Iliyan Malchev5bb14022016-08-09 15:04:39 -070078 fqName.string().c_str());
79
80 return UNKNOWN_ERROR;
81 }
82
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070083 if (lang == "c++") {
84 return ast->generateCpp(outputDir);
85 }
Steven Moreland9c387612016-09-07 09:54:26 -070086 if (lang == "c++-impl") {
87 return ast->generateCppImpl(outputDir);
88 }
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070089 if (lang == "java") {
Andreas Huber0fa9e392016-08-31 09:05:44 -070090 return ast->generateJava(outputDir, limitToType);
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070091 }
92 if (lang == "vts") {
93 return ast->generateVts(outputDir);
94 }
95 // Unknown language.
96 return UNKNOWN_ERROR;
Iliyan Malchev5bb14022016-08-09 15:04:39 -070097}
98
99static status_t generateSourcesForPackage(
100 const FQName &packageFQName,
101 const char *hidl_gen,
102 Coordinator *coordinator,
Andreas Huber2831d512016-08-15 09:33:47 -0700103 const std::string &outputDir,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700104 const std::string &lang) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700105 CHECK(packageFQName.isValid() &&
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700106 !packageFQName.isFullyQualified() &&
107 packageFQName.name().empty());
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700108
109 std::vector<FQName> packageInterfaces;
110
111 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700112 coordinator->appendPackageInterfacesToVector(packageFQName,
113 &packageInterfaces);
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700114
115 if (err != OK) {
116 return err;
117 }
118
119 for (const auto &fqName : packageInterfaces) {
Andreas Huber2831d512016-08-15 09:33:47 -0700120 err = generateSourcesForFile(
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700121 fqName, hidl_gen, coordinator, outputDir, lang);
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700122 if (err != OK) {
123 return err;
124 }
125 }
126
127 return OK;
Andreas Huberb82318c2016-08-02 14:45:54 -0700128}
129
Andreas Huberd2943e12016-08-05 11:59:31 -0700130static std::string makeLibraryName(const FQName &packageFQName) {
Iliyan Malcheve2c595a2016-08-07 21:20:04 -0700131 return packageFQName.string();
Andreas Huberd2943e12016-08-05 11:59:31 -0700132}
133
Dan Willemsen676abdc2016-09-28 19:42:22 -0700134static void generateMakefileSectionForType(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700135 Formatter &out,
136 Coordinator *coordinator,
137 const FQName &packageFQName,
138 const FQName &fqName,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700139 const char *typeName) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700140 out << "\n"
141 << "\n#"
142 << "\n# Build " << fqName.name() << ".hal";
143
Dan Willemsen676abdc2016-09-28 19:42:22 -0700144 if (typeName != nullptr) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700145 out << " (" << typeName << ")";
146 }
147
148 out << "\n#"
149 << "\nGEN := $(intermediates)/"
150 << coordinator->convertPackageRootToPath(packageFQName)
151 << coordinator->getPackagePath(packageFQName, true /* relative */);
Dan Willemsen676abdc2016-09-28 19:42:22 -0700152 if (typeName == nullptr) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700153 out << fqName.name() << ".java";
154 } else {
155 out << typeName << ".java";
156 }
157
158 out << "\n$(GEN): $(HIDL)";
159 out << "\n$(GEN): PRIVATE_HIDL := $(HIDL)";
160 out << "\n$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/"
161 << fqName.name() << ".hal";
Iliyan Malchevb9819132016-09-07 12:38:31 -0700162
163 {
164 AST *ast = coordinator->parse(fqName);
165 CHECK(ast != nullptr);
166 const std::set<FQName>& refs = ast->getImportedNames();
167 for (auto depFQName : refs) {
168 // If the package of depFQName is the same as this fqName's package,
169 // then add it explicitly as a .hal dependency within the same
170 // package.
171 if (fqName.package() == depFQName.package() &&
172 fqName.version() == depFQName.version()) {
173 // PRIVATE_DEPS is not actually being used in the
174 // auto-generated file, but is necessary if the build rule
175 // ever needs to use the dependency information, since the
176 // built-in Make variables are not supported in the Android
177 // build system.
178 out << "\n$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/"
179 << depFQName.name() << ".hal";
180 // This is the actual dependency.
181 out << "\n$(GEN): $(LOCAL_PATH)/"
182 << depFQName.name() << ".hal";
183 }
184 }
185 }
186
Andreas Huber0fa9e392016-08-31 09:05:44 -0700187 out << "\n$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)"
188 << "\n$(GEN): PRIVATE_CUSTOM_TOOL = \\";
189 out.indent();
190 out.indent();
191 out << "\n$(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \\"
Yifan Hongc8934042016-11-17 17:10:52 -0800192 << "\n-Ljava \\"
193 << "\n-r"
194 << coordinator->getPackageRootOption(packageFQName) << " \\"
195 << "\n-r"
196 << coordinator->getPackageRootOption(gIBasePackageFqName) << " \\\n";
Andreas Huber0fa9e392016-08-31 09:05:44 -0700197
198 out << packageFQName.string()
199 << "::"
200 << fqName.name();
201
Dan Willemsen676abdc2016-09-28 19:42:22 -0700202 if (typeName != nullptr) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700203 out << "." << typeName;
204 }
205
206 out << "\n";
207
208 out.unindent();
209 out.unindent();
210
211 out << "\n$(GEN): $(LOCAL_PATH)/" << fqName.name() << ".hal";
212 out << "\n\t$(transform-generated-source)";
213 out << "\nLOCAL_GENERATED_SOURCES += $(GEN)";
214}
215
Dan Willemsen676abdc2016-09-28 19:42:22 -0700216static void generateMakefileSection(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700217 Formatter &out,
218 Coordinator *coordinator,
219 const FQName &packageFQName,
220 const std::vector<FQName> &packageInterfaces,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700221 AST *typesAST) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700222 for (const auto &fqName : packageInterfaces) {
Dan Willemsen676abdc2016-09-28 19:42:22 -0700223 if (fqName.name() == "types") {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700224 CHECK(typesAST != nullptr);
225
226 Scope *rootScope = typesAST->scope();
Andreas Huber0fa9e392016-08-31 09:05:44 -0700227
Andreas Huberb747bd92016-09-26 15:55:31 -0700228 std::vector<NamedType *> subTypes = rootScope->getSubTypes();
229 std::sort(
230 subTypes.begin(),
231 subTypes.end(),
232 [](const NamedType *a, const NamedType *b) -> bool {
233 return a->fqName() < b->fqName();
234 });
235
236 for (const auto &type : subTypes) {
Andreas Huberdda25cc2016-09-22 10:39:47 -0700237 if (type->isTypeDef()) {
238 continue;
239 }
240
Dan Willemsen676abdc2016-09-28 19:42:22 -0700241 generateMakefileSectionForType(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700242 out,
243 coordinator,
244 packageFQName,
245 fqName,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700246 type->localName().c_str());
Andreas Huber0fa9e392016-08-31 09:05:44 -0700247 }
248
249 continue;
250 }
251
Dan Willemsen676abdc2016-09-28 19:42:22 -0700252 generateMakefileSectionForType(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700253 out,
254 coordinator,
255 packageFQName,
256 fqName,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700257 nullptr /* typeName */);
Andreas Huber0fa9e392016-08-31 09:05:44 -0700258 }
259}
260
Andreas Huber75ae95d2016-10-12 16:08:26 -0700261static status_t isPackageJavaCompatible(
262 const FQName &packageFQName,
263 Coordinator *coordinator,
264 bool *compatible) {
265 std::vector<FQName> todo;
266 status_t err =
267 coordinator->appendPackageInterfacesToVector(packageFQName, &todo);
268
269 if (err != OK) {
270 return err;
271 }
272
273 std::set<FQName> seen;
274 for (const auto &iface : todo) {
275 seen.insert(iface);
276 }
277
278 // Form the transitive closure of all imported interfaces (and types.hal-s)
279 // If any one of them is not java compatible, this package isn't either.
280 while (!todo.empty()) {
281 const FQName fqName = todo.back();
282 todo.pop_back();
283
284 AST *ast = coordinator->parse(fqName);
285
286 if (ast == nullptr) {
287 return UNKNOWN_ERROR;
288 }
289
290 if (!ast->isJavaCompatible()) {
291 *compatible = false;
292 return OK;
293 }
294
295 std::set<FQName> importedPackages;
296 ast->getImportedPackages(&importedPackages);
297
298 for (const auto &package : importedPackages) {
299 std::vector<FQName> packageInterfaces;
300 status_t err = coordinator->appendPackageInterfacesToVector(
301 package, &packageInterfaces);
302
303 if (err != OK) {
304 return err;
305 }
306
307 for (const auto &iface : packageInterfaces) {
308 if (seen.find(iface) != seen.end()) {
309 continue;
310 }
311
312 todo.push_back(iface);
313 seen.insert(iface);
314 }
315 }
316 }
317
318 *compatible = true;
319 return OK;
320}
321
Andreas Huber5a9fe2c2016-10-13 15:31:10 -0700322static bool packageNeedsJavaCode(
323 const std::vector<FQName> &packageInterfaces, AST *typesAST) {
324 // If there is more than just a types.hal file to this package we'll
325 // definitely need to generate Java code.
326 if (packageInterfaces.size() > 1
327 || packageInterfaces[0].name() != "types") {
328 return true;
329 }
330
331 CHECK(typesAST != nullptr);
332
333 // We'll have to generate Java code if types.hal contains any non-typedef
334 // type declarations.
335
336 Scope *rootScope = typesAST->scope();
337 std::vector<NamedType *> subTypes = rootScope->getSubTypes();
338
339 for (const auto &subType : subTypes) {
340 if (!subType->isTypeDef()) {
341 return true;
342 }
343 }
344
345 return false;
346}
347
Andreas Huber1c507272016-10-05 14:33:21 -0700348static void generateMakefileSectionForJavaConstants(
349 Formatter &out,
350 Coordinator *coordinator,
351 const FQName &packageFQName,
352 const std::vector<FQName> &packageInterfaces) {
353 out << "\n#"
354 << "\nGEN := $(intermediates)/"
355 << coordinator->convertPackageRootToPath(packageFQName)
356 << coordinator->getPackagePath(packageFQName, true /* relative */)
357 << "Constants.java";
358
359 out << "\n$(GEN): $(HIDL)\n";
360 for (const auto &iface : packageInterfaces) {
361 out << "$(GEN): $(LOCAL_PATH)/" << iface.name() << ".hal\n";
362 }
363 out << "\n$(GEN): PRIVATE_HIDL := $(HIDL)";
364 out << "\n$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)"
365 << "\n$(GEN): PRIVATE_CUSTOM_TOOL = \\";
366 out.indent();
367 out.indent();
368 out << "\n$(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \\"
Yifan Hongc8934042016-11-17 17:10:52 -0800369 << "\n-Ljava-constants \\"
370 << "\n-r"
371 << coordinator->getPackageRootOption(packageFQName) << " \\"
372 << "\n-r"
373 << coordinator->getPackageRootOption(gIBasePackageFqName) << " \\\n";
Andreas Huber1c507272016-10-05 14:33:21 -0700374
375 out << packageFQName.string();
376 out << "\n";
377
378 out.unindent();
379 out.unindent();
380
381 out << "\n$(GEN):";
382 out << "\n\t$(transform-generated-source)";
383 out << "\nLOCAL_GENERATED_SOURCES += $(GEN)";
384}
385
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700386static status_t generateMakefileForPackage(
387 const FQName &packageFQName,
Iliyan Malchevb66c3992016-08-07 21:18:13 -0700388 const char *hidl_gen,
Andreas Huberd2943e12016-08-05 11:59:31 -0700389 Coordinator *coordinator,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700390 const std::string &) {
391
392 CHECK(packageFQName.isValid() &&
393 !packageFQName.isFullyQualified() &&
394 packageFQName.name().empty());
395
Andreas Huberd2943e12016-08-05 11:59:31 -0700396 std::vector<FQName> packageInterfaces;
397
398 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700399 coordinator->appendPackageInterfacesToVector(packageFQName,
400 &packageInterfaces);
Andreas Huberd2943e12016-08-05 11:59:31 -0700401
402 if (err != OK) {
403 return err;
404 }
405
406 std::set<FQName> importedPackages;
Andreas Huber0fa9e392016-08-31 09:05:44 -0700407 AST *typesAST = nullptr;
Andreas Huber1c507272016-10-05 14:33:21 -0700408 std::vector<const Type *> exportedTypes;
Andreas Huber0fa9e392016-08-31 09:05:44 -0700409
Andreas Huberd2943e12016-08-05 11:59:31 -0700410 for (const auto &fqName : packageInterfaces) {
411 AST *ast = coordinator->parse(fqName);
412
413 if (ast == NULL) {
414 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700415 "ERROR: Could not parse %s. Aborting.\n",
Andreas Huberd2943e12016-08-05 11:59:31 -0700416 fqName.string().c_str());
417
418 return UNKNOWN_ERROR;
419 }
420
Andreas Huber0fa9e392016-08-31 09:05:44 -0700421 if (fqName.name() == "types") {
422 typesAST = ast;
423 }
424
Yifan Hong40a373d2016-11-30 15:16:47 -0800425 ast->getImportedPackagesHierarchy(&importedPackages);
Andreas Huber1c507272016-10-05 14:33:21 -0700426 ast->appendToExportedTypesVector(&exportedTypes);
Andreas Huberd2943e12016-08-05 11:59:31 -0700427 }
428
Andreas Huber75ae95d2016-10-12 16:08:26 -0700429 bool packageIsJavaCompatible;
430 err = isPackageJavaCompatible(
431 packageFQName, coordinator, &packageIsJavaCompatible);
432
433 if (err != OK) {
434 return err;
435 }
436
Andreas Huber1c507272016-10-05 14:33:21 -0700437 bool haveJavaConstants = !exportedTypes.empty();
438
439 if (!packageIsJavaCompatible && !haveJavaConstants) {
Steven Moreland81979932016-12-07 15:11:06 -0800440 // TODO(b/33420795)
441 fprintf(stderr,
442 "WARNING: %s is not java compatible. No java makefile created.\n",
443 packageFQName.string().c_str());
Dan Willemsen676abdc2016-09-28 19:42:22 -0700444 return OK;
445 }
446
Andreas Huber5a9fe2c2016-10-13 15:31:10 -0700447 if (!packageNeedsJavaCode(packageInterfaces, typesAST)) {
448 return OK;
449 }
450
Andreas Huberd2943e12016-08-05 11:59:31 -0700451 std::string path =
452 coordinator->getPackagePath(packageFQName, false /* relative */);
453
454 path.append("Android.mk");
455
456 CHECK(Coordinator::MakeParentHierarchy(path));
457 FILE *file = fopen(path.c_str(), "w");
458
459 if (file == NULL) {
460 return -errno;
461 }
462
463 const std::string libraryName = makeLibraryName(packageFQName);
464
465 Formatter out(file);
466
Dan Willemsen676abdc2016-09-28 19:42:22 -0700467 out << "# This file is autogenerated by hidl-gen. Do not edit manually.\n\n";
468 out << "LOCAL_PATH := $(call my-dir)\n";
Andreas Huberd2943e12016-08-05 11:59:31 -0700469
Dan Willemsen676abdc2016-09-28 19:42:22 -0700470 enum LibraryStyle {
471 LIBRARY_STYLE_REGULAR,
472 LIBRARY_STYLE_STATIC,
473 LIBRARY_STYLE_END,
474 };
Andreas Huberd2943e12016-08-05 11:59:31 -0700475
Andreas Huber1c507272016-10-05 14:33:21 -0700476 for (int style = LIBRARY_STYLE_REGULAR;
477 (packageIsJavaCompatible && style != LIBRARY_STYLE_END);
Dan Willemsen676abdc2016-09-28 19:42:22 -0700478 ++style) {
479 const std::string staticSuffix =
480 (style == LIBRARY_STYLE_STATIC) ? "-static" : "";
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700481
Dan Willemsen676abdc2016-09-28 19:42:22 -0700482 out << "\n"
483 << "########################################"
484 << "########################################\n\n";
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700485
Dan Willemsen676abdc2016-09-28 19:42:22 -0700486 out << "include $(CLEAR_VARS)\n"
487 << "LOCAL_MODULE := "
488 << libraryName
489 << "-java"
490 << staticSuffix
491 << "\nLOCAL_MODULE_CLASS := JAVA_LIBRARIES\n\n"
492 << "intermediates := $(local-generated-sources-dir)\n\n"
493 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
494 << hidl_gen
495 << "$(HOST_EXECUTABLE_SUFFIX)";
Andreas Huberd2943e12016-08-05 11:59:31 -0700496
Dan Willemsen676abdc2016-09-28 19:42:22 -0700497 if (!importedPackages.empty()) {
Iliyan Malchev800273d2016-09-02 15:25:07 -0700498 out << "\n"
Dan Willemsen676abdc2016-09-28 19:42:22 -0700499 << "\nLOCAL_"
Andreas Huber782d45e2016-09-22 13:25:14 -0700500 << ((style == LIBRARY_STYLE_STATIC) ? "STATIC_" : "")
Dan Willemsen676abdc2016-09-28 19:42:22 -0700501 << "JAVA_LIBRARIES := \\";
502
503 out.indent();
504 for (const auto &importedPackage : importedPackages) {
505 out << "\n"
506 << makeLibraryName(importedPackage)
507 << "-java"
508 << staticSuffix
509 << " \\";
510 }
511 out << "\n";
512 out.unindent();
Iliyan Malchev800273d2016-09-02 15:25:07 -0700513 }
Dan Willemsen676abdc2016-09-28 19:42:22 -0700514
515 generateMakefileSection(
516 out,
517 coordinator,
518 packageFQName,
519 packageInterfaces,
520 typesAST);
521
522 out << "\ninclude $(BUILD_"
523 << ((style == LIBRARY_STYLE_STATIC) ? "STATIC_" : "")
524 << "JAVA_LIBRARY)\n\n";
Andreas Huber0fa9e392016-08-31 09:05:44 -0700525 }
526
Andreas Huber1c507272016-10-05 14:33:21 -0700527 if (haveJavaConstants) {
528 out << "\n"
529 << "########################################"
530 << "########################################\n\n";
531
532 out << "include $(CLEAR_VARS)\n"
533 << "LOCAL_MODULE := "
534 << libraryName
535 << "-java-constants"
536 << "\nLOCAL_MODULE_CLASS := JAVA_LIBRARIES\n\n"
537 << "intermediates := $(local-generated-sources-dir)\n\n"
538 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
539 << hidl_gen
540 << "$(HOST_EXECUTABLE_SUFFIX)";
541
542 generateMakefileSectionForJavaConstants(
543 out, coordinator, packageFQName, packageInterfaces);
544
545 out << "\n# Avoid dependency cycle of framework.jar -> this-library "
546 << "-> framework.jar\n"
547 << "LOCAL_NO_STANDARD_LIBRARIES := true\n"
548 << "LOCAL_JAVA_LIBRARIES := core-oj\n\n"
549 << "include $(BUILD_STATIC_JAVA_LIBRARY)\n\n";
550 }
551
Iliyan Malchev8be09552016-09-22 16:20:33 -0700552 out << "\n\n"
553 << "include $(call all-makefiles-under,$(LOCAL_PATH))\n";
554
Andreas Huberd2943e12016-08-05 11:59:31 -0700555 return OK;
556}
557
Andreas Huber0fa9e392016-08-31 09:05:44 -0700558OutputHandler::ValRes validateForMakefile(
559 const FQName &fqName, const std::string & /* language */) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700560 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700561 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700562 return OutputHandler::FAILED;
563 }
564
565 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700566 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700567 return OutputHandler::FAILED;
568 }
569
570 if (!fqName.name().empty()) {
571 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700572 "ERROR: Expecting only package name and version.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700573 return OutputHandler::FAILED;
574 }
575
576 return OutputHandler::PASS_PACKAGE;
577}
578
Dan Willemsen676abdc2016-09-28 19:42:22 -0700579static void generateAndroidBpGenSection(
580 Formatter &out,
581 const FQName &packageFQName,
582 const char *hidl_gen,
583 Coordinator *coordinator,
584 const std::string &genName,
585 const char *language,
586 const std::vector<FQName> &packageInterfaces,
587 const std::function<void(Formatter&, const FQName)> outputFn) {
588
589 out << "genrule {\n";
590 out.indent();
591 out << "name: \"" << genName << "\",\n"
Colin Crossd5419bd2016-11-04 15:05:54 -0700592 << "tools: [\"" << hidl_gen << "\"],\n";
Dan Willemsen676abdc2016-09-28 19:42:22 -0700593
Colin Crossd5419bd2016-11-04 15:05:54 -0700594 out << "cmd: \"$(location " << hidl_gen << ") -o $(genDir)"
Dan Willemsen676abdc2016-09-28 19:42:22 -0700595 << " -L" << language
596 << " -r"
Yifan Hongc8934042016-11-17 17:10:52 -0800597 << coordinator->getPackageRootOption(packageFQName)
598 << " -r"
599 << coordinator->getPackageRootOption(gIBasePackageFqName)
Dan Willemsen676abdc2016-09-28 19:42:22 -0700600 << " " << packageFQName.string() << "\",\n";
601
602 out << "srcs: [\n";
603 out.indent();
604 for (const auto &fqName : packageInterfaces) {
605 out << "\"" << fqName.name() << ".hal\",\n";
606 }
607 out.unindent();
608 out << "],\n";
609
610 out << "out: [\n";
611 out.indent();
612 for (const auto &fqName : packageInterfaces) {
613 outputFn(out, fqName);
614 }
615 out.unindent();
616 out << "],\n";
617
618 out.unindent();
619 out << "}\n\n";
620}
621
622static status_t generateAndroidBpForPackage(
623 const FQName &packageFQName,
624 const char *hidl_gen,
625 Coordinator *coordinator,
626 const std::string &) {
627
628 CHECK(packageFQName.isValid() &&
629 !packageFQName.isFullyQualified() &&
630 packageFQName.name().empty());
631
632 std::vector<FQName> packageInterfaces;
633
634 status_t err =
635 coordinator->appendPackageInterfacesToVector(packageFQName,
636 &packageInterfaces);
637
638 if (err != OK) {
639 return err;
640 }
641
642 std::set<FQName> importedPackages;
643 AST *typesAST = nullptr;
644
645 for (const auto &fqName : packageInterfaces) {
646 AST *ast = coordinator->parse(fqName);
647
648 if (ast == NULL) {
649 fprintf(stderr,
650 "ERROR: Could not parse %s. Aborting.\n",
651 fqName.string().c_str());
652
653 return UNKNOWN_ERROR;
654 }
655
656 if (fqName.name() == "types") {
657 typesAST = ast;
658 }
659
660 ast->getImportedPackages(&importedPackages);
661 }
662
663 std::string path =
664 coordinator->getPackagePath(packageFQName, false /* relative */);
665
666 path.append("Android.bp");
667
668 CHECK(Coordinator::MakeParentHierarchy(path));
669 FILE *file = fopen(path.c_str(), "w");
670
671 if (file == NULL) {
672 return -errno;
673 }
674
675 const std::string libraryName = makeLibraryName(packageFQName);
676 const std::string genSourceName = libraryName + "_genc++";
677 const std::string genHeaderName = libraryName + "_genc++_headers";
678 const std::string pathPrefix =
679 coordinator->convertPackageRootToPath(packageFQName) +
680 coordinator->getPackagePath(packageFQName, true /* relative */);
681
682 Formatter out(file);
683
684 out << "// This file is autogenerated by hidl-gen. Do not edit manually.\n\n";
685
686 // Rule to generate the C++ source files
687 generateAndroidBpGenSection(
688 out,
689 packageFQName,
690 hidl_gen,
691 coordinator,
692 genSourceName,
693 "c++",
694 packageInterfaces,
695 [&pathPrefix](Formatter &out, const FQName &fqName) {
696 if (fqName.name() == "types") {
697 out << "\"" << pathPrefix << "types.cpp\",\n";
698 } else {
699 out << "\"" << pathPrefix << fqName.name().substr(1) << "All.cpp\",\n";
700 }
701 });
702
703 // Rule to generate the C++ header files
704 generateAndroidBpGenSection(
705 out,
706 packageFQName,
707 hidl_gen,
708 coordinator,
709 genHeaderName,
710 "c++",
711 packageInterfaces,
712 [&pathPrefix](Formatter &out, const FQName &fqName) {
713 out << "\"" << pathPrefix << fqName.name() << ".h\",\n";
714 if (fqName.name() != "types") {
715 out << "\"" << pathPrefix << "IHw" << fqName.name().substr(1) << ".h\",\n";
716 out << "\"" << pathPrefix << "Bn" << fqName.name().substr(1) << ".h\",\n";
717 out << "\"" << pathPrefix << "Bp" << fqName.name().substr(1) << ".h\",\n";
718 out << "\"" << pathPrefix << "Bs" << fqName.name().substr(1) << ".h\",\n";
719 }
720 });
721
722 // C++ library definition
723 out << "cc_library_shared {\n";
724 out.indent();
725 out << "name: \"" << libraryName << "\",\n"
726 << "generated_sources: [\"" << genSourceName << "\"],\n"
727 << "generated_headers: [\"" << genHeaderName << "\"],\n"
728 << "export_generated_headers: [\"" << genHeaderName << "\"],\n"
729 << "shared_libs: [\n";
730
731 out.indent();
Yifan Honga5abe922016-11-16 14:18:37 -0800732 out << "\"libhidlbase\",\n"
733 << "\"libhidltransport\",\n"
Dan Willemsen676abdc2016-09-28 19:42:22 -0700734 << "\"libhwbinder\",\n"
Steven Moreland05cd4232016-11-21 16:01:12 -0800735 << "\"liblog\",\n"
Dan Willemsen676abdc2016-09-28 19:42:22 -0700736 << "\"libutils\",\n"
737 << "\"libcutils\",\n";
738 for (const auto &importedPackage : importedPackages) {
739 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
740 }
741 out.unindent();
742
743 out << "],\n";
Steven Morelandb8a26c02016-10-21 13:40:14 -0700744
745 out << "export_shared_lib_headers: [\n";
746 out.indent();
Yifan Honga5abe922016-11-16 14:18:37 -0800747 out << "\"libhidlbase\",\n"
748 << "\"libhidltransport\",\n"
Steven Morelandb8a26c02016-10-21 13:40:14 -0700749 << "\"libhwbinder\",\n"
Steven Moreland865243c2016-11-01 13:05:24 -0700750 << "\"libutils\",\n";
Yifan Hongc1f9b8d2016-11-07 14:35:44 -0800751 for (const auto &importedPackage : importedPackages) {
752 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
753 }
Steven Moreland865243c2016-11-01 13:05:24 -0700754 out.unindent();
755 out << "],\n";
Steven Morelandb8a26c02016-10-21 13:40:14 -0700756 out.unindent();
757
Dan Willemsen676abdc2016-09-28 19:42:22 -0700758 out << "}\n";
759
760 return OK;
761}
762
Yifan Hong958ee462016-12-06 17:09:51 -0800763static status_t generateAndroidBpImplForPackage(
Steven Moreland197d56c2016-09-09 10:03:58 -0700764 const FQName &packageFQName,
765 const char *,
766 Coordinator *coordinator,
767 const std::string &outputDir) {
768
Iliyan Malchev4923f932016-09-09 13:04:59 -0700769 const std::string libraryName = makeLibraryName(packageFQName) + "-impl";
Steven Moreland197d56c2016-09-09 10:03:58 -0700770
771 std::vector<FQName> packageInterfaces;
772
773 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700774 coordinator->appendPackageInterfacesToVector(packageFQName,
775 &packageInterfaces);
Steven Moreland197d56c2016-09-09 10:03:58 -0700776
777 if (err != OK) {
778 return err;
779 }
780
781 std::set<FQName> importedPackages;
782
783 for (const auto &fqName : packageInterfaces) {
784 AST *ast = coordinator->parse(fqName);
785
786 if (ast == NULL) {
787 fprintf(stderr,
788 "ERROR: Could not parse %s. Aborting.\n",
789 fqName.string().c_str());
790
791 return UNKNOWN_ERROR;
792 }
793
794 ast->getImportedPackages(&importedPackages);
795 }
796
797 std::string path = outputDir + "Android.mk";
798
799 CHECK(Coordinator::MakeParentHierarchy(path));
800 FILE *file = fopen(path.c_str(), "w");
801
802 if (file == NULL) {
803 return -errno;
804 }
805
806 Formatter out(file);
807
Yifan Hong958ee462016-12-06 17:09:51 -0800808 out << "cc_library_shared {\n";
809 out.indentBlock([&] {
810 out << "name: \"" << libraryName << "\",\n"
811 << "relative_install_path: \"hw\",\n"
812 << "srcs: [\n";
813 out.indentBlock([&] {
814 for (const auto &fqName : packageInterfaces) {
815 if (fqName.name() == "types") {
816 continue;
817 }
818 out << "\"" << fqName.getInterfaceBaseName() << ".cpp\",\n";
819 }
820 });
821 out << "],\n"
822 << "shared_libs: [\n";
823 out.indentBlock([&] {
824 out << "\"libhidlbase\",\n"
825 << "\"libhidltransport\",\n"
826 << "\"libhwbinder\",\n"
827 << "\"libutils\",\n"
828 << "\"" << makeLibraryName(packageFQName) << "\",\n";
Yifan Honge0f7d692016-10-20 17:51:33 -0700829
Yifan Hong958ee462016-12-06 17:09:51 -0800830 for (const auto &importedPackage : importedPackages) {
831 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
832 }
833 });
834 out << "],\n";
835 });
836 out << "}\n";
Steven Moreland197d56c2016-09-09 10:03:58 -0700837
838 return OK;
839}
840
Andreas Huber0fa9e392016-08-31 09:05:44 -0700841OutputHandler::ValRes validateForSource(
842 const FQName &fqName, const std::string &language) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700843 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700844 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700845 return OutputHandler::FAILED;
846 }
847
848 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700849 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700850 return OutputHandler::FAILED;
851 }
852
Andreas Huber0fa9e392016-08-31 09:05:44 -0700853 const std::string &name = fqName.name();
854 if (!name.empty()) {
855 if (name.find('.') == std::string::npos) {
856 return OutputHandler::PASS_FULL;
857 }
858
859 if (language != "java" || name.find("types.") != 0) {
860 // When generating java sources for "types.hal", output can be
861 // constrained to just one of the top-level types declared
862 // by using the extended syntax
863 // android.hardware.Foo@1.0::types.TopLevelTypeName.
864 // In all other cases (different language, not 'types') the dot
865 // notation in the name is illegal in this context.
866 return OutputHandler::FAILED;
867 }
868
869 return OutputHandler::PASS_FULL;
870 }
871
872 return OutputHandler::PASS_PACKAGE;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700873}
874
Andreas Huber019d21d2016-10-03 12:59:47 -0700875OutputHandler::ValRes validateForExportHeader(
876 const FQName &fqName, const std::string & /* language */) {
877 if (fqName.package().empty()) {
878 fprintf(stderr, "ERROR: Expecting package name\n");
879 return OutputHandler::FAILED;
880 }
881
882 if (fqName.version().empty()) {
883 fprintf(stderr, "ERROR: Expecting package version\n");
884 return OutputHandler::FAILED;
885 }
886
887 if (!fqName.name().empty()) {
888 fprintf(stderr,
889 "ERROR: Expecting only package name and version.\n");
890 return OutputHandler::FAILED;
891 }
892
893 return OutputHandler::PASS_PACKAGE;
894}
895
896
897static status_t generateExportHeaderForPackage(
898 const FQName &packageFQName,
899 const char * /* hidl_gen */,
900 Coordinator *coordinator,
Andreas Huber1c507272016-10-05 14:33:21 -0700901 const std::string &outputPath,
902 bool forJava) {
Andreas Huber019d21d2016-10-03 12:59:47 -0700903
904 CHECK(packageFQName.isValid()
905 && !packageFQName.isFullyQualified()
906 && packageFQName.name().empty());
907
908 std::vector<FQName> packageInterfaces;
909
910 status_t err = coordinator->appendPackageInterfacesToVector(
911 packageFQName, &packageInterfaces);
912
913 if (err != OK) {
914 return err;
915 }
916
917 std::vector<const Type *> exportedTypes;
918
919 for (const auto &fqName : packageInterfaces) {
920 AST *ast = coordinator->parse(fqName);
921
922 if (ast == NULL) {
923 fprintf(stderr,
924 "ERROR: Could not parse %s. Aborting.\n",
925 fqName.string().c_str());
926
927 return UNKNOWN_ERROR;
928 }
929
930 ast->appendToExportedTypesVector(&exportedTypes);
931 }
932
933 if (exportedTypes.empty()) {
934 return OK;
935 }
936
Andreas Huber1c507272016-10-05 14:33:21 -0700937 std::string path = outputPath;
938
939 if (forJava) {
940 path.append(coordinator->convertPackageRootToPath(packageFQName));
941
942 path.append(coordinator->getPackagePath(
943 packageFQName, true /* relative */));
944
945 path.append("Constants.java");
946 }
947
948 CHECK(Coordinator::MakeParentHierarchy(path));
949 FILE *file = fopen(path.c_str(), "w");
Andreas Huber019d21d2016-10-03 12:59:47 -0700950
951 if (file == nullptr) {
952 return -errno;
953 }
954
955 Formatter out(file);
956
Steven Morelandd177b122016-12-12 09:15:37 -0800957 out << "// This file is autogenerated by hidl-gen. Do not edit manually.\n"
958 << "// Source: " << packageFQName.string() << "\n\n";
Andreas Huber019d21d2016-10-03 12:59:47 -0700959
Andreas Huber1c507272016-10-05 14:33:21 -0700960 std::string guard;
961 if (forJava) {
962 out << "package " << packageFQName.javaPackage() << ";\n\n";
963 out << "public class Constants {\n";
964 out.indent();
965 } else {
966 guard = "HIDL_GENERATED_";
Steven Morelandd177b122016-12-12 09:15:37 -0800967 guard += StringHelper::Uppercase(packageFQName.tokenName());
Andreas Huber1c507272016-10-05 14:33:21 -0700968 guard += "_";
969 guard += "EXPORTED_CONSTANTS_H_";
Andreas Huber019d21d2016-10-03 12:59:47 -0700970
Andreas Huber1c507272016-10-05 14:33:21 -0700971 out << "#ifndef "
972 << guard
973 << "\n#define "
974 << guard
975 << "\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n";
Andreas Huber019d21d2016-10-03 12:59:47 -0700976 }
977
Andreas Huber1c507272016-10-05 14:33:21 -0700978 for (const auto &type : exportedTypes) {
979 type->emitExportedHeader(out, forJava);
980 }
981
982 if (forJava) {
983 out.unindent();
984 out << "}\n";
985 } else {
986 out << "#ifdef __cplusplus\n}\n#endif\n\n#endif // "
987 << guard
988 << "\n";
989 }
Andreas Huber019d21d2016-10-03 12:59:47 -0700990
991 return OK;
992}
993
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700994static std::vector<OutputHandler> formats = {
995 {"c++",
Andreas Huber019d21d2016-10-03 12:59:47 -0700996 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700997 validateForSource,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700998 [](const FQName &fqName,
999 const char *hidl_gen, Coordinator *coordinator,
1000 const std::string &outputDir) -> status_t {
1001 if (fqName.isFullyQualified()) {
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001002 return generateSourcesForFile(fqName,
1003 hidl_gen,
1004 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -07001005 outputDir,
1006 "c++");
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001007 } else {
1008 return generateSourcesForPackage(fqName,
1009 hidl_gen,
1010 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -07001011 outputDir,
1012 "c++");
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001013 }
1014 }
1015 },
1016
Andreas Huber019d21d2016-10-03 12:59:47 -07001017 {"export-header",
1018 OutputHandler::NEEDS_FILE /* mOutputMode */,
1019 validateForExportHeader,
1020 [](const FQName &fqName,
1021 const char *hidl_gen,
1022 Coordinator *coordinator,
1023 const std::string &outputPath) -> status_t {
1024 CHECK(!fqName.isFullyQualified());
1025
1026 return generateExportHeaderForPackage(
1027 fqName,
1028 hidl_gen,
1029 coordinator,
Andreas Huber1c507272016-10-05 14:33:21 -07001030 outputPath,
1031 false /* forJava */);
Andreas Huber019d21d2016-10-03 12:59:47 -07001032 }
1033 },
1034
Steven Moreland9c387612016-09-07 09:54:26 -07001035 {"c++-impl",
Andreas Huber019d21d2016-10-03 12:59:47 -07001036 OutputHandler::NEEDS_DIR /* mOutputMode */,
Steven Moreland9c387612016-09-07 09:54:26 -07001037 validateForSource,
1038 [](const FQName &fqName,
1039 const char *hidl_gen, Coordinator *coordinator,
1040 const std::string &outputDir) -> status_t {
1041 if (fqName.isFullyQualified()) {
1042 return generateSourcesForFile(fqName,
1043 hidl_gen,
1044 coordinator,
1045 outputDir, "c++-impl");
1046 } else {
1047 return generateSourcesForPackage(fqName,
1048 hidl_gen,
1049 coordinator,
1050 outputDir, "c++-impl");
1051 }
1052 }
1053 },
1054
1055
Andreas Huber2831d512016-08-15 09:33:47 -07001056 {"java",
Andreas Huber019d21d2016-10-03 12:59:47 -07001057 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001058 validateForSource,
Andreas Huber2831d512016-08-15 09:33:47 -07001059 [](const FQName &fqName,
1060 const char *hidl_gen, Coordinator *coordinator,
1061 const std::string &outputDir) -> status_t {
1062 if (fqName.isFullyQualified()) {
1063 return generateSourcesForFile(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 else {
1070 return generateSourcesForPackage(fqName,
1071 hidl_gen,
1072 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -07001073 outputDir,
1074 "java");
Andreas Huber2831d512016-08-15 09:33:47 -07001075 }
1076 }
1077 },
1078
Andreas Huber1c507272016-10-05 14:33:21 -07001079 {"java-constants",
1080 OutputHandler::NEEDS_DIR /* mOutputMode */,
1081 validateForExportHeader,
1082 [](const FQName &fqName,
1083 const char *hidl_gen, Coordinator *coordinator,
1084 const std::string &outputDir) -> status_t {
1085 CHECK(!fqName.isFullyQualified());
1086 return generateExportHeaderForPackage(
1087 fqName,
1088 hidl_gen,
1089 coordinator,
1090 outputDir,
1091 true /* forJava */);
1092 }
1093 },
1094
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001095 {"vts",
Andreas Huber019d21d2016-10-03 12:59:47 -07001096 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -07001097 validateForSource,
1098 [](const FQName &fqName,
1099 const char * hidl_gen,
1100 Coordinator *coordinator,
1101 const std::string &outputDir) -> status_t {
1102 if (fqName.isFullyQualified()) {
1103 return generateSourcesForFile(fqName,
1104 hidl_gen,
1105 coordinator,
1106 outputDir, "vts");
1107 } else {
1108 return generateSourcesForPackage(fqName,
1109 hidl_gen,
1110 coordinator,
1111 outputDir, "vts");
1112 }
1113 }
1114 },
1115
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001116 {"makefile",
Andreas Huber019d21d2016-10-03 12:59:47 -07001117 OutputHandler::NOT_NEEDED /* mOutputMode */,
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001118 validateForMakefile,
1119 generateMakefileForPackage,
1120 },
Steven Moreland197d56c2016-09-09 10:03:58 -07001121
Dan Willemsen676abdc2016-09-28 19:42:22 -07001122 {"androidbp",
Andreas Huber019d21d2016-10-03 12:59:47 -07001123 OutputHandler::NOT_NEEDED /* mOutputMode */,
Dan Willemsen676abdc2016-09-28 19:42:22 -07001124 validateForMakefile,
1125 generateAndroidBpForPackage,
1126 },
1127
Yifan Hong958ee462016-12-06 17:09:51 -08001128 {"androidbp-impl",
Yifan Hong94bcea02016-10-06 13:51:31 -07001129 OutputHandler::NEEDS_DIR /* mOutputMode */,
Steven Moreland197d56c2016-09-09 10:03:58 -07001130 validateForMakefile,
Yifan Hong958ee462016-12-06 17:09:51 -08001131 generateAndroidBpImplForPackage,
Steven Moreland197d56c2016-09-09 10:03:58 -07001132 }
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001133};
1134
1135static void usage(const char *me) {
1136 fprintf(stderr,
1137 "usage: %s -o output-path -L <language> (-r interface-root)+ fqname+\n",
1138 me);
1139
1140 fprintf(stderr, " -o output path\n");
1141
1142 fprintf(stderr, " -L <language> (one of");
1143 for (auto &e : formats) {
1144 fprintf(stderr, " %s", e.mKey.c_str());
1145 }
1146 fprintf(stderr, ")\n");
1147
1148 fprintf(stderr,
1149 " -r package:path root "
1150 "(e.g., android.hardware:hardware/interfaces)\n");
1151}
1152
Andreas Huberb82318c2016-08-02 14:45:54 -07001153int main(int argc, char **argv) {
Andreas Huber019d21d2016-10-03 12:59:47 -07001154 std::string outputPath;
Andreas Huberdca261f2016-08-04 13:47:51 -07001155 std::vector<std::string> packageRootPaths;
1156 std::vector<std::string> packageRoots;
Andreas Huberb82318c2016-08-02 14:45:54 -07001157
Andreas Huber737080b2016-08-02 15:38:04 -07001158 const char *me = argv[0];
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001159 OutputHandler *outputFormat = nullptr;
Andreas Huber737080b2016-08-02 15:38:04 -07001160
Andreas Huberb82318c2016-08-02 14:45:54 -07001161 int res;
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001162 while ((res = getopt(argc, argv, "ho:r:L:")) >= 0) {
Andreas Huberb82318c2016-08-02 14:45:54 -07001163 switch (res) {
1164 case 'o':
1165 {
Andreas Huber019d21d2016-10-03 12:59:47 -07001166 outputPath = optarg;
Andreas Huberb82318c2016-08-02 14:45:54 -07001167 break;
1168 }
1169
Andreas Huberdca261f2016-08-04 13:47:51 -07001170 case 'r':
1171 {
1172 std::string val(optarg);
1173 auto index = val.find_first_of(':');
1174 CHECK(index != std::string::npos);
1175
1176 auto package = val.substr(0, index);
1177 auto path = val.substr(index + 1);
1178 packageRootPaths.push_back(path);
1179 packageRoots.push_back(package);
1180 break;
1181 }
1182
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001183 case 'L':
1184 {
Steven Morelande429a262016-11-15 09:54:32 -08001185 CHECK(outputFormat == nullptr) << "Only one -L option allowed.";
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001186 for (auto &e : formats) {
1187 if (e.mKey == optarg) {
1188 outputFormat = &e;
1189 break;
1190 }
1191 }
Steven Morelande429a262016-11-15 09:54:32 -08001192 CHECK(outputFormat != nullptr) << "Output format not recognized.";
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001193 break;
1194 }
1195
Andreas Huberb82318c2016-08-02 14:45:54 -07001196 case '?':
1197 case 'h':
1198 default:
1199 {
Andreas Huber737080b2016-08-02 15:38:04 -07001200 usage(me);
Andreas Huberb82318c2016-08-02 14:45:54 -07001201 exit(1);
1202 break;
1203 }
1204 }
1205 }
1206
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001207 if (outputFormat == nullptr) {
1208 usage(me);
1209 exit(1);
1210 }
1211
Andreas Huberb82318c2016-08-02 14:45:54 -07001212 argc -= optind;
1213 argv += optind;
1214
Andreas Huberdca261f2016-08-04 13:47:51 -07001215 if (packageRootPaths.empty()) {
1216 // Pick reasonable defaults.
1217
1218 packageRoots.push_back("android.hardware");
1219
1220 const char *TOP = getenv("TOP");
Steven Morelandaf330382016-11-09 15:48:03 -08001221 if (TOP == nullptr) {
1222 fprintf(stderr,
1223 "ERROR: No root path (-r) specified"
1224 " and $TOP environment variable not set.\n");
1225 exit(1);
1226 }
Andreas Huberdca261f2016-08-04 13:47:51 -07001227
1228 std::string path = TOP;
1229 path.append("/hardware/interfaces");
1230
1231 packageRootPaths.push_back(path);
1232 }
1233
Andreas Huber737080b2016-08-02 15:38:04 -07001234 // Valid options are now in argv[0] .. argv[argc - 1].
1235
Andreas Huber019d21d2016-10-03 12:59:47 -07001236 switch (outputFormat->mOutputMode) {
1237 case OutputHandler::NEEDS_DIR:
1238 case OutputHandler::NEEDS_FILE:
1239 {
1240 if (outputPath.empty()) {
1241 usage(me);
1242 exit(1);
1243 }
1244
1245 if (outputFormat->mOutputMode == OutputHandler::NEEDS_DIR) {
1246 const size_t len = outputPath.size();
1247 if (outputPath[len - 1] != '/') {
1248 outputPath += "/";
1249 }
1250 }
1251 break;
Andreas Huberb82318c2016-08-02 14:45:54 -07001252 }
Andreas Huber019d21d2016-10-03 12:59:47 -07001253
1254 default:
1255 outputPath.clear(); // Unused.
1256 break;
Andreas Huberb82318c2016-08-02 14:45:54 -07001257 }
1258
Andreas Huberdca261f2016-08-04 13:47:51 -07001259 Coordinator coordinator(packageRootPaths, packageRoots);
Andreas Huber5345ec22016-07-29 13:33:27 -07001260
Andreas Huber737080b2016-08-02 15:38:04 -07001261 for (int i = 0; i < argc; ++i) {
Andreas Huber68f24592016-07-29 14:53:48 -07001262 FQName fqName(argv[i]);
Andreas Huber68f24592016-07-29 14:53:48 -07001263
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001264 if (!fqName.isValid()) {
Andreas Hubere61e3f72016-08-03 10:22:03 -07001265 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -07001266 "ERROR: Invalid fully-qualified name.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001267 exit(1);
1268 }
Andreas Huber881227d2016-08-02 14:20:21 -07001269
Andreas Huber0fa9e392016-08-31 09:05:44 -07001270 OutputHandler::ValRes valid =
1271 outputFormat->validate(fqName, outputFormat->mKey);
1272
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001273 if (valid == OutputHandler::FAILED) {
Andreas Hubere61e3f72016-08-03 10:22:03 -07001274 exit(1);
1275 }
Andreas Huberd2943e12016-08-05 11:59:31 -07001276
1277 status_t err =
Andreas Huber019d21d2016-10-03 12:59:47 -07001278 outputFormat->generate(fqName, me, &coordinator, outputPath);
Andreas Huberd2943e12016-08-05 11:59:31 -07001279
1280 if (err != OK) {
Steven Moreland261370a2016-08-29 15:36:59 -07001281 exit(1);
Andreas Huberd2943e12016-08-05 11:59:31 -07001282 }
Andreas Hubereb1081f2016-07-28 13:13:24 -07001283 }
Andreas Huberc9410c72016-07-28 12:18:40 -07001284
Andreas Huberd2943e12016-08-05 11:59:31 -07001285 return 0;
Andreas Huberc9410c72016-07-28 12:18:40 -07001286}