blob: 6f0f248894b34c524a0f67f6ca4cfbb3c2f6ea2d [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 }
80 if (lang == "java") {
Andreas Huber0fa9e392016-08-31 09:05:44 -070081 return ast->generateJava(outputDir, limitToType);
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070082 }
83 if (lang == "vts") {
84 return ast->generateVts(outputDir);
85 }
86 // Unknown language.
87 return UNKNOWN_ERROR;
Iliyan Malchev5bb14022016-08-09 15:04:39 -070088}
89
90static status_t generateSourcesForPackage(
91 const FQName &packageFQName,
92 const char *hidl_gen,
93 Coordinator *coordinator,
Andreas Huber2831d512016-08-15 09:33:47 -070094 const std::string &outputDir,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070095 const std::string &lang) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -070096 CHECK(packageFQName.isValid() &&
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070097 !packageFQName.isFullyQualified() &&
98 packageFQName.name().empty());
Iliyan Malchev5bb14022016-08-09 15:04:39 -070099
100 std::vector<FQName> packageInterfaces;
101
102 status_t err =
103 coordinator->appendPackageInterfacesToSet(packageFQName,
104 &packageInterfaces);
105
106 if (err != OK) {
107 return err;
108 }
109
110 for (const auto &fqName : packageInterfaces) {
Andreas Huber2831d512016-08-15 09:33:47 -0700111 err = generateSourcesForFile(
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700112 fqName, hidl_gen, coordinator, outputDir, lang);
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700113 if (err != OK) {
114 return err;
115 }
116 }
117
118 return OK;
Andreas Huberb82318c2016-08-02 14:45:54 -0700119}
120
Andreas Huberd2943e12016-08-05 11:59:31 -0700121static std::string makeLibraryName(const FQName &packageFQName) {
Iliyan Malcheve2c595a2016-08-07 21:20:04 -0700122 return packageFQName.string();
Andreas Huberd2943e12016-08-05 11:59:31 -0700123}
124
Andreas Huber0fa9e392016-08-31 09:05:44 -0700125static void generateMakefileSectionForLanguageAndType(
126 Formatter &out,
127 Coordinator *coordinator,
128 const FQName &packageFQName,
129 const FQName &fqName,
130 const char *typeName,
131 bool forJava) {
132 out << "\n"
133 << "\n#"
134 << "\n# Build " << fqName.name() << ".hal";
135
136 if (forJava && typeName != nullptr) {
137 out << " (" << typeName << ")";
138 }
139
140 out << "\n#"
141 << "\nGEN := $(intermediates)/"
142 << coordinator->convertPackageRootToPath(packageFQName)
143 << coordinator->getPackagePath(packageFQName, true /* relative */);
144 if (!forJava) {
145 CHECK(typeName == nullptr);
146
147 if (fqName.name() == "types") {
148 out << "types.cpp";
149 } else {
150 out << fqName.name().substr(1) << "All.cpp";
151 }
152 } else if (typeName == nullptr) {
153 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";
162 out << "\n$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)"
163 << "\n$(GEN): PRIVATE_CUSTOM_TOOL = \\";
164 out.indent();
165 out.indent();
166 out << "\n$(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \\"
167 << "\n-L"
168 << (forJava ? "java" : "c++")
169 << " -r"
170 << coordinator->getPackageRoot(packageFQName) << ":"
171 << coordinator->getPackageRootPath(packageFQName) << " \\\n";
172
173 out << packageFQName.string()
174 << "::"
175 << fqName.name();
176
177 if (forJava && typeName != nullptr) {
178 out << "." << typeName;
179 }
180
181 out << "\n";
182
183 out.unindent();
184 out.unindent();
185
186 out << "\n$(GEN): $(LOCAL_PATH)/" << fqName.name() << ".hal";
187 out << "\n\t$(transform-generated-source)";
188 out << "\nLOCAL_GENERATED_SOURCES += $(GEN)";
189}
190
191static void generateMakefileSectionForLanguage(
192 Formatter &out,
193 Coordinator *coordinator,
194 const FQName &packageFQName,
195 const std::vector<FQName> &packageInterfaces,
196 AST *typesAST,
197 bool forJava) {
198 for (const auto &fqName : packageInterfaces) {
199 if (forJava && fqName.name() == "types") {
200 CHECK(typesAST != nullptr);
201
202 Scope *rootScope = typesAST->scope();
203 for (size_t i = 0; i < rootScope->countTypes(); ++i) {
204 std::string typeName;
205 rootScope->typeAt(i, &typeName);
206
207 generateMakefileSectionForLanguageAndType(
208 out,
209 coordinator,
210 packageFQName,
211 fqName,
212 typeName.c_str(),
213 forJava);
214 }
215
216 continue;
217 }
218
219 generateMakefileSectionForLanguageAndType(
220 out,
221 coordinator,
222 packageFQName,
223 fqName,
224 nullptr /* typeName */,
225 forJava);
226 }
227}
228
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700229static status_t generateMakefileForPackage(
230 const FQName &packageFQName,
Iliyan Malchevb66c3992016-08-07 21:18:13 -0700231 const char *hidl_gen,
Andreas Huberd2943e12016-08-05 11:59:31 -0700232 Coordinator *coordinator,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700233 const std::string &) {
234
235 CHECK(packageFQName.isValid() &&
236 !packageFQName.isFullyQualified() &&
237 packageFQName.name().empty());
238
Andreas Huberd2943e12016-08-05 11:59:31 -0700239 std::vector<FQName> packageInterfaces;
240
241 status_t err =
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700242 coordinator->appendPackageInterfacesToSet(packageFQName,
243 &packageInterfaces);
Andreas Huberd2943e12016-08-05 11:59:31 -0700244
245 if (err != OK) {
246 return err;
247 }
248
249 std::set<FQName> importedPackages;
Andreas Huber0fa9e392016-08-31 09:05:44 -0700250 bool packageIsJavaCompatible = true;
251 AST *typesAST = nullptr;
252
Andreas Huberd2943e12016-08-05 11:59:31 -0700253 for (const auto &fqName : packageInterfaces) {
254 AST *ast = coordinator->parse(fqName);
255
256 if (ast == NULL) {
257 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700258 "ERROR: Could not parse %s. Aborting.\n",
Andreas Huberd2943e12016-08-05 11:59:31 -0700259 fqName.string().c_str());
260
261 return UNKNOWN_ERROR;
262 }
263
Andreas Huber0fa9e392016-08-31 09:05:44 -0700264 if (packageIsJavaCompatible && !ast->isJavaCompatible()) {
265 packageIsJavaCompatible = false;
266 }
267
268 if (fqName.name() == "types") {
269 typesAST = ast;
270 }
271
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700272 ast->getImportedPackages(&importedPackages);
Andreas Huberd2943e12016-08-05 11:59:31 -0700273 }
274
275 std::string path =
276 coordinator->getPackagePath(packageFQName, false /* relative */);
277
278 path.append("Android.mk");
279
280 CHECK(Coordinator::MakeParentHierarchy(path));
281 FILE *file = fopen(path.c_str(), "w");
282
283 if (file == NULL) {
284 return -errno;
285 }
286
287 const std::string libraryName = makeLibraryName(packageFQName);
288
289 Formatter out(file);
290
291 out << "LOCAL_PATH := $(call my-dir)\n"
292 << "include $(CLEAR_VARS)\n\n"
293 << "LOCAL_MODULE := "
294 << libraryName
295 << "\n"
296 << "LOCAL_MODULE_CLASS := SHARED_LIBRARIES\n\n"
297 << "intermediates := $(local-generated-sources-dir)\n\n"
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700298 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
299 << hidl_gen << "$(HOST_EXECUTABLE_SUFFIX)";
Andreas Huberd2943e12016-08-05 11:59:31 -0700300
Andreas Huber0fa9e392016-08-31 09:05:44 -0700301 generateMakefileSectionForLanguage(
302 out,
303 coordinator,
304 packageFQName,
305 packageInterfaces,
306 typesAST,
307 false /* forJava */);
Andreas Huberd2943e12016-08-05 11:59:31 -0700308
Andreas Huberd2943e12016-08-05 11:59:31 -0700309 out << "\n"
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700310 << "\nLOCAL_EXPORT_C_INCLUDE_DIRS := $(intermediates)"
311 << "\nLOCAL_SHARED_LIBRARIES := \\";
312 out.indent();
Martijn Coenen7473fab2016-08-19 14:05:40 +0200313 out << "\nlibhidl \\"
314 << "\nlibhwbinder \\"
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700315 << "\nlibutils \\";
316
317 for (const auto &importedPackage : importedPackages) {
318 out << "\n" << makeLibraryName(importedPackage) << " \\";
319 }
320 out << "\n";
321 out.unindent();
Keun Soo Yimc2903d22016-08-26 18:56:22 -0700322 out << "\nLOCAL_MULTILIB := both";
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700323
324 out << "\ninclude $(BUILD_SHARED_LIBRARY)\n";
Andreas Huberd2943e12016-08-05 11:59:31 -0700325
Andreas Huber0fa9e392016-08-31 09:05:44 -0700326 if (packageIsJavaCompatible) {
327 out << "\n"
328 << "########################################"
329 << "########################################\n\n";
330
331 out << "include $(CLEAR_VARS)\n"
332 << "LOCAL_MODULE := "
333 << libraryName
334 << "-java\n"
335 << "LOCAL_MODULE_CLASS := JAVA_LIBRARIES\n\n"
336 << "intermediates := $(local-generated-sources-dir)\n\n"
337 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
338 << hidl_gen
339 << "$(HOST_EXECUTABLE_SUFFIX)";
340
Iliyan Malchev800273d2016-09-02 15:25:07 -0700341 if (!importedPackages.empty()) {
342 out << "\n"
343 << "\nLOCAL_JAVA_LIBRARIES := \\";
344 out.indent();
345 for (const auto &importedPackage : importedPackages) {
346 out << "\n" << makeLibraryName(importedPackage) << "-java \\";
347 }
348 out << "\n";
349 out.unindent();
350 }
351
Andreas Huber0fa9e392016-08-31 09:05:44 -0700352 generateMakefileSectionForLanguage(
353 out,
354 coordinator,
355 packageFQName,
356 packageInterfaces,
357 typesAST,
358 true /* forJava */);
359
360 out << "\ninclude $(BUILD_JAVA_LIBRARY)\n";
361 }
362
Andreas Huberd2943e12016-08-05 11:59:31 -0700363 return OK;
364}
365
Andreas Huber0fa9e392016-08-31 09:05:44 -0700366OutputHandler::ValRes validateForMakefile(
367 const FQName &fqName, const std::string & /* language */) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700368 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700369 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700370 return OutputHandler::FAILED;
371 }
372
373 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700374 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700375 return OutputHandler::FAILED;
376 }
377
378 if (!fqName.name().empty()) {
379 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700380 "ERROR: Expecting only package name and version.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700381 return OutputHandler::FAILED;
382 }
383
384 return OutputHandler::PASS_PACKAGE;
385}
386
Andreas Huber0fa9e392016-08-31 09:05:44 -0700387OutputHandler::ValRes validateForSource(
388 const FQName &fqName, const std::string &language) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700389 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700390 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700391 return OutputHandler::FAILED;
392 }
393
394 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700395 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700396 return OutputHandler::FAILED;
397 }
398
Andreas Huber0fa9e392016-08-31 09:05:44 -0700399 const std::string &name = fqName.name();
400 if (!name.empty()) {
401 if (name.find('.') == std::string::npos) {
402 return OutputHandler::PASS_FULL;
403 }
404
405 if (language != "java" || name.find("types.") != 0) {
406 // When generating java sources for "types.hal", output can be
407 // constrained to just one of the top-level types declared
408 // by using the extended syntax
409 // android.hardware.Foo@1.0::types.TopLevelTypeName.
410 // In all other cases (different language, not 'types') the dot
411 // notation in the name is illegal in this context.
412 return OutputHandler::FAILED;
413 }
414
415 return OutputHandler::PASS_FULL;
416 }
417
418 return OutputHandler::PASS_PACKAGE;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700419}
420
421static std::vector<OutputHandler> formats = {
422 {"c++",
Andreas Huber2831d512016-08-15 09:33:47 -0700423 true /* mNeedsOutputDir */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700424 validateForSource,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700425 [](const FQName &fqName,
426 const char *hidl_gen, Coordinator *coordinator,
427 const std::string &outputDir) -> status_t {
428 if (fqName.isFullyQualified()) {
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700429 return generateSourcesForFile(fqName,
430 hidl_gen,
431 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700432 outputDir,
433 "c++");
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700434 } else {
435 return generateSourcesForPackage(fqName,
436 hidl_gen,
437 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700438 outputDir,
439 "c++");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700440 }
441 }
442 },
443
Andreas Huber2831d512016-08-15 09:33:47 -0700444 {"java",
445 true /* mNeedsOutputDir */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700446 validateForSource,
Andreas Huber2831d512016-08-15 09:33:47 -0700447 [](const FQName &fqName,
448 const char *hidl_gen, Coordinator *coordinator,
449 const std::string &outputDir) -> status_t {
450 if (fqName.isFullyQualified()) {
451 return generateSourcesForFile(fqName,
452 hidl_gen,
453 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700454 outputDir,
455 "java");
Andreas Huber2831d512016-08-15 09:33:47 -0700456 }
457 else {
458 return generateSourcesForPackage(fqName,
459 hidl_gen,
460 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700461 outputDir,
462 "java");
Andreas Huber2831d512016-08-15 09:33:47 -0700463 }
464 }
465 },
466
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700467 {"vts",
468 true,
469 validateForSource,
470 [](const FQName &fqName,
471 const char * hidl_gen,
472 Coordinator *coordinator,
473 const std::string &outputDir) -> status_t {
474 if (fqName.isFullyQualified()) {
475 return generateSourcesForFile(fqName,
476 hidl_gen,
477 coordinator,
478 outputDir, "vts");
479 } else {
480 return generateSourcesForPackage(fqName,
481 hidl_gen,
482 coordinator,
483 outputDir, "vts");
484 }
485 }
486 },
487
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700488 {"makefile",
Andreas Huber2831d512016-08-15 09:33:47 -0700489 false /* mNeedsOutputDir */,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700490 validateForMakefile,
491 generateMakefileForPackage,
492 },
493};
494
495static void usage(const char *me) {
496 fprintf(stderr,
497 "usage: %s -o output-path -L <language> (-r interface-root)+ fqname+\n",
498 me);
499
500 fprintf(stderr, " -o output path\n");
501
502 fprintf(stderr, " -L <language> (one of");
503 for (auto &e : formats) {
504 fprintf(stderr, " %s", e.mKey.c_str());
505 }
506 fprintf(stderr, ")\n");
507
508 fprintf(stderr,
509 " -r package:path root "
510 "(e.g., android.hardware:hardware/interfaces)\n");
511}
512
Andreas Huberb82318c2016-08-02 14:45:54 -0700513int main(int argc, char **argv) {
514 std::string outputDir;
Andreas Huberdca261f2016-08-04 13:47:51 -0700515 std::vector<std::string> packageRootPaths;
516 std::vector<std::string> packageRoots;
Andreas Huberb82318c2016-08-02 14:45:54 -0700517
Andreas Huber737080b2016-08-02 15:38:04 -0700518 const char *me = argv[0];
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700519 OutputHandler *outputFormat = nullptr;
Andreas Huber737080b2016-08-02 15:38:04 -0700520
Andreas Huberb82318c2016-08-02 14:45:54 -0700521 int res;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700522 while ((res = getopt(argc, argv, "ho:r:L:")) >= 0) {
Andreas Huberb82318c2016-08-02 14:45:54 -0700523 switch (res) {
524 case 'o':
525 {
526 outputDir = optarg;
527 break;
528 }
529
Andreas Huberdca261f2016-08-04 13:47:51 -0700530 case 'r':
531 {
532 std::string val(optarg);
533 auto index = val.find_first_of(':');
534 CHECK(index != std::string::npos);
535
536 auto package = val.substr(0, index);
537 auto path = val.substr(index + 1);
538 packageRootPaths.push_back(path);
539 packageRoots.push_back(package);
540 break;
541 }
542
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700543 case 'L':
544 {
545 CHECK(outputFormat == nullptr); // only one -L option
546 for (auto &e : formats) {
547 if (e.mKey == optarg) {
548 outputFormat = &e;
549 break;
550 }
551 }
552 CHECK(outputFormat != nullptr);
553 break;
554 }
555
Andreas Huberb82318c2016-08-02 14:45:54 -0700556 case '?':
557 case 'h':
558 default:
559 {
Andreas Huber737080b2016-08-02 15:38:04 -0700560 usage(me);
Andreas Huberb82318c2016-08-02 14:45:54 -0700561 exit(1);
562 break;
563 }
564 }
565 }
566
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700567 if (outputFormat == nullptr) {
568 usage(me);
569 exit(1);
570 }
571
Andreas Huberb82318c2016-08-02 14:45:54 -0700572 argc -= optind;
573 argv += optind;
574
Andreas Huberdca261f2016-08-04 13:47:51 -0700575 if (packageRootPaths.empty()) {
576 // Pick reasonable defaults.
577
578 packageRoots.push_back("android.hardware");
579
580 const char *TOP = getenv("TOP");
581 CHECK(TOP != NULL);
582
583 std::string path = TOP;
584 path.append("/hardware/interfaces");
585
586 packageRootPaths.push_back(path);
587 }
588
Andreas Huber737080b2016-08-02 15:38:04 -0700589 // Valid options are now in argv[0] .. argv[argc - 1].
590
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700591 if (!outputFormat->mNeedsOutputDir) {
Andreas Huberd2943e12016-08-05 11:59:31 -0700592 outputDir.clear(); // Unused.
593 } else if (outputDir.empty()) {
Andreas Huber737080b2016-08-02 15:38:04 -0700594 usage(me);
Andreas Huberb82318c2016-08-02 14:45:54 -0700595 exit(1);
596 } else {
597 const size_t len = outputDir.size();
598 if (outputDir[len - 1] != '/') {
599 outputDir += "/";
600 }
601 }
602
Andreas Huberdca261f2016-08-04 13:47:51 -0700603 Coordinator coordinator(packageRootPaths, packageRoots);
Andreas Huber5345ec22016-07-29 13:33:27 -0700604
Andreas Huber737080b2016-08-02 15:38:04 -0700605 for (int i = 0; i < argc; ++i) {
Andreas Huber68f24592016-07-29 14:53:48 -0700606 FQName fqName(argv[i]);
Andreas Huber68f24592016-07-29 14:53:48 -0700607
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700608 if (!fqName.isValid()) {
Andreas Hubere61e3f72016-08-03 10:22:03 -0700609 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700610 "ERROR: Invalid fully-qualified name.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700611 exit(1);
612 }
Andreas Huber881227d2016-08-02 14:20:21 -0700613
Andreas Huber0fa9e392016-08-31 09:05:44 -0700614 OutputHandler::ValRes valid =
615 outputFormat->validate(fqName, outputFormat->mKey);
616
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700617 if (valid == OutputHandler::FAILED) {
Andreas Hubere61e3f72016-08-03 10:22:03 -0700618 exit(1);
619 }
Andreas Huberd2943e12016-08-05 11:59:31 -0700620
621 status_t err =
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700622 outputFormat->generate(fqName, me, &coordinator, outputDir);
Andreas Huberd2943e12016-08-05 11:59:31 -0700623
624 if (err != OK) {
Steven Moreland261370a2016-08-29 15:36:59 -0700625 exit(1);
Andreas Huberd2943e12016-08-05 11:59:31 -0700626 }
Andreas Hubereb1081f2016-07-28 13:13:24 -0700627 }
Andreas Huberc9410c72016-07-28 12:18:40 -0700628
Andreas Huberd2943e12016-08-05 11:59:31 -0700629 return 0;
Andreas Huberc9410c72016-07-28 12:18:40 -0700630}