blob: 134cc6bdfc47c1e8ece6ecd3777edb6aacd02d9f [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 Huberd2943e12016-08-05 11:59:31 -070019#include "Formatter.h"
Andreas Huber84f89de2016-07-28 15:39:51 -070020#include "FQName.h"
Andreas Huber0fa9e392016-08-31 09:05:44 -070021#include "Scope.h"
Andreas Huberc9410c72016-07-28 12:18:40 -070022
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;
56 const char *limitToType = nullptr;
57
58 if (fqName.name().find("types.") == 0) {
59 CHECK(lang == "java"); // Already verified in validate().
60
61 limitToType = fqName.name().c_str() + strlen("types.");
62
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 =
106 coordinator->appendPackageInterfacesToSet(packageFQName,
107 &packageInterfaces);
108
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();
231 for (size_t i = 0; i < rootScope->countTypes(); ++i) {
232 std::string typeName;
233 rootScope->typeAt(i, &typeName);
234
235 generateMakefileSectionForLanguageAndType(
236 out,
237 coordinator,
238 packageFQName,
239 fqName,
240 typeName.c_str(),
241 forJava);
242 }
243
244 continue;
245 }
246
247 generateMakefileSectionForLanguageAndType(
248 out,
249 coordinator,
250 packageFQName,
251 fqName,
252 nullptr /* typeName */,
253 forJava);
254 }
255}
256
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700257static status_t generateMakefileForPackage(
258 const FQName &packageFQName,
Iliyan Malchevb66c3992016-08-07 21:18:13 -0700259 const char *hidl_gen,
Andreas Huberd2943e12016-08-05 11:59:31 -0700260 Coordinator *coordinator,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700261 const std::string &) {
262
263 CHECK(packageFQName.isValid() &&
264 !packageFQName.isFullyQualified() &&
265 packageFQName.name().empty());
266
Andreas Huberd2943e12016-08-05 11:59:31 -0700267 std::vector<FQName> packageInterfaces;
268
269 status_t err =
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700270 coordinator->appendPackageInterfacesToSet(packageFQName,
271 &packageInterfaces);
Andreas Huberd2943e12016-08-05 11:59:31 -0700272
273 if (err != OK) {
274 return err;
275 }
276
277 std::set<FQName> importedPackages;
Andreas Huber0fa9e392016-08-31 09:05:44 -0700278 bool packageIsJavaCompatible = true;
279 AST *typesAST = nullptr;
280
Andreas Huberd2943e12016-08-05 11:59:31 -0700281 for (const auto &fqName : packageInterfaces) {
282 AST *ast = coordinator->parse(fqName);
283
284 if (ast == NULL) {
285 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700286 "ERROR: Could not parse %s. Aborting.\n",
Andreas Huberd2943e12016-08-05 11:59:31 -0700287 fqName.string().c_str());
288
289 return UNKNOWN_ERROR;
290 }
291
Andreas Huber0fa9e392016-08-31 09:05:44 -0700292 if (packageIsJavaCompatible && !ast->isJavaCompatible()) {
293 packageIsJavaCompatible = false;
294 }
295
296 if (fqName.name() == "types") {
297 typesAST = ast;
298 }
299
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700300 ast->getImportedPackages(&importedPackages);
Andreas Huberd2943e12016-08-05 11:59:31 -0700301 }
302
303 std::string path =
304 coordinator->getPackagePath(packageFQName, false /* relative */);
305
306 path.append("Android.mk");
307
308 CHECK(Coordinator::MakeParentHierarchy(path));
309 FILE *file = fopen(path.c_str(), "w");
310
311 if (file == NULL) {
312 return -errno;
313 }
314
315 const std::string libraryName = makeLibraryName(packageFQName);
316
317 Formatter out(file);
318
319 out << "LOCAL_PATH := $(call my-dir)\n"
320 << "include $(CLEAR_VARS)\n\n"
321 << "LOCAL_MODULE := "
322 << libraryName
323 << "\n"
324 << "LOCAL_MODULE_CLASS := SHARED_LIBRARIES\n\n"
325 << "intermediates := $(local-generated-sources-dir)\n\n"
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700326 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
327 << hidl_gen << "$(HOST_EXECUTABLE_SUFFIX)";
Andreas Huberd2943e12016-08-05 11:59:31 -0700328
Andreas Huber0fa9e392016-08-31 09:05:44 -0700329 generateMakefileSectionForLanguage(
330 out,
331 coordinator,
332 packageFQName,
333 packageInterfaces,
334 typesAST,
335 false /* forJava */);
Andreas Huberd2943e12016-08-05 11:59:31 -0700336
Andreas Huberd2943e12016-08-05 11:59:31 -0700337 out << "\n"
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700338 << "\nLOCAL_EXPORT_C_INCLUDE_DIRS := $(intermediates)"
339 << "\nLOCAL_SHARED_LIBRARIES := \\";
340 out.indent();
Martijn Coenen7473fab2016-08-19 14:05:40 +0200341 out << "\nlibhidl \\"
342 << "\nlibhwbinder \\"
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700343 << "\nlibutils \\";
344
345 for (const auto &importedPackage : importedPackages) {
346 out << "\n" << makeLibraryName(importedPackage) << " \\";
347 }
348 out << "\n";
349 out.unindent();
Keun Soo Yimc2903d22016-08-26 18:56:22 -0700350 out << "\nLOCAL_MULTILIB := both";
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700351
352 out << "\ninclude $(BUILD_SHARED_LIBRARY)\n";
Andreas Huberd2943e12016-08-05 11:59:31 -0700353
Andreas Huber0fa9e392016-08-31 09:05:44 -0700354 if (packageIsJavaCompatible) {
355 out << "\n"
356 << "########################################"
357 << "########################################\n\n";
358
359 out << "include $(CLEAR_VARS)\n"
360 << "LOCAL_MODULE := "
361 << libraryName
362 << "-java\n"
363 << "LOCAL_MODULE_CLASS := JAVA_LIBRARIES\n\n"
364 << "intermediates := $(local-generated-sources-dir)\n\n"
365 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
366 << hidl_gen
367 << "$(HOST_EXECUTABLE_SUFFIX)";
368
Iliyan Malchev800273d2016-09-02 15:25:07 -0700369 if (!importedPackages.empty()) {
370 out << "\n"
371 << "\nLOCAL_JAVA_LIBRARIES := \\";
372 out.indent();
373 for (const auto &importedPackage : importedPackages) {
374 out << "\n" << makeLibraryName(importedPackage) << "-java \\";
375 }
376 out << "\n";
377 out.unindent();
378 }
379
Andreas Huber0fa9e392016-08-31 09:05:44 -0700380 generateMakefileSectionForLanguage(
381 out,
382 coordinator,
383 packageFQName,
384 packageInterfaces,
385 typesAST,
386 true /* forJava */);
387
388 out << "\ninclude $(BUILD_JAVA_LIBRARY)\n";
389 }
390
Andreas Huberd2943e12016-08-05 11:59:31 -0700391 return OK;
392}
393
Andreas Huber0fa9e392016-08-31 09:05:44 -0700394OutputHandler::ValRes validateForMakefile(
395 const FQName &fqName, const std::string & /* language */) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700396 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700397 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700398 return OutputHandler::FAILED;
399 }
400
401 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700402 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700403 return OutputHandler::FAILED;
404 }
405
406 if (!fqName.name().empty()) {
407 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700408 "ERROR: Expecting only package name and version.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700409 return OutputHandler::FAILED;
410 }
411
412 return OutputHandler::PASS_PACKAGE;
413}
414
Steven Moreland197d56c2016-09-09 10:03:58 -0700415static status_t generateMakefileImplForPackage(
416 const FQName &packageFQName,
417 const char *,
418 Coordinator *coordinator,
419 const std::string &outputDir) {
420
Iliyan Malchev4923f932016-09-09 13:04:59 -0700421 const std::string libraryName = makeLibraryName(packageFQName) + "-impl";
Steven Moreland197d56c2016-09-09 10:03:58 -0700422
423 std::vector<FQName> packageInterfaces;
424
425 status_t err =
426 coordinator->appendPackageInterfacesToSet(packageFQName,
427 &packageInterfaces);
428
429 if (err != OK) {
430 return err;
431 }
432
433 std::set<FQName> importedPackages;
434
435 for (const auto &fqName : packageInterfaces) {
436 AST *ast = coordinator->parse(fqName);
437
438 if (ast == NULL) {
439 fprintf(stderr,
440 "ERROR: Could not parse %s. Aborting.\n",
441 fqName.string().c_str());
442
443 return UNKNOWN_ERROR;
444 }
445
446 ast->getImportedPackages(&importedPackages);
447 }
448
449 std::string path = outputDir + "Android.mk";
450
451 CHECK(Coordinator::MakeParentHierarchy(path));
452 FILE *file = fopen(path.c_str(), "w");
453
454 if (file == NULL) {
455 return -errno;
456 }
457
458 Formatter out(file);
459
460 out << "LOCAL_PATH := $(call my-dir)\n\n"
461 << "include $(CLEAR_VARS)\n"
462 << "LOCAL_MODULE := " << libraryName << "\n"
463 << "LOCAL_MODULE_RELATIVE_PATH := hw\n"
464 << "LOCAL_SRC_FILES := \\\n";
465 out.indent();
466 for (const auto &fqName : packageInterfaces) {
467 if (fqName.name() == "types") {
468 continue;
469 }
470 out << fqName.getInterfaceBaseName() << ".cpp \\\n";
471 }
472 out.unindent();
473 out << "\n";
474 out << "LOCAL_SHARED_LIBRARIES := \\\n";
475 out.indent();
476 out << "libhidl \\\n"
477 << "libhwbinder \\\n"
478 << "libutils \\\n"
479 << makeLibraryName(packageFQName) << " \\\n";
480 out.unindent();
481 out << "\n";
482
483 out << "include $(BUILD_SHARED_LIBRARY)\n";
484
485 return OK;
486}
487
Andreas Huber0fa9e392016-08-31 09:05:44 -0700488OutputHandler::ValRes validateForSource(
489 const FQName &fqName, const std::string &language) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700490 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700491 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700492 return OutputHandler::FAILED;
493 }
494
495 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700496 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700497 return OutputHandler::FAILED;
498 }
499
Andreas Huber0fa9e392016-08-31 09:05:44 -0700500 const std::string &name = fqName.name();
501 if (!name.empty()) {
502 if (name.find('.') == std::string::npos) {
503 return OutputHandler::PASS_FULL;
504 }
505
506 if (language != "java" || name.find("types.") != 0) {
507 // When generating java sources for "types.hal", output can be
508 // constrained to just one of the top-level types declared
509 // by using the extended syntax
510 // android.hardware.Foo@1.0::types.TopLevelTypeName.
511 // In all other cases (different language, not 'types') the dot
512 // notation in the name is illegal in this context.
513 return OutputHandler::FAILED;
514 }
515
516 return OutputHandler::PASS_FULL;
517 }
518
519 return OutputHandler::PASS_PACKAGE;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700520}
521
522static std::vector<OutputHandler> formats = {
523 {"c++",
Andreas Huber2831d512016-08-15 09:33:47 -0700524 true /* mNeedsOutputDir */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700525 validateForSource,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700526 [](const FQName &fqName,
527 const char *hidl_gen, Coordinator *coordinator,
528 const std::string &outputDir) -> status_t {
529 if (fqName.isFullyQualified()) {
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700530 return generateSourcesForFile(fqName,
531 hidl_gen,
532 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700533 outputDir,
534 "c++");
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700535 } else {
536 return generateSourcesForPackage(fqName,
537 hidl_gen,
538 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700539 outputDir,
540 "c++");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700541 }
542 }
543 },
544
Steven Moreland9c387612016-09-07 09:54:26 -0700545 {"c++-impl",
546 true /* mNeedsOutputDir */,
547 validateForSource,
548 [](const FQName &fqName,
549 const char *hidl_gen, Coordinator *coordinator,
550 const std::string &outputDir) -> status_t {
551 if (fqName.isFullyQualified()) {
552 return generateSourcesForFile(fqName,
553 hidl_gen,
554 coordinator,
555 outputDir, "c++-impl");
556 } else {
557 return generateSourcesForPackage(fqName,
558 hidl_gen,
559 coordinator,
560 outputDir, "c++-impl");
561 }
562 }
563 },
564
565
Andreas Huber2831d512016-08-15 09:33:47 -0700566 {"java",
567 true /* mNeedsOutputDir */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700568 validateForSource,
Andreas Huber2831d512016-08-15 09:33:47 -0700569 [](const FQName &fqName,
570 const char *hidl_gen, Coordinator *coordinator,
571 const std::string &outputDir) -> status_t {
572 if (fqName.isFullyQualified()) {
573 return generateSourcesForFile(fqName,
574 hidl_gen,
575 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700576 outputDir,
577 "java");
Andreas Huber2831d512016-08-15 09:33:47 -0700578 }
579 else {
580 return generateSourcesForPackage(fqName,
581 hidl_gen,
582 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700583 outputDir,
584 "java");
Andreas Huber2831d512016-08-15 09:33:47 -0700585 }
586 }
587 },
588
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700589 {"vts",
590 true,
591 validateForSource,
592 [](const FQName &fqName,
593 const char * hidl_gen,
594 Coordinator *coordinator,
595 const std::string &outputDir) -> status_t {
596 if (fqName.isFullyQualified()) {
597 return generateSourcesForFile(fqName,
598 hidl_gen,
599 coordinator,
600 outputDir, "vts");
601 } else {
602 return generateSourcesForPackage(fqName,
603 hidl_gen,
604 coordinator,
605 outputDir, "vts");
606 }
607 }
608 },
609
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700610 {"makefile",
Andreas Huber2831d512016-08-15 09:33:47 -0700611 false /* mNeedsOutputDir */,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700612 validateForMakefile,
613 generateMakefileForPackage,
614 },
Steven Moreland197d56c2016-09-09 10:03:58 -0700615
616 {"makefile-impl",
617 true /* mNeedsOutputDir */,
618 validateForMakefile,
619 generateMakefileImplForPackage,
620 }
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700621};
622
623static void usage(const char *me) {
624 fprintf(stderr,
625 "usage: %s -o output-path -L <language> (-r interface-root)+ fqname+\n",
626 me);
627
628 fprintf(stderr, " -o output path\n");
629
630 fprintf(stderr, " -L <language> (one of");
631 for (auto &e : formats) {
632 fprintf(stderr, " %s", e.mKey.c_str());
633 }
634 fprintf(stderr, ")\n");
635
636 fprintf(stderr,
637 " -r package:path root "
638 "(e.g., android.hardware:hardware/interfaces)\n");
639}
640
Andreas Huberb82318c2016-08-02 14:45:54 -0700641int main(int argc, char **argv) {
642 std::string outputDir;
Andreas Huberdca261f2016-08-04 13:47:51 -0700643 std::vector<std::string> packageRootPaths;
644 std::vector<std::string> packageRoots;
Andreas Huberb82318c2016-08-02 14:45:54 -0700645
Andreas Huber737080b2016-08-02 15:38:04 -0700646 const char *me = argv[0];
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700647 OutputHandler *outputFormat = nullptr;
Andreas Huber737080b2016-08-02 15:38:04 -0700648
Andreas Huberb82318c2016-08-02 14:45:54 -0700649 int res;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700650 while ((res = getopt(argc, argv, "ho:r:L:")) >= 0) {
Andreas Huberb82318c2016-08-02 14:45:54 -0700651 switch (res) {
652 case 'o':
653 {
654 outputDir = optarg;
655 break;
656 }
657
Andreas Huberdca261f2016-08-04 13:47:51 -0700658 case 'r':
659 {
660 std::string val(optarg);
661 auto index = val.find_first_of(':');
662 CHECK(index != std::string::npos);
663
664 auto package = val.substr(0, index);
665 auto path = val.substr(index + 1);
666 packageRootPaths.push_back(path);
667 packageRoots.push_back(package);
668 break;
669 }
670
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700671 case 'L':
672 {
673 CHECK(outputFormat == nullptr); // only one -L option
674 for (auto &e : formats) {
675 if (e.mKey == optarg) {
676 outputFormat = &e;
677 break;
678 }
679 }
680 CHECK(outputFormat != nullptr);
681 break;
682 }
683
Andreas Huberb82318c2016-08-02 14:45:54 -0700684 case '?':
685 case 'h':
686 default:
687 {
Andreas Huber737080b2016-08-02 15:38:04 -0700688 usage(me);
Andreas Huberb82318c2016-08-02 14:45:54 -0700689 exit(1);
690 break;
691 }
692 }
693 }
694
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700695 if (outputFormat == nullptr) {
696 usage(me);
697 exit(1);
698 }
699
Andreas Huberb82318c2016-08-02 14:45:54 -0700700 argc -= optind;
701 argv += optind;
702
Andreas Huberdca261f2016-08-04 13:47:51 -0700703 if (packageRootPaths.empty()) {
704 // Pick reasonable defaults.
705
706 packageRoots.push_back("android.hardware");
707
708 const char *TOP = getenv("TOP");
709 CHECK(TOP != NULL);
710
711 std::string path = TOP;
712 path.append("/hardware/interfaces");
713
714 packageRootPaths.push_back(path);
715 }
716
Andreas Huber737080b2016-08-02 15:38:04 -0700717 // Valid options are now in argv[0] .. argv[argc - 1].
718
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700719 if (!outputFormat->mNeedsOutputDir) {
Andreas Huberd2943e12016-08-05 11:59:31 -0700720 outputDir.clear(); // Unused.
721 } else if (outputDir.empty()) {
Andreas Huber737080b2016-08-02 15:38:04 -0700722 usage(me);
Andreas Huberb82318c2016-08-02 14:45:54 -0700723 exit(1);
724 } else {
725 const size_t len = outputDir.size();
726 if (outputDir[len - 1] != '/') {
727 outputDir += "/";
728 }
729 }
730
Andreas Huberdca261f2016-08-04 13:47:51 -0700731 Coordinator coordinator(packageRootPaths, packageRoots);
Andreas Huber5345ec22016-07-29 13:33:27 -0700732
Andreas Huber737080b2016-08-02 15:38:04 -0700733 for (int i = 0; i < argc; ++i) {
Andreas Huber68f24592016-07-29 14:53:48 -0700734 FQName fqName(argv[i]);
Andreas Huber68f24592016-07-29 14:53:48 -0700735
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700736 if (!fqName.isValid()) {
Andreas Hubere61e3f72016-08-03 10:22:03 -0700737 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700738 "ERROR: Invalid fully-qualified name.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700739 exit(1);
740 }
Andreas Huber881227d2016-08-02 14:20:21 -0700741
Andreas Huber0fa9e392016-08-31 09:05:44 -0700742 OutputHandler::ValRes valid =
743 outputFormat->validate(fqName, outputFormat->mKey);
744
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700745 if (valid == OutputHandler::FAILED) {
Andreas Hubere61e3f72016-08-03 10:22:03 -0700746 exit(1);
747 }
Andreas Huberd2943e12016-08-05 11:59:31 -0700748
749 status_t err =
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700750 outputFormat->generate(fqName, me, &coordinator, outputDir);
Andreas Huberd2943e12016-08-05 11:59:31 -0700751
752 if (err != OK) {
Steven Moreland261370a2016-08-29 15:36:59 -0700753 exit(1);
Andreas Huberd2943e12016-08-05 11:59:31 -0700754 }
Andreas Hubereb1081f2016-07-28 13:13:24 -0700755 }
Andreas Huberc9410c72016-07-28 12:18:40 -0700756
Andreas Huberd2943e12016-08-05 11:59:31 -0700757 return 0;
Andreas Huberc9410c72016-07-28 12:18:40 -0700758}