blob: e9c07b796851e8c99ed3a4e6105a39b124f1328f [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";
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) \\"
192 << "\n-L"
193 << (forJava ? "java" : "c++")
194 << " -r"
195 << coordinator->getPackageRoot(packageFQName) << ":"
196 << coordinator->getPackageRootPath(packageFQName) << " \\\n";
197
198 out << packageFQName.string()
199 << "::"
200 << fqName.name();
201
202 if (forJava && typeName != nullptr) {
203 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
216static void generateMakefileSectionForLanguage(
217 Formatter &out,
218 Coordinator *coordinator,
219 const FQName &packageFQName,
220 const std::vector<FQName> &packageInterfaces,
221 AST *typesAST,
222 bool forJava) {
223 for (const auto &fqName : packageInterfaces) {
224 if (forJava && fqName.name() == "types") {
225 CHECK(typesAST != nullptr);
226
227 Scope *rootScope = typesAST->scope();
228 for (size_t i = 0; i < rootScope->countTypes(); ++i) {
229 std::string typeName;
230 rootScope->typeAt(i, &typeName);
231
232 generateMakefileSectionForLanguageAndType(
233 out,
234 coordinator,
235 packageFQName,
236 fqName,
237 typeName.c_str(),
238 forJava);
239 }
240
241 continue;
242 }
243
244 generateMakefileSectionForLanguageAndType(
245 out,
246 coordinator,
247 packageFQName,
248 fqName,
249 nullptr /* typeName */,
250 forJava);
251 }
252}
253
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700254static status_t generateMakefileForPackage(
255 const FQName &packageFQName,
Iliyan Malchevb66c3992016-08-07 21:18:13 -0700256 const char *hidl_gen,
Andreas Huberd2943e12016-08-05 11:59:31 -0700257 Coordinator *coordinator,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700258 const std::string &) {
259
260 CHECK(packageFQName.isValid() &&
261 !packageFQName.isFullyQualified() &&
262 packageFQName.name().empty());
263
Andreas Huberd2943e12016-08-05 11:59:31 -0700264 std::vector<FQName> packageInterfaces;
265
266 status_t err =
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700267 coordinator->appendPackageInterfacesToSet(packageFQName,
268 &packageInterfaces);
Andreas Huberd2943e12016-08-05 11:59:31 -0700269
270 if (err != OK) {
271 return err;
272 }
273
274 std::set<FQName> importedPackages;
Andreas Huber0fa9e392016-08-31 09:05:44 -0700275 bool packageIsJavaCompatible = true;
276 AST *typesAST = nullptr;
277
Andreas Huberd2943e12016-08-05 11:59:31 -0700278 for (const auto &fqName : packageInterfaces) {
279 AST *ast = coordinator->parse(fqName);
280
281 if (ast == NULL) {
282 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700283 "ERROR: Could not parse %s. Aborting.\n",
Andreas Huberd2943e12016-08-05 11:59:31 -0700284 fqName.string().c_str());
285
286 return UNKNOWN_ERROR;
287 }
288
Andreas Huber0fa9e392016-08-31 09:05:44 -0700289 if (packageIsJavaCompatible && !ast->isJavaCompatible()) {
290 packageIsJavaCompatible = false;
291 }
292
293 if (fqName.name() == "types") {
294 typesAST = ast;
295 }
296
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700297 ast->getImportedPackages(&importedPackages);
Andreas Huberd2943e12016-08-05 11:59:31 -0700298 }
299
300 std::string path =
301 coordinator->getPackagePath(packageFQName, false /* relative */);
302
303 path.append("Android.mk");
304
305 CHECK(Coordinator::MakeParentHierarchy(path));
306 FILE *file = fopen(path.c_str(), "w");
307
308 if (file == NULL) {
309 return -errno;
310 }
311
312 const std::string libraryName = makeLibraryName(packageFQName);
313
314 Formatter out(file);
315
316 out << "LOCAL_PATH := $(call my-dir)\n"
317 << "include $(CLEAR_VARS)\n\n"
318 << "LOCAL_MODULE := "
319 << libraryName
320 << "\n"
321 << "LOCAL_MODULE_CLASS := SHARED_LIBRARIES\n\n"
322 << "intermediates := $(local-generated-sources-dir)\n\n"
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700323 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
324 << hidl_gen << "$(HOST_EXECUTABLE_SUFFIX)";
Andreas Huberd2943e12016-08-05 11:59:31 -0700325
Andreas Huber0fa9e392016-08-31 09:05:44 -0700326 generateMakefileSectionForLanguage(
327 out,
328 coordinator,
329 packageFQName,
330 packageInterfaces,
331 typesAST,
332 false /* forJava */);
Andreas Huberd2943e12016-08-05 11:59:31 -0700333
Andreas Huberd2943e12016-08-05 11:59:31 -0700334 out << "\n"
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700335 << "\nLOCAL_EXPORT_C_INCLUDE_DIRS := $(intermediates)"
336 << "\nLOCAL_SHARED_LIBRARIES := \\";
337 out.indent();
Martijn Coenen7473fab2016-08-19 14:05:40 +0200338 out << "\nlibhidl \\"
339 << "\nlibhwbinder \\"
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700340 << "\nlibutils \\";
341
342 for (const auto &importedPackage : importedPackages) {
343 out << "\n" << makeLibraryName(importedPackage) << " \\";
344 }
345 out << "\n";
346 out.unindent();
Keun Soo Yimc2903d22016-08-26 18:56:22 -0700347 out << "\nLOCAL_MULTILIB := both";
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700348
349 out << "\ninclude $(BUILD_SHARED_LIBRARY)\n";
Andreas Huberd2943e12016-08-05 11:59:31 -0700350
Andreas Huber0fa9e392016-08-31 09:05:44 -0700351 if (packageIsJavaCompatible) {
352 out << "\n"
353 << "########################################"
354 << "########################################\n\n";
355
356 out << "include $(CLEAR_VARS)\n"
357 << "LOCAL_MODULE := "
358 << libraryName
359 << "-java\n"
360 << "LOCAL_MODULE_CLASS := JAVA_LIBRARIES\n\n"
361 << "intermediates := $(local-generated-sources-dir)\n\n"
362 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
363 << hidl_gen
364 << "$(HOST_EXECUTABLE_SUFFIX)";
365
Iliyan Malchev800273d2016-09-02 15:25:07 -0700366 if (!importedPackages.empty()) {
367 out << "\n"
368 << "\nLOCAL_JAVA_LIBRARIES := \\";
369 out.indent();
370 for (const auto &importedPackage : importedPackages) {
371 out << "\n" << makeLibraryName(importedPackage) << "-java \\";
372 }
373 out << "\n";
374 out.unindent();
375 }
376
Andreas Huber0fa9e392016-08-31 09:05:44 -0700377 generateMakefileSectionForLanguage(
378 out,
379 coordinator,
380 packageFQName,
381 packageInterfaces,
382 typesAST,
383 true /* forJava */);
384
385 out << "\ninclude $(BUILD_JAVA_LIBRARY)\n";
386 }
387
Andreas Huberd2943e12016-08-05 11:59:31 -0700388 return OK;
389}
390
Andreas Huber0fa9e392016-08-31 09:05:44 -0700391OutputHandler::ValRes validateForMakefile(
392 const FQName &fqName, const std::string & /* language */) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700393 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700394 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700395 return OutputHandler::FAILED;
396 }
397
398 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700399 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700400 return OutputHandler::FAILED;
401 }
402
403 if (!fqName.name().empty()) {
404 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700405 "ERROR: Expecting only package name and version.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700406 return OutputHandler::FAILED;
407 }
408
409 return OutputHandler::PASS_PACKAGE;
410}
411
Andreas Huber0fa9e392016-08-31 09:05:44 -0700412OutputHandler::ValRes validateForSource(
413 const FQName &fqName, const std::string &language) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700414 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700415 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700416 return OutputHandler::FAILED;
417 }
418
419 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700420 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700421 return OutputHandler::FAILED;
422 }
423
Andreas Huber0fa9e392016-08-31 09:05:44 -0700424 const std::string &name = fqName.name();
425 if (!name.empty()) {
426 if (name.find('.') == std::string::npos) {
427 return OutputHandler::PASS_FULL;
428 }
429
430 if (language != "java" || name.find("types.") != 0) {
431 // When generating java sources for "types.hal", output can be
432 // constrained to just one of the top-level types declared
433 // by using the extended syntax
434 // android.hardware.Foo@1.0::types.TopLevelTypeName.
435 // In all other cases (different language, not 'types') the dot
436 // notation in the name is illegal in this context.
437 return OutputHandler::FAILED;
438 }
439
440 return OutputHandler::PASS_FULL;
441 }
442
443 return OutputHandler::PASS_PACKAGE;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700444}
445
446static std::vector<OutputHandler> formats = {
447 {"c++",
Andreas Huber2831d512016-08-15 09:33:47 -0700448 true /* mNeedsOutputDir */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700449 validateForSource,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700450 [](const FQName &fqName,
451 const char *hidl_gen, Coordinator *coordinator,
452 const std::string &outputDir) -> status_t {
453 if (fqName.isFullyQualified()) {
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700454 return generateSourcesForFile(fqName,
455 hidl_gen,
456 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700457 outputDir,
458 "c++");
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700459 } else {
460 return generateSourcesForPackage(fqName,
461 hidl_gen,
462 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700463 outputDir,
464 "c++");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700465 }
466 }
467 },
468
Andreas Huber2831d512016-08-15 09:33:47 -0700469 {"java",
470 true /* mNeedsOutputDir */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700471 validateForSource,
Andreas Huber2831d512016-08-15 09:33:47 -0700472 [](const FQName &fqName,
473 const char *hidl_gen, Coordinator *coordinator,
474 const std::string &outputDir) -> status_t {
475 if (fqName.isFullyQualified()) {
476 return generateSourcesForFile(fqName,
477 hidl_gen,
478 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700479 outputDir,
480 "java");
Andreas Huber2831d512016-08-15 09:33:47 -0700481 }
482 else {
483 return generateSourcesForPackage(fqName,
484 hidl_gen,
485 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700486 outputDir,
487 "java");
Andreas Huber2831d512016-08-15 09:33:47 -0700488 }
489 }
490 },
491
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700492 {"vts",
493 true,
494 validateForSource,
495 [](const FQName &fqName,
496 const char * hidl_gen,
497 Coordinator *coordinator,
498 const std::string &outputDir) -> status_t {
499 if (fqName.isFullyQualified()) {
500 return generateSourcesForFile(fqName,
501 hidl_gen,
502 coordinator,
503 outputDir, "vts");
504 } else {
505 return generateSourcesForPackage(fqName,
506 hidl_gen,
507 coordinator,
508 outputDir, "vts");
509 }
510 }
511 },
512
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700513 {"makefile",
Andreas Huber2831d512016-08-15 09:33:47 -0700514 false /* mNeedsOutputDir */,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700515 validateForMakefile,
516 generateMakefileForPackage,
517 },
518};
519
520static void usage(const char *me) {
521 fprintf(stderr,
522 "usage: %s -o output-path -L <language> (-r interface-root)+ fqname+\n",
523 me);
524
525 fprintf(stderr, " -o output path\n");
526
527 fprintf(stderr, " -L <language> (one of");
528 for (auto &e : formats) {
529 fprintf(stderr, " %s", e.mKey.c_str());
530 }
531 fprintf(stderr, ")\n");
532
533 fprintf(stderr,
534 " -r package:path root "
535 "(e.g., android.hardware:hardware/interfaces)\n");
536}
537
Andreas Huberb82318c2016-08-02 14:45:54 -0700538int main(int argc, char **argv) {
539 std::string outputDir;
Andreas Huberdca261f2016-08-04 13:47:51 -0700540 std::vector<std::string> packageRootPaths;
541 std::vector<std::string> packageRoots;
Andreas Huberb82318c2016-08-02 14:45:54 -0700542
Andreas Huber737080b2016-08-02 15:38:04 -0700543 const char *me = argv[0];
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700544 OutputHandler *outputFormat = nullptr;
Andreas Huber737080b2016-08-02 15:38:04 -0700545
Andreas Huberb82318c2016-08-02 14:45:54 -0700546 int res;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700547 while ((res = getopt(argc, argv, "ho:r:L:")) >= 0) {
Andreas Huberb82318c2016-08-02 14:45:54 -0700548 switch (res) {
549 case 'o':
550 {
551 outputDir = optarg;
552 break;
553 }
554
Andreas Huberdca261f2016-08-04 13:47:51 -0700555 case 'r':
556 {
557 std::string val(optarg);
558 auto index = val.find_first_of(':');
559 CHECK(index != std::string::npos);
560
561 auto package = val.substr(0, index);
562 auto path = val.substr(index + 1);
563 packageRootPaths.push_back(path);
564 packageRoots.push_back(package);
565 break;
566 }
567
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700568 case 'L':
569 {
570 CHECK(outputFormat == nullptr); // only one -L option
571 for (auto &e : formats) {
572 if (e.mKey == optarg) {
573 outputFormat = &e;
574 break;
575 }
576 }
577 CHECK(outputFormat != nullptr);
578 break;
579 }
580
Andreas Huberb82318c2016-08-02 14:45:54 -0700581 case '?':
582 case 'h':
583 default:
584 {
Andreas Huber737080b2016-08-02 15:38:04 -0700585 usage(me);
Andreas Huberb82318c2016-08-02 14:45:54 -0700586 exit(1);
587 break;
588 }
589 }
590 }
591
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700592 if (outputFormat == nullptr) {
593 usage(me);
594 exit(1);
595 }
596
Andreas Huberb82318c2016-08-02 14:45:54 -0700597 argc -= optind;
598 argv += optind;
599
Andreas Huberdca261f2016-08-04 13:47:51 -0700600 if (packageRootPaths.empty()) {
601 // Pick reasonable defaults.
602
603 packageRoots.push_back("android.hardware");
604
605 const char *TOP = getenv("TOP");
606 CHECK(TOP != NULL);
607
608 std::string path = TOP;
609 path.append("/hardware/interfaces");
610
611 packageRootPaths.push_back(path);
612 }
613
Andreas Huber737080b2016-08-02 15:38:04 -0700614 // Valid options are now in argv[0] .. argv[argc - 1].
615
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700616 if (!outputFormat->mNeedsOutputDir) {
Andreas Huberd2943e12016-08-05 11:59:31 -0700617 outputDir.clear(); // Unused.
618 } else if (outputDir.empty()) {
Andreas Huber737080b2016-08-02 15:38:04 -0700619 usage(me);
Andreas Huberb82318c2016-08-02 14:45:54 -0700620 exit(1);
621 } else {
622 const size_t len = outputDir.size();
623 if (outputDir[len - 1] != '/') {
624 outputDir += "/";
625 }
626 }
627
Andreas Huberdca261f2016-08-04 13:47:51 -0700628 Coordinator coordinator(packageRootPaths, packageRoots);
Andreas Huber5345ec22016-07-29 13:33:27 -0700629
Andreas Huber737080b2016-08-02 15:38:04 -0700630 for (int i = 0; i < argc; ++i) {
Andreas Huber68f24592016-07-29 14:53:48 -0700631 FQName fqName(argv[i]);
Andreas Huber68f24592016-07-29 14:53:48 -0700632
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700633 if (!fqName.isValid()) {
Andreas Hubere61e3f72016-08-03 10:22:03 -0700634 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700635 "ERROR: Invalid fully-qualified name.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700636 exit(1);
637 }
Andreas Huber881227d2016-08-02 14:20:21 -0700638
Andreas Huber0fa9e392016-08-31 09:05:44 -0700639 OutputHandler::ValRes valid =
640 outputFormat->validate(fqName, outputFormat->mKey);
641
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700642 if (valid == OutputHandler::FAILED) {
Andreas Hubere61e3f72016-08-03 10:22:03 -0700643 exit(1);
644 }
Andreas Huberd2943e12016-08-05 11:59:31 -0700645
646 status_t err =
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700647 outputFormat->generate(fqName, me, &coordinator, outputDir);
Andreas Huberd2943e12016-08-05 11:59:31 -0700648
649 if (err != OK) {
Steven Moreland261370a2016-08-29 15:36:59 -0700650 exit(1);
Andreas Huberd2943e12016-08-05 11:59:31 -0700651 }
Andreas Hubereb1081f2016-07-28 13:13:24 -0700652 }
Andreas Huberc9410c72016-07-28 12:18:40 -0700653
Andreas Huberd2943e12016-08-05 11:59:31 -0700654 return 0;
Andreas Huberc9410c72016-07-28 12:18:40 -0700655}