blob: ae7f6a87876106575c6dc37276726dfd96608c62 [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
Andreas Huber0fa9e392016-08-31 09:05:44 -0700128static void generateMakefileSectionForLanguageAndType(
129 Formatter &out,
130 Coordinator *coordinator,
131 const FQName &packageFQName,
132 const FQName &fqName,
133 const char *typeName,
134 bool forJava) {
135 out << "\n"
136 << "\n#"
137 << "\n# Build " << fqName.name() << ".hal";
138
139 if (forJava && typeName != nullptr) {
140 out << " (" << typeName << ")";
141 }
142
143 out << "\n#"
144 << "\nGEN := $(intermediates)/"
145 << coordinator->convertPackageRootToPath(packageFQName)
146 << coordinator->getPackagePath(packageFQName, true /* relative */);
147 if (!forJava) {
148 CHECK(typeName == nullptr);
149
150 if (fqName.name() == "types") {
151 out << "types.cpp";
152 } else {
153 out << fqName.name().substr(1) << "All.cpp";
154 }
155 } else if (typeName == nullptr) {
156 out << fqName.name() << ".java";
157 } else {
158 out << typeName << ".java";
159 }
160
161 out << "\n$(GEN): $(HIDL)";
162 out << "\n$(GEN): PRIVATE_HIDL := $(HIDL)";
163 out << "\n$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/"
164 << fqName.name() << ".hal";
Iliyan Malchevb9819132016-09-07 12:38:31 -0700165
166 {
167 AST *ast = coordinator->parse(fqName);
168 CHECK(ast != nullptr);
169 const std::set<FQName>& refs = ast->getImportedNames();
170 for (auto depFQName : refs) {
171 // If the package of depFQName is the same as this fqName's package,
172 // then add it explicitly as a .hal dependency within the same
173 // package.
174 if (fqName.package() == depFQName.package() &&
175 fqName.version() == depFQName.version()) {
176 // PRIVATE_DEPS is not actually being used in the
177 // auto-generated file, but is necessary if the build rule
178 // ever needs to use the dependency information, since the
179 // built-in Make variables are not supported in the Android
180 // build system.
181 out << "\n$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/"
182 << depFQName.name() << ".hal";
183 // This is the actual dependency.
184 out << "\n$(GEN): $(LOCAL_PATH)/"
185 << depFQName.name() << ".hal";
186 }
187 }
188 }
189
Andreas Huber0fa9e392016-08-31 09:05:44 -0700190 out << "\n$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)"
191 << "\n$(GEN): PRIVATE_CUSTOM_TOOL = \\";
192 out.indent();
193 out.indent();
194 out << "\n$(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \\"
195 << "\n-L"
196 << (forJava ? "java" : "c++")
197 << " -r"
198 << coordinator->getPackageRoot(packageFQName) << ":"
199 << coordinator->getPackageRootPath(packageFQName) << " \\\n";
200
201 out << packageFQName.string()
202 << "::"
203 << fqName.name();
204
205 if (forJava && typeName != nullptr) {
206 out << "." << typeName;
207 }
208
209 out << "\n";
210
211 out.unindent();
212 out.unindent();
213
214 out << "\n$(GEN): $(LOCAL_PATH)/" << fqName.name() << ".hal";
215 out << "\n\t$(transform-generated-source)";
216 out << "\nLOCAL_GENERATED_SOURCES += $(GEN)";
217}
218
219static void generateMakefileSectionForLanguage(
220 Formatter &out,
221 Coordinator *coordinator,
222 const FQName &packageFQName,
223 const std::vector<FQName> &packageInterfaces,
224 AST *typesAST,
225 bool forJava) {
226 for (const auto &fqName : packageInterfaces) {
227 if (forJava && fqName.name() == "types") {
228 CHECK(typesAST != nullptr);
229
230 Scope *rootScope = typesAST->scope();
Andreas Huber0fa9e392016-08-31 09:05:44 -0700231
Andreas Huberb747bd92016-09-26 15:55:31 -0700232 std::vector<NamedType *> subTypes = rootScope->getSubTypes();
233 std::sort(
234 subTypes.begin(),
235 subTypes.end(),
236 [](const NamedType *a, const NamedType *b) -> bool {
237 return a->fqName() < b->fqName();
238 });
239
240 for (const auto &type : subTypes) {
Andreas Huberdda25cc2016-09-22 10:39:47 -0700241 if (type->isTypeDef()) {
242 continue;
243 }
244
Andreas Huber0fa9e392016-08-31 09:05:44 -0700245 generateMakefileSectionForLanguageAndType(
246 out,
247 coordinator,
248 packageFQName,
249 fqName,
Steven Morelandd537ab02016-09-12 10:32:01 -0700250 type->localName().c_str(),
Andreas Huber0fa9e392016-08-31 09:05:44 -0700251 forJava);
252 }
253
254 continue;
255 }
256
257 generateMakefileSectionForLanguageAndType(
258 out,
259 coordinator,
260 packageFQName,
261 fqName,
262 nullptr /* typeName */,
263 forJava);
264 }
265}
266
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700267static status_t generateMakefileForPackage(
268 const FQName &packageFQName,
Iliyan Malchevb66c3992016-08-07 21:18:13 -0700269 const char *hidl_gen,
Andreas Huberd2943e12016-08-05 11:59:31 -0700270 Coordinator *coordinator,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700271 const std::string &) {
272
273 CHECK(packageFQName.isValid() &&
274 !packageFQName.isFullyQualified() &&
275 packageFQName.name().empty());
276
Andreas Huberd2943e12016-08-05 11:59:31 -0700277 std::vector<FQName> packageInterfaces;
278
279 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700280 coordinator->appendPackageInterfacesToVector(packageFQName,
281 &packageInterfaces);
Andreas Huberd2943e12016-08-05 11:59:31 -0700282
283 if (err != OK) {
284 return err;
285 }
286
287 std::set<FQName> importedPackages;
Andreas Huber0fa9e392016-08-31 09:05:44 -0700288 bool packageIsJavaCompatible = true;
289 AST *typesAST = nullptr;
290
Andreas Huberd2943e12016-08-05 11:59:31 -0700291 for (const auto &fqName : packageInterfaces) {
292 AST *ast = coordinator->parse(fqName);
293
294 if (ast == NULL) {
295 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700296 "ERROR: Could not parse %s. Aborting.\n",
Andreas Huberd2943e12016-08-05 11:59:31 -0700297 fqName.string().c_str());
298
299 return UNKNOWN_ERROR;
300 }
301
Andreas Huber0fa9e392016-08-31 09:05:44 -0700302 if (packageIsJavaCompatible && !ast->isJavaCompatible()) {
303 packageIsJavaCompatible = false;
304 }
305
306 if (fqName.name() == "types") {
307 typesAST = ast;
308 }
309
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700310 ast->getImportedPackages(&importedPackages);
Andreas Huberd2943e12016-08-05 11:59:31 -0700311 }
312
313 std::string path =
314 coordinator->getPackagePath(packageFQName, false /* relative */);
315
316 path.append("Android.mk");
317
318 CHECK(Coordinator::MakeParentHierarchy(path));
319 FILE *file = fopen(path.c_str(), "w");
320
321 if (file == NULL) {
322 return -errno;
323 }
324
325 const std::string libraryName = makeLibraryName(packageFQName);
326
327 Formatter out(file);
328
329 out << "LOCAL_PATH := $(call my-dir)\n"
330 << "include $(CLEAR_VARS)\n\n"
331 << "LOCAL_MODULE := "
332 << libraryName
333 << "\n"
334 << "LOCAL_MODULE_CLASS := SHARED_LIBRARIES\n\n"
335 << "intermediates := $(local-generated-sources-dir)\n\n"
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700336 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
337 << hidl_gen << "$(HOST_EXECUTABLE_SUFFIX)";
Andreas Huberd2943e12016-08-05 11:59:31 -0700338
Andreas Huber0fa9e392016-08-31 09:05:44 -0700339 generateMakefileSectionForLanguage(
340 out,
341 coordinator,
342 packageFQName,
343 packageInterfaces,
344 typesAST,
345 false /* forJava */);
Andreas Huberd2943e12016-08-05 11:59:31 -0700346
Andreas Huberd2943e12016-08-05 11:59:31 -0700347 out << "\n"
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700348 << "\nLOCAL_EXPORT_C_INCLUDE_DIRS := $(intermediates)"
349 << "\nLOCAL_SHARED_LIBRARIES := \\";
350 out.indent();
Martijn Coenen7473fab2016-08-19 14:05:40 +0200351 out << "\nlibhidl \\"
352 << "\nlibhwbinder \\"
Zhuoyao Zhangde578002016-09-07 18:24:17 -0700353 << "\nlibutils \\"
354 << "\nlibcutils \\";
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700355
356 for (const auto &importedPackage : importedPackages) {
357 out << "\n" << makeLibraryName(importedPackage) << " \\";
358 }
359 out << "\n";
360 out.unindent();
Keun Soo Yimc2903d22016-08-26 18:56:22 -0700361 out << "\nLOCAL_MULTILIB := both";
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700362
363 out << "\ninclude $(BUILD_SHARED_LIBRARY)\n";
Andreas Huberd2943e12016-08-05 11:59:31 -0700364
Andreas Huber0fa9e392016-08-31 09:05:44 -0700365 if (packageIsJavaCompatible) {
Andreas Huber782d45e2016-09-22 13:25:14 -0700366 enum LibraryStyle {
367 LIBRARY_STYLE_REGULAR,
368 LIBRARY_STYLE_STATIC,
369 LIBRARY_STYLE_END,
370 };
Andreas Huber0fa9e392016-08-31 09:05:44 -0700371
Andreas Huber782d45e2016-09-22 13:25:14 -0700372 for (int style = LIBRARY_STYLE_REGULAR; style != LIBRARY_STYLE_END;
373 ++style) {
374 const std::string staticSuffix =
375 (style == LIBRARY_STYLE_STATIC) ? "-static" : "";
Andreas Huber0fa9e392016-08-31 09:05:44 -0700376
Iliyan Malchev800273d2016-09-02 15:25:07 -0700377 out << "\n"
Andreas Huber782d45e2016-09-22 13:25:14 -0700378 << "########################################"
379 << "########################################\n\n";
380
381 out << "include $(CLEAR_VARS)\n"
382 << "LOCAL_MODULE := "
383 << libraryName
384 << "-java"
385 << staticSuffix
386 << "\nLOCAL_MODULE_CLASS := JAVA_LIBRARIES\n\n"
387 << "intermediates := $(local-generated-sources-dir)\n\n"
388 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
389 << hidl_gen
390 << "$(HOST_EXECUTABLE_SUFFIX)";
391
392 if (!importedPackages.empty()) {
393 out << "\n"
394 << "\nLOCAL_"
395 << ((style == LIBRARY_STYLE_STATIC) ? "STATIC_" : "")
396 << "JAVA_LIBRARIES := \\";
397
398 out.indent();
399 for (const auto &importedPackage : importedPackages) {
400 out << "\n"
401 << makeLibraryName(importedPackage)
402 << "-java"
403 << staticSuffix
404 << " \\";
405 }
406 out << "\n";
407 out.unindent();
Iliyan Malchev800273d2016-09-02 15:25:07 -0700408 }
Andreas Huber782d45e2016-09-22 13:25:14 -0700409
410 generateMakefileSectionForLanguage(
411 out,
412 coordinator,
413 packageFQName,
414 packageInterfaces,
415 typesAST,
416 true /* forJava */);
417
418 out << "\ninclude $(BUILD_"
419 << ((style == LIBRARY_STYLE_STATIC) ? "STATIC_" : "")
420 << "JAVA_LIBRARY)\n\n";
Iliyan Malchev800273d2016-09-02 15:25:07 -0700421 }
Andreas Huber0fa9e392016-08-31 09:05:44 -0700422 }
423
Iliyan Malchev8be09552016-09-22 16:20:33 -0700424 out << "\n\n"
425 << "include $(call all-makefiles-under,$(LOCAL_PATH))\n";
426
Andreas Huberd2943e12016-08-05 11:59:31 -0700427 return OK;
428}
429
Andreas Huber0fa9e392016-08-31 09:05:44 -0700430OutputHandler::ValRes validateForMakefile(
431 const FQName &fqName, const std::string & /* language */) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700432 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700433 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700434 return OutputHandler::FAILED;
435 }
436
437 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700438 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700439 return OutputHandler::FAILED;
440 }
441
442 if (!fqName.name().empty()) {
443 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700444 "ERROR: Expecting only package name and version.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700445 return OutputHandler::FAILED;
446 }
447
448 return OutputHandler::PASS_PACKAGE;
449}
450
Steven Moreland197d56c2016-09-09 10:03:58 -0700451static status_t generateMakefileImplForPackage(
452 const FQName &packageFQName,
453 const char *,
454 Coordinator *coordinator,
455 const std::string &outputDir) {
456
Iliyan Malchev4923f932016-09-09 13:04:59 -0700457 const std::string libraryName = makeLibraryName(packageFQName) + "-impl";
Steven Moreland197d56c2016-09-09 10:03:58 -0700458
459 std::vector<FQName> packageInterfaces;
460
461 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700462 coordinator->appendPackageInterfacesToVector(packageFQName,
463 &packageInterfaces);
Steven Moreland197d56c2016-09-09 10:03:58 -0700464
465 if (err != OK) {
466 return err;
467 }
468
469 std::set<FQName> importedPackages;
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 ast->getImportedPackages(&importedPackages);
483 }
484
485 std::string path = outputDir + "Android.mk";
486
487 CHECK(Coordinator::MakeParentHierarchy(path));
488 FILE *file = fopen(path.c_str(), "w");
489
490 if (file == NULL) {
491 return -errno;
492 }
493
494 Formatter out(file);
495
496 out << "LOCAL_PATH := $(call my-dir)\n\n"
497 << "include $(CLEAR_VARS)\n"
498 << "LOCAL_MODULE := " << libraryName << "\n"
499 << "LOCAL_MODULE_RELATIVE_PATH := hw\n"
500 << "LOCAL_SRC_FILES := \\\n";
501 out.indent();
502 for (const auto &fqName : packageInterfaces) {
503 if (fqName.name() == "types") {
504 continue;
505 }
506 out << fqName.getInterfaceBaseName() << ".cpp \\\n";
507 }
508 out.unindent();
509 out << "\n";
510 out << "LOCAL_SHARED_LIBRARIES := \\\n";
511 out.indent();
512 out << "libhidl \\\n"
513 << "libhwbinder \\\n"
514 << "libutils \\\n"
515 << makeLibraryName(packageFQName) << " \\\n";
516 out.unindent();
517 out << "\n";
518
519 out << "include $(BUILD_SHARED_LIBRARY)\n";
520
521 return OK;
522}
523
Andreas Huber0fa9e392016-08-31 09:05:44 -0700524OutputHandler::ValRes validateForSource(
525 const FQName &fqName, const std::string &language) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700526 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700527 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700528 return OutputHandler::FAILED;
529 }
530
531 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700532 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700533 return OutputHandler::FAILED;
534 }
535
Andreas Huber0fa9e392016-08-31 09:05:44 -0700536 const std::string &name = fqName.name();
537 if (!name.empty()) {
538 if (name.find('.') == std::string::npos) {
539 return OutputHandler::PASS_FULL;
540 }
541
542 if (language != "java" || name.find("types.") != 0) {
543 // When generating java sources for "types.hal", output can be
544 // constrained to just one of the top-level types declared
545 // by using the extended syntax
546 // android.hardware.Foo@1.0::types.TopLevelTypeName.
547 // In all other cases (different language, not 'types') the dot
548 // notation in the name is illegal in this context.
549 return OutputHandler::FAILED;
550 }
551
552 return OutputHandler::PASS_FULL;
553 }
554
555 return OutputHandler::PASS_PACKAGE;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700556}
557
558static std::vector<OutputHandler> formats = {
559 {"c++",
Andreas Huber2831d512016-08-15 09:33:47 -0700560 true /* mNeedsOutputDir */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700561 validateForSource,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700562 [](const FQName &fqName,
563 const char *hidl_gen, Coordinator *coordinator,
564 const std::string &outputDir) -> status_t {
565 if (fqName.isFullyQualified()) {
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700566 return generateSourcesForFile(fqName,
567 hidl_gen,
568 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700569 outputDir,
570 "c++");
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700571 } else {
572 return generateSourcesForPackage(fqName,
573 hidl_gen,
574 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700575 outputDir,
576 "c++");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700577 }
578 }
579 },
580
Steven Moreland9c387612016-09-07 09:54:26 -0700581 {"c++-impl",
582 true /* mNeedsOutputDir */,
583 validateForSource,
584 [](const FQName &fqName,
585 const char *hidl_gen, Coordinator *coordinator,
586 const std::string &outputDir) -> status_t {
587 if (fqName.isFullyQualified()) {
588 return generateSourcesForFile(fqName,
589 hidl_gen,
590 coordinator,
591 outputDir, "c++-impl");
592 } else {
593 return generateSourcesForPackage(fqName,
594 hidl_gen,
595 coordinator,
596 outputDir, "c++-impl");
597 }
598 }
599 },
600
601
Andreas Huber2831d512016-08-15 09:33:47 -0700602 {"java",
603 true /* mNeedsOutputDir */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700604 validateForSource,
Andreas Huber2831d512016-08-15 09:33:47 -0700605 [](const FQName &fqName,
606 const char *hidl_gen, Coordinator *coordinator,
607 const std::string &outputDir) -> status_t {
608 if (fqName.isFullyQualified()) {
609 return generateSourcesForFile(fqName,
610 hidl_gen,
611 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700612 outputDir,
613 "java");
Andreas Huber2831d512016-08-15 09:33:47 -0700614 }
615 else {
616 return generateSourcesForPackage(fqName,
617 hidl_gen,
618 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700619 outputDir,
620 "java");
Andreas Huber2831d512016-08-15 09:33:47 -0700621 }
622 }
623 },
624
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700625 {"vts",
626 true,
627 validateForSource,
628 [](const FQName &fqName,
629 const char * hidl_gen,
630 Coordinator *coordinator,
631 const std::string &outputDir) -> status_t {
632 if (fqName.isFullyQualified()) {
633 return generateSourcesForFile(fqName,
634 hidl_gen,
635 coordinator,
636 outputDir, "vts");
637 } else {
638 return generateSourcesForPackage(fqName,
639 hidl_gen,
640 coordinator,
641 outputDir, "vts");
642 }
643 }
644 },
645
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700646 {"makefile",
Andreas Huber2831d512016-08-15 09:33:47 -0700647 false /* mNeedsOutputDir */,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700648 validateForMakefile,
649 generateMakefileForPackage,
650 },
Steven Moreland197d56c2016-09-09 10:03:58 -0700651
652 {"makefile-impl",
653 true /* mNeedsOutputDir */,
654 validateForMakefile,
655 generateMakefileImplForPackage,
656 }
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700657};
658
659static void usage(const char *me) {
660 fprintf(stderr,
661 "usage: %s -o output-path -L <language> (-r interface-root)+ fqname+\n",
662 me);
663
664 fprintf(stderr, " -o output path\n");
665
666 fprintf(stderr, " -L <language> (one of");
667 for (auto &e : formats) {
668 fprintf(stderr, " %s", e.mKey.c_str());
669 }
670 fprintf(stderr, ")\n");
671
672 fprintf(stderr,
673 " -r package:path root "
674 "(e.g., android.hardware:hardware/interfaces)\n");
675}
676
Andreas Huberb82318c2016-08-02 14:45:54 -0700677int main(int argc, char **argv) {
678 std::string outputDir;
Andreas Huberdca261f2016-08-04 13:47:51 -0700679 std::vector<std::string> packageRootPaths;
680 std::vector<std::string> packageRoots;
Andreas Huberb82318c2016-08-02 14:45:54 -0700681
Andreas Huber737080b2016-08-02 15:38:04 -0700682 const char *me = argv[0];
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700683 OutputHandler *outputFormat = nullptr;
Andreas Huber737080b2016-08-02 15:38:04 -0700684
Andreas Huberb82318c2016-08-02 14:45:54 -0700685 int res;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700686 while ((res = getopt(argc, argv, "ho:r:L:")) >= 0) {
Andreas Huberb82318c2016-08-02 14:45:54 -0700687 switch (res) {
688 case 'o':
689 {
690 outputDir = optarg;
691 break;
692 }
693
Andreas Huberdca261f2016-08-04 13:47:51 -0700694 case 'r':
695 {
696 std::string val(optarg);
697 auto index = val.find_first_of(':');
698 CHECK(index != std::string::npos);
699
700 auto package = val.substr(0, index);
701 auto path = val.substr(index + 1);
702 packageRootPaths.push_back(path);
703 packageRoots.push_back(package);
704 break;
705 }
706
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700707 case 'L':
708 {
709 CHECK(outputFormat == nullptr); // only one -L option
710 for (auto &e : formats) {
711 if (e.mKey == optarg) {
712 outputFormat = &e;
713 break;
714 }
715 }
716 CHECK(outputFormat != nullptr);
717 break;
718 }
719
Andreas Huberb82318c2016-08-02 14:45:54 -0700720 case '?':
721 case 'h':
722 default:
723 {
Andreas Huber737080b2016-08-02 15:38:04 -0700724 usage(me);
Andreas Huberb82318c2016-08-02 14:45:54 -0700725 exit(1);
726 break;
727 }
728 }
729 }
730
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700731 if (outputFormat == nullptr) {
732 usage(me);
733 exit(1);
734 }
735
Andreas Huberb82318c2016-08-02 14:45:54 -0700736 argc -= optind;
737 argv += optind;
738
Andreas Huberdca261f2016-08-04 13:47:51 -0700739 if (packageRootPaths.empty()) {
740 // Pick reasonable defaults.
741
742 packageRoots.push_back("android.hardware");
743
744 const char *TOP = getenv("TOP");
745 CHECK(TOP != NULL);
746
747 std::string path = TOP;
748 path.append("/hardware/interfaces");
749
750 packageRootPaths.push_back(path);
751 }
752
Andreas Huber737080b2016-08-02 15:38:04 -0700753 // Valid options are now in argv[0] .. argv[argc - 1].
754
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700755 if (!outputFormat->mNeedsOutputDir) {
Andreas Huberd2943e12016-08-05 11:59:31 -0700756 outputDir.clear(); // Unused.
757 } else if (outputDir.empty()) {
Andreas Huber737080b2016-08-02 15:38:04 -0700758 usage(me);
Andreas Huberb82318c2016-08-02 14:45:54 -0700759 exit(1);
760 } else {
761 const size_t len = outputDir.size();
762 if (outputDir[len - 1] != '/') {
763 outputDir += "/";
764 }
765 }
766
Andreas Huberdca261f2016-08-04 13:47:51 -0700767 Coordinator coordinator(packageRootPaths, packageRoots);
Andreas Huber5345ec22016-07-29 13:33:27 -0700768
Andreas Huber737080b2016-08-02 15:38:04 -0700769 for (int i = 0; i < argc; ++i) {
Andreas Huber68f24592016-07-29 14:53:48 -0700770 FQName fqName(argv[i]);
Andreas Huber68f24592016-07-29 14:53:48 -0700771
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700772 if (!fqName.isValid()) {
Andreas Hubere61e3f72016-08-03 10:22:03 -0700773 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700774 "ERROR: Invalid fully-qualified name.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700775 exit(1);
776 }
Andreas Huber881227d2016-08-02 14:20:21 -0700777
Andreas Huber0fa9e392016-08-31 09:05:44 -0700778 OutputHandler::ValRes valid =
779 outputFormat->validate(fqName, outputFormat->mKey);
780
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700781 if (valid == OutputHandler::FAILED) {
Andreas Hubere61e3f72016-08-03 10:22:03 -0700782 exit(1);
783 }
Andreas Huberd2943e12016-08-05 11:59:31 -0700784
785 status_t err =
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700786 outputFormat->generate(fqName, me, &coordinator, outputDir);
Andreas Huberd2943e12016-08-05 11:59:31 -0700787
788 if (err != OK) {
Steven Moreland261370a2016-08-29 15:36:59 -0700789 exit(1);
Andreas Huberd2943e12016-08-05 11:59:31 -0700790 }
Andreas Hubereb1081f2016-07-28 13:13:24 -0700791 }
Andreas Huberc9410c72016-07-28 12:18:40 -0700792
Andreas Huberd2943e12016-08-05 11:59:31 -0700793 return 0;
Andreas Huberc9410c72016-07-28 12:18:40 -0700794}