blob: e69069b3e03663421fde1c84f6abc22d8efeb5bb [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;
Andreas Huber019d21d2016-10-03 12:59:47 -070034 enum OutputMode {
35 NEEDS_DIR,
36 NEEDS_FILE,
37 NOT_NEEDED
38 } mOutputMode;
39
Iliyan Malchev5bb14022016-08-09 15:04:39 -070040 enum ValRes {
41 FAILED,
42 PASS_PACKAGE,
43 PASS_FULL
44 };
Andreas Huber0fa9e392016-08-31 09:05:44 -070045 ValRes (*validate)(const FQName &, const std::string &language);
Iliyan Malchev5bb14022016-08-09 15:04:39 -070046 status_t (*generate)(const FQName &fqName,
47 const char *hidl_gen,
48 Coordinator *coordinator,
49 const std::string &outputDir);
50};
Andreas Huberdca261f2016-08-04 13:47:51 -070051
Iliyan Malchev5bb14022016-08-09 15:04:39 -070052static status_t generateSourcesForFile(
53 const FQName &fqName,
54 const char *,
55 Coordinator *coordinator,
Andreas Huber2831d512016-08-15 09:33:47 -070056 const std::string &outputDir,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070057 const std::string &lang) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -070058 CHECK(fqName.isFullyQualified());
59
Andreas Huber0fa9e392016-08-31 09:05:44 -070060 AST *ast;
Andreas Huberd29724f2016-09-14 09:33:13 -070061 std::string limitToType;
Andreas Huber0fa9e392016-08-31 09:05:44 -070062
63 if (fqName.name().find("types.") == 0) {
64 CHECK(lang == "java"); // Already verified in validate().
65
Andreas Huberd29724f2016-09-14 09:33:13 -070066 limitToType = fqName.name().substr(strlen("types."));
Andreas Huber0fa9e392016-08-31 09:05:44 -070067
68 FQName typesName(fqName.package(), fqName.version(), "types");
69 ast = coordinator->parse(typesName);
70 } else {
71 ast = coordinator->parse(fqName);
72 }
Iliyan Malchev5bb14022016-08-09 15:04:39 -070073
74 if (ast == NULL) {
75 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -070076 "ERROR: Could not parse %s. Aborting.\n",
Iliyan Malchev5bb14022016-08-09 15:04:39 -070077 fqName.string().c_str());
78
79 return UNKNOWN_ERROR;
80 }
81
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070082 if (lang == "c++") {
83 return ast->generateCpp(outputDir);
84 }
Steven Moreland9c387612016-09-07 09:54:26 -070085 if (lang == "c++-impl") {
86 return ast->generateCppImpl(outputDir);
87 }
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070088 if (lang == "java") {
Andreas Huber0fa9e392016-08-31 09:05:44 -070089 return ast->generateJava(outputDir, limitToType);
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070090 }
91 if (lang == "vts") {
92 return ast->generateVts(outputDir);
93 }
94 // Unknown language.
95 return UNKNOWN_ERROR;
Iliyan Malchev5bb14022016-08-09 15:04:39 -070096}
97
98static status_t generateSourcesForPackage(
99 const FQName &packageFQName,
100 const char *hidl_gen,
101 Coordinator *coordinator,
Andreas Huber2831d512016-08-15 09:33:47 -0700102 const std::string &outputDir,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700103 const std::string &lang) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700104 CHECK(packageFQName.isValid() &&
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700105 !packageFQName.isFullyQualified() &&
106 packageFQName.name().empty());
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700107
108 std::vector<FQName> packageInterfaces;
109
110 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700111 coordinator->appendPackageInterfacesToVector(packageFQName,
112 &packageInterfaces);
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700113
114 if (err != OK) {
115 return err;
116 }
117
118 for (const auto &fqName : packageInterfaces) {
Andreas Huber2831d512016-08-15 09:33:47 -0700119 err = generateSourcesForFile(
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700120 fqName, hidl_gen, coordinator, outputDir, lang);
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700121 if (err != OK) {
122 return err;
123 }
124 }
125
126 return OK;
Andreas Huberb82318c2016-08-02 14:45:54 -0700127}
128
Andreas Huberd2943e12016-08-05 11:59:31 -0700129static std::string makeLibraryName(const FQName &packageFQName) {
Iliyan Malcheve2c595a2016-08-07 21:20:04 -0700130 return packageFQName.string();
Andreas Huberd2943e12016-08-05 11:59:31 -0700131}
132
Dan Willemsen676abdc2016-09-28 19:42:22 -0700133static void generateMakefileSectionForType(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700134 Formatter &out,
135 Coordinator *coordinator,
136 const FQName &packageFQName,
137 const FQName &fqName,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700138 const char *typeName) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700139 out << "\n"
140 << "\n#"
141 << "\n# Build " << fqName.name() << ".hal";
142
Dan Willemsen676abdc2016-09-28 19:42:22 -0700143 if (typeName != nullptr) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700144 out << " (" << typeName << ")";
145 }
146
147 out << "\n#"
148 << "\nGEN := $(intermediates)/"
149 << coordinator->convertPackageRootToPath(packageFQName)
150 << coordinator->getPackagePath(packageFQName, true /* relative */);
Dan Willemsen676abdc2016-09-28 19:42:22 -0700151 if (typeName == nullptr) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700152 out << fqName.name() << ".java";
153 } else {
154 out << typeName << ".java";
155 }
156
157 out << "\n$(GEN): $(HIDL)";
158 out << "\n$(GEN): PRIVATE_HIDL := $(HIDL)";
159 out << "\n$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/"
160 << fqName.name() << ".hal";
Iliyan Malchevb9819132016-09-07 12:38:31 -0700161
162 {
163 AST *ast = coordinator->parse(fqName);
164 CHECK(ast != nullptr);
165 const std::set<FQName>& refs = ast->getImportedNames();
166 for (auto depFQName : refs) {
167 // If the package of depFQName is the same as this fqName's package,
168 // then add it explicitly as a .hal dependency within the same
169 // package.
170 if (fqName.package() == depFQName.package() &&
171 fqName.version() == depFQName.version()) {
172 // PRIVATE_DEPS is not actually being used in the
173 // auto-generated file, but is necessary if the build rule
174 // ever needs to use the dependency information, since the
175 // built-in Make variables are not supported in the Android
176 // build system.
177 out << "\n$(GEN): PRIVATE_DEPS += $(LOCAL_PATH)/"
178 << depFQName.name() << ".hal";
179 // This is the actual dependency.
180 out << "\n$(GEN): $(LOCAL_PATH)/"
181 << depFQName.name() << ".hal";
182 }
183 }
184 }
185
Andreas Huber0fa9e392016-08-31 09:05:44 -0700186 out << "\n$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)"
187 << "\n$(GEN): PRIVATE_CUSTOM_TOOL = \\";
188 out.indent();
189 out.indent();
190 out << "\n$(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \\"
Dan Willemsen676abdc2016-09-28 19:42:22 -0700191 << "\n-Ljava"
Andreas Huber0fa9e392016-08-31 09:05:44 -0700192 << " -r"
193 << coordinator->getPackageRoot(packageFQName) << ":"
194 << coordinator->getPackageRootPath(packageFQName) << " \\\n";
195
196 out << packageFQName.string()
197 << "::"
198 << fqName.name();
199
Dan Willemsen676abdc2016-09-28 19:42:22 -0700200 if (typeName != nullptr) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700201 out << "." << typeName;
202 }
203
204 out << "\n";
205
206 out.unindent();
207 out.unindent();
208
209 out << "\n$(GEN): $(LOCAL_PATH)/" << fqName.name() << ".hal";
210 out << "\n\t$(transform-generated-source)";
211 out << "\nLOCAL_GENERATED_SOURCES += $(GEN)";
212}
213
Dan Willemsen676abdc2016-09-28 19:42:22 -0700214static void generateMakefileSection(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700215 Formatter &out,
216 Coordinator *coordinator,
217 const FQName &packageFQName,
218 const std::vector<FQName> &packageInterfaces,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700219 AST *typesAST) {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700220 for (const auto &fqName : packageInterfaces) {
Dan Willemsen676abdc2016-09-28 19:42:22 -0700221 if (fqName.name() == "types") {
Andreas Huber0fa9e392016-08-31 09:05:44 -0700222 CHECK(typesAST != nullptr);
223
224 Scope *rootScope = typesAST->scope();
Andreas Huber0fa9e392016-08-31 09:05:44 -0700225
Andreas Huberb747bd92016-09-26 15:55:31 -0700226 std::vector<NamedType *> subTypes = rootScope->getSubTypes();
227 std::sort(
228 subTypes.begin(),
229 subTypes.end(),
230 [](const NamedType *a, const NamedType *b) -> bool {
231 return a->fqName() < b->fqName();
232 });
233
234 for (const auto &type : subTypes) {
Andreas Huberdda25cc2016-09-22 10:39:47 -0700235 if (type->isTypeDef()) {
236 continue;
237 }
238
Dan Willemsen676abdc2016-09-28 19:42:22 -0700239 generateMakefileSectionForType(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700240 out,
241 coordinator,
242 packageFQName,
243 fqName,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700244 type->localName().c_str());
Andreas Huber0fa9e392016-08-31 09:05:44 -0700245 }
246
247 continue;
248 }
249
Dan Willemsen676abdc2016-09-28 19:42:22 -0700250 generateMakefileSectionForType(
Andreas Huber0fa9e392016-08-31 09:05:44 -0700251 out,
252 coordinator,
253 packageFQName,
254 fqName,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700255 nullptr /* typeName */);
Andreas Huber0fa9e392016-08-31 09:05:44 -0700256 }
257}
258
Andreas Huber75ae95d2016-10-12 16:08:26 -0700259static status_t isPackageJavaCompatible(
260 const FQName &packageFQName,
261 Coordinator *coordinator,
262 bool *compatible) {
263 std::vector<FQName> todo;
264 status_t err =
265 coordinator->appendPackageInterfacesToVector(packageFQName, &todo);
266
267 if (err != OK) {
268 return err;
269 }
270
271 std::set<FQName> seen;
272 for (const auto &iface : todo) {
273 seen.insert(iface);
274 }
275
276 // Form the transitive closure of all imported interfaces (and types.hal-s)
277 // If any one of them is not java compatible, this package isn't either.
278 while (!todo.empty()) {
279 const FQName fqName = todo.back();
280 todo.pop_back();
281
282 AST *ast = coordinator->parse(fqName);
283
284 if (ast == nullptr) {
285 return UNKNOWN_ERROR;
286 }
287
288 if (!ast->isJavaCompatible()) {
289 *compatible = false;
290 return OK;
291 }
292
293 std::set<FQName> importedPackages;
294 ast->getImportedPackages(&importedPackages);
295
296 for (const auto &package : importedPackages) {
297 std::vector<FQName> packageInterfaces;
298 status_t err = coordinator->appendPackageInterfacesToVector(
299 package, &packageInterfaces);
300
301 if (err != OK) {
302 return err;
303 }
304
305 for (const auto &iface : packageInterfaces) {
306 if (seen.find(iface) != seen.end()) {
307 continue;
308 }
309
310 todo.push_back(iface);
311 seen.insert(iface);
312 }
313 }
314 }
315
316 *compatible = true;
317 return OK;
318}
319
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700320static status_t generateMakefileForPackage(
321 const FQName &packageFQName,
Iliyan Malchevb66c3992016-08-07 21:18:13 -0700322 const char *hidl_gen,
Andreas Huberd2943e12016-08-05 11:59:31 -0700323 Coordinator *coordinator,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700324 const std::string &) {
325
326 CHECK(packageFQName.isValid() &&
327 !packageFQName.isFullyQualified() &&
328 packageFQName.name().empty());
329
Andreas Huberd2943e12016-08-05 11:59:31 -0700330 std::vector<FQName> packageInterfaces;
331
332 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700333 coordinator->appendPackageInterfacesToVector(packageFQName,
334 &packageInterfaces);
Andreas Huberd2943e12016-08-05 11:59:31 -0700335
336 if (err != OK) {
337 return err;
338 }
339
340 std::set<FQName> importedPackages;
Andreas Huber0fa9e392016-08-31 09:05:44 -0700341 AST *typesAST = nullptr;
342
Andreas Huberd2943e12016-08-05 11:59:31 -0700343 for (const auto &fqName : packageInterfaces) {
344 AST *ast = coordinator->parse(fqName);
345
346 if (ast == NULL) {
347 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700348 "ERROR: Could not parse %s. Aborting.\n",
Andreas Huberd2943e12016-08-05 11:59:31 -0700349 fqName.string().c_str());
350
351 return UNKNOWN_ERROR;
352 }
353
Andreas Huber0fa9e392016-08-31 09:05:44 -0700354 if (fqName.name() == "types") {
355 typesAST = ast;
356 }
357
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700358 ast->getImportedPackages(&importedPackages);
Andreas Huberd2943e12016-08-05 11:59:31 -0700359 }
360
Andreas Huber75ae95d2016-10-12 16:08:26 -0700361 bool packageIsJavaCompatible;
362 err = isPackageJavaCompatible(
363 packageFQName, coordinator, &packageIsJavaCompatible);
364
365 if (err != OK) {
366 return err;
367 }
368
Dan Willemsen676abdc2016-09-28 19:42:22 -0700369 if (!packageIsJavaCompatible) {
370 return OK;
371 }
372
Andreas Huberd2943e12016-08-05 11:59:31 -0700373 std::string path =
374 coordinator->getPackagePath(packageFQName, false /* relative */);
375
376 path.append("Android.mk");
377
378 CHECK(Coordinator::MakeParentHierarchy(path));
379 FILE *file = fopen(path.c_str(), "w");
380
381 if (file == NULL) {
382 return -errno;
383 }
384
385 const std::string libraryName = makeLibraryName(packageFQName);
386
387 Formatter out(file);
388
Dan Willemsen676abdc2016-09-28 19:42:22 -0700389 out << "# This file is autogenerated by hidl-gen. Do not edit manually.\n\n";
390 out << "LOCAL_PATH := $(call my-dir)\n";
Andreas Huberd2943e12016-08-05 11:59:31 -0700391
Dan Willemsen676abdc2016-09-28 19:42:22 -0700392 enum LibraryStyle {
393 LIBRARY_STYLE_REGULAR,
394 LIBRARY_STYLE_STATIC,
395 LIBRARY_STYLE_END,
396 };
Andreas Huberd2943e12016-08-05 11:59:31 -0700397
Dan Willemsen676abdc2016-09-28 19:42:22 -0700398 for (int style = LIBRARY_STYLE_REGULAR; style != LIBRARY_STYLE_END;
399 ++style) {
400 const std::string staticSuffix =
401 (style == LIBRARY_STYLE_STATIC) ? "-static" : "";
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700402
Dan Willemsen676abdc2016-09-28 19:42:22 -0700403 out << "\n"
404 << "########################################"
405 << "########################################\n\n";
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700406
Dan Willemsen676abdc2016-09-28 19:42:22 -0700407 out << "include $(CLEAR_VARS)\n"
408 << "LOCAL_MODULE := "
409 << libraryName
410 << "-java"
411 << staticSuffix
412 << "\nLOCAL_MODULE_CLASS := JAVA_LIBRARIES\n\n"
413 << "intermediates := $(local-generated-sources-dir)\n\n"
414 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
415 << hidl_gen
416 << "$(HOST_EXECUTABLE_SUFFIX)";
Andreas Huberd2943e12016-08-05 11:59:31 -0700417
Dan Willemsen676abdc2016-09-28 19:42:22 -0700418 if (!importedPackages.empty()) {
Iliyan Malchev800273d2016-09-02 15:25:07 -0700419 out << "\n"
Dan Willemsen676abdc2016-09-28 19:42:22 -0700420 << "\nLOCAL_"
Andreas Huber782d45e2016-09-22 13:25:14 -0700421 << ((style == LIBRARY_STYLE_STATIC) ? "STATIC_" : "")
Dan Willemsen676abdc2016-09-28 19:42:22 -0700422 << "JAVA_LIBRARIES := \\";
423
424 out.indent();
425 for (const auto &importedPackage : importedPackages) {
426 out << "\n"
427 << makeLibraryName(importedPackage)
428 << "-java"
429 << staticSuffix
430 << " \\";
431 }
432 out << "\n";
433 out.unindent();
Iliyan Malchev800273d2016-09-02 15:25:07 -0700434 }
Dan Willemsen676abdc2016-09-28 19:42:22 -0700435
436 generateMakefileSection(
437 out,
438 coordinator,
439 packageFQName,
440 packageInterfaces,
441 typesAST);
442
443 out << "\ninclude $(BUILD_"
444 << ((style == LIBRARY_STYLE_STATIC) ? "STATIC_" : "")
445 << "JAVA_LIBRARY)\n\n";
Andreas Huber0fa9e392016-08-31 09:05:44 -0700446 }
447
Iliyan Malchev8be09552016-09-22 16:20:33 -0700448 out << "\n\n"
449 << "include $(call all-makefiles-under,$(LOCAL_PATH))\n";
450
Andreas Huberd2943e12016-08-05 11:59:31 -0700451 return OK;
452}
453
Andreas Huber0fa9e392016-08-31 09:05:44 -0700454OutputHandler::ValRes validateForMakefile(
455 const FQName &fqName, const std::string & /* language */) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700456 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700457 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700458 return OutputHandler::FAILED;
459 }
460
461 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700462 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700463 return OutputHandler::FAILED;
464 }
465
466 if (!fqName.name().empty()) {
467 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700468 "ERROR: Expecting only package name and version.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700469 return OutputHandler::FAILED;
470 }
471
472 return OutputHandler::PASS_PACKAGE;
473}
474
Dan Willemsen676abdc2016-09-28 19:42:22 -0700475static void generateAndroidBpGenSection(
476 Formatter &out,
477 const FQName &packageFQName,
478 const char *hidl_gen,
479 Coordinator *coordinator,
480 const std::string &genName,
481 const char *language,
482 const std::vector<FQName> &packageInterfaces,
483 const std::function<void(Formatter&, const FQName)> outputFn) {
484
485 out << "genrule {\n";
486 out.indent();
487 out << "name: \"" << genName << "\",\n"
488 << "tool: \"" << hidl_gen << "\",\n";
489
490 out << "cmd: \"$tool -o $genDir"
491 << " -L" << language
492 << " -r"
493 << coordinator->getPackageRoot(packageFQName) << ":"
494 << coordinator->getPackageRootPath(packageFQName)
495 << " " << packageFQName.string() << "\",\n";
496
497 out << "srcs: [\n";
498 out.indent();
499 for (const auto &fqName : packageInterfaces) {
500 out << "\"" << fqName.name() << ".hal\",\n";
501 }
502 out.unindent();
503 out << "],\n";
504
505 out << "out: [\n";
506 out.indent();
507 for (const auto &fqName : packageInterfaces) {
508 outputFn(out, fqName);
509 }
510 out.unindent();
511 out << "],\n";
512
513 out.unindent();
514 out << "}\n\n";
515}
516
517static status_t generateAndroidBpForPackage(
518 const FQName &packageFQName,
519 const char *hidl_gen,
520 Coordinator *coordinator,
521 const std::string &) {
522
523 CHECK(packageFQName.isValid() &&
524 !packageFQName.isFullyQualified() &&
525 packageFQName.name().empty());
526
527 std::vector<FQName> packageInterfaces;
528
529 status_t err =
530 coordinator->appendPackageInterfacesToVector(packageFQName,
531 &packageInterfaces);
532
533 if (err != OK) {
534 return err;
535 }
536
537 std::set<FQName> importedPackages;
538 AST *typesAST = nullptr;
539
540 for (const auto &fqName : packageInterfaces) {
541 AST *ast = coordinator->parse(fqName);
542
543 if (ast == NULL) {
544 fprintf(stderr,
545 "ERROR: Could not parse %s. Aborting.\n",
546 fqName.string().c_str());
547
548 return UNKNOWN_ERROR;
549 }
550
551 if (fqName.name() == "types") {
552 typesAST = ast;
553 }
554
555 ast->getImportedPackages(&importedPackages);
556 }
557
558 std::string path =
559 coordinator->getPackagePath(packageFQName, false /* relative */);
560
561 path.append("Android.bp");
562
563 CHECK(Coordinator::MakeParentHierarchy(path));
564 FILE *file = fopen(path.c_str(), "w");
565
566 if (file == NULL) {
567 return -errno;
568 }
569
570 const std::string libraryName = makeLibraryName(packageFQName);
571 const std::string genSourceName = libraryName + "_genc++";
572 const std::string genHeaderName = libraryName + "_genc++_headers";
573 const std::string pathPrefix =
574 coordinator->convertPackageRootToPath(packageFQName) +
575 coordinator->getPackagePath(packageFQName, true /* relative */);
576
577 Formatter out(file);
578
579 out << "// This file is autogenerated by hidl-gen. Do not edit manually.\n\n";
580
581 // Rule to generate the C++ source files
582 generateAndroidBpGenSection(
583 out,
584 packageFQName,
585 hidl_gen,
586 coordinator,
587 genSourceName,
588 "c++",
589 packageInterfaces,
590 [&pathPrefix](Formatter &out, const FQName &fqName) {
591 if (fqName.name() == "types") {
592 out << "\"" << pathPrefix << "types.cpp\",\n";
593 } else {
594 out << "\"" << pathPrefix << fqName.name().substr(1) << "All.cpp\",\n";
595 }
596 });
597
598 // Rule to generate the C++ header files
599 generateAndroidBpGenSection(
600 out,
601 packageFQName,
602 hidl_gen,
603 coordinator,
604 genHeaderName,
605 "c++",
606 packageInterfaces,
607 [&pathPrefix](Formatter &out, const FQName &fqName) {
608 out << "\"" << pathPrefix << fqName.name() << ".h\",\n";
609 if (fqName.name() != "types") {
610 out << "\"" << pathPrefix << "IHw" << fqName.name().substr(1) << ".h\",\n";
611 out << "\"" << pathPrefix << "Bn" << fqName.name().substr(1) << ".h\",\n";
612 out << "\"" << pathPrefix << "Bp" << fqName.name().substr(1) << ".h\",\n";
613 out << "\"" << pathPrefix << "Bs" << fqName.name().substr(1) << ".h\",\n";
614 }
615 });
616
617 // C++ library definition
618 out << "cc_library_shared {\n";
619 out.indent();
620 out << "name: \"" << libraryName << "\",\n"
621 << "generated_sources: [\"" << genSourceName << "\"],\n"
622 << "generated_headers: [\"" << genHeaderName << "\"],\n"
623 << "export_generated_headers: [\"" << genHeaderName << "\"],\n"
624 << "shared_libs: [\n";
625
626 out.indent();
627 out << "\"libhidl\",\n"
628 << "\"libhwbinder\",\n"
629 << "\"libutils\",\n"
630 << "\"libcutils\",\n";
631 for (const auto &importedPackage : importedPackages) {
632 out << "\"" << makeLibraryName(importedPackage) << "\",\n";
633 }
634 out.unindent();
635
636 out << "],\n";
637 out.unindent();
638 out << "}\n";
639
640 return OK;
641}
642
Steven Moreland197d56c2016-09-09 10:03:58 -0700643static status_t generateMakefileImplForPackage(
644 const FQName &packageFQName,
645 const char *,
646 Coordinator *coordinator,
647 const std::string &outputDir) {
648
Iliyan Malchev4923f932016-09-09 13:04:59 -0700649 const std::string libraryName = makeLibraryName(packageFQName) + "-impl";
Steven Moreland197d56c2016-09-09 10:03:58 -0700650
651 std::vector<FQName> packageInterfaces;
652
653 status_t err =
Steven Morelandaa186832016-09-26 13:51:43 -0700654 coordinator->appendPackageInterfacesToVector(packageFQName,
655 &packageInterfaces);
Steven Moreland197d56c2016-09-09 10:03:58 -0700656
657 if (err != OK) {
658 return err;
659 }
660
661 std::set<FQName> importedPackages;
662
663 for (const auto &fqName : packageInterfaces) {
664 AST *ast = coordinator->parse(fqName);
665
666 if (ast == NULL) {
667 fprintf(stderr,
668 "ERROR: Could not parse %s. Aborting.\n",
669 fqName.string().c_str());
670
671 return UNKNOWN_ERROR;
672 }
673
674 ast->getImportedPackages(&importedPackages);
675 }
676
677 std::string path = outputDir + "Android.mk";
678
679 CHECK(Coordinator::MakeParentHierarchy(path));
680 FILE *file = fopen(path.c_str(), "w");
681
682 if (file == NULL) {
683 return -errno;
684 }
685
686 Formatter out(file);
687
688 out << "LOCAL_PATH := $(call my-dir)\n\n"
689 << "include $(CLEAR_VARS)\n"
690 << "LOCAL_MODULE := " << libraryName << "\n"
691 << "LOCAL_MODULE_RELATIVE_PATH := hw\n"
692 << "LOCAL_SRC_FILES := \\\n";
693 out.indent();
694 for (const auto &fqName : packageInterfaces) {
695 if (fqName.name() == "types") {
696 continue;
697 }
698 out << fqName.getInterfaceBaseName() << ".cpp \\\n";
699 }
700 out.unindent();
701 out << "\n";
702 out << "LOCAL_SHARED_LIBRARIES := \\\n";
703 out.indent();
704 out << "libhidl \\\n"
705 << "libhwbinder \\\n"
706 << "libutils \\\n"
707 << makeLibraryName(packageFQName) << " \\\n";
708 out.unindent();
709 out << "\n";
710
711 out << "include $(BUILD_SHARED_LIBRARY)\n";
712
713 return OK;
714}
715
Andreas Huber0fa9e392016-08-31 09:05:44 -0700716OutputHandler::ValRes validateForSource(
717 const FQName &fqName, const std::string &language) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700718 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700719 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700720 return OutputHandler::FAILED;
721 }
722
723 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700724 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700725 return OutputHandler::FAILED;
726 }
727
Andreas Huber0fa9e392016-08-31 09:05:44 -0700728 const std::string &name = fqName.name();
729 if (!name.empty()) {
730 if (name.find('.') == std::string::npos) {
731 return OutputHandler::PASS_FULL;
732 }
733
734 if (language != "java" || name.find("types.") != 0) {
735 // When generating java sources for "types.hal", output can be
736 // constrained to just one of the top-level types declared
737 // by using the extended syntax
738 // android.hardware.Foo@1.0::types.TopLevelTypeName.
739 // In all other cases (different language, not 'types') the dot
740 // notation in the name is illegal in this context.
741 return OutputHandler::FAILED;
742 }
743
744 return OutputHandler::PASS_FULL;
745 }
746
747 return OutputHandler::PASS_PACKAGE;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700748}
749
Andreas Huber019d21d2016-10-03 12:59:47 -0700750OutputHandler::ValRes validateForExportHeader(
751 const FQName &fqName, const std::string & /* language */) {
752 if (fqName.package().empty()) {
753 fprintf(stderr, "ERROR: Expecting package name\n");
754 return OutputHandler::FAILED;
755 }
756
757 if (fqName.version().empty()) {
758 fprintf(stderr, "ERROR: Expecting package version\n");
759 return OutputHandler::FAILED;
760 }
761
762 if (!fqName.name().empty()) {
763 fprintf(stderr,
764 "ERROR: Expecting only package name and version.\n");
765 return OutputHandler::FAILED;
766 }
767
768 return OutputHandler::PASS_PACKAGE;
769}
770
771
772static status_t generateExportHeaderForPackage(
773 const FQName &packageFQName,
774 const char * /* hidl_gen */,
775 Coordinator *coordinator,
776 const std::string &outputPath) {
777
778 CHECK(packageFQName.isValid()
779 && !packageFQName.isFullyQualified()
780 && packageFQName.name().empty());
781
782 std::vector<FQName> packageInterfaces;
783
784 status_t err = coordinator->appendPackageInterfacesToVector(
785 packageFQName, &packageInterfaces);
786
787 if (err != OK) {
788 return err;
789 }
790
791 std::vector<const Type *> exportedTypes;
792
793 for (const auto &fqName : packageInterfaces) {
794 AST *ast = coordinator->parse(fqName);
795
796 if (ast == NULL) {
797 fprintf(stderr,
798 "ERROR: Could not parse %s. Aborting.\n",
799 fqName.string().c_str());
800
801 return UNKNOWN_ERROR;
802 }
803
804 ast->appendToExportedTypesVector(&exportedTypes);
805 }
806
807 if (exportedTypes.empty()) {
808 return OK;
809 }
810
811 CHECK(Coordinator::MakeParentHierarchy(outputPath));
812 FILE *file = fopen(outputPath.c_str(), "w");
813
814 if (file == nullptr) {
815 return -errno;
816 }
817
818 Formatter out(file);
819
820 out << "// This file is autogenerated by hidl-gen. Do not edit manually."
821 "\n\n";
822
823 std::string guard = "HIDL_GENERATED_";
824 guard += packageFQName.tokenName();
825 guard += "_";
826 guard += "EXPORTED_CONSTANTS_H_";
827
828 out << "#ifndef "
829 << guard
830 << "\n#define "
831 << guard
832 << "\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n";
833
834 for (const auto &type : exportedTypes) {
835 type->emitExportedHeader(out);
836 }
837
838 out << "#ifdef __cplusplus\n}\n#endif\n\n#endif // "
839 << guard
840 << "\n";
841
842 return OK;
843}
844
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700845static std::vector<OutputHandler> formats = {
846 {"c++",
Andreas Huber019d21d2016-10-03 12:59:47 -0700847 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700848 validateForSource,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700849 [](const FQName &fqName,
850 const char *hidl_gen, Coordinator *coordinator,
851 const std::string &outputDir) -> status_t {
852 if (fqName.isFullyQualified()) {
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700853 return generateSourcesForFile(fqName,
854 hidl_gen,
855 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700856 outputDir,
857 "c++");
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700858 } else {
859 return generateSourcesForPackage(fqName,
860 hidl_gen,
861 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700862 outputDir,
863 "c++");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700864 }
865 }
866 },
867
Andreas Huber019d21d2016-10-03 12:59:47 -0700868 {"export-header",
869 OutputHandler::NEEDS_FILE /* mOutputMode */,
870 validateForExportHeader,
871 [](const FQName &fqName,
872 const char *hidl_gen,
873 Coordinator *coordinator,
874 const std::string &outputPath) -> status_t {
875 CHECK(!fqName.isFullyQualified());
876
877 return generateExportHeaderForPackage(
878 fqName,
879 hidl_gen,
880 coordinator,
881 outputPath);
882 }
883 },
884
Steven Moreland9c387612016-09-07 09:54:26 -0700885 {"c++-impl",
Andreas Huber019d21d2016-10-03 12:59:47 -0700886 OutputHandler::NEEDS_DIR /* mOutputMode */,
Steven Moreland9c387612016-09-07 09:54:26 -0700887 validateForSource,
888 [](const FQName &fqName,
889 const char *hidl_gen, Coordinator *coordinator,
890 const std::string &outputDir) -> status_t {
891 if (fqName.isFullyQualified()) {
892 return generateSourcesForFile(fqName,
893 hidl_gen,
894 coordinator,
895 outputDir, "c++-impl");
896 } else {
897 return generateSourcesForPackage(fqName,
898 hidl_gen,
899 coordinator,
900 outputDir, "c++-impl");
901 }
902 }
903 },
904
905
Andreas Huber2831d512016-08-15 09:33:47 -0700906 {"java",
Andreas Huber019d21d2016-10-03 12:59:47 -0700907 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700908 validateForSource,
Andreas Huber2831d512016-08-15 09:33:47 -0700909 [](const FQName &fqName,
910 const char *hidl_gen, Coordinator *coordinator,
911 const std::string &outputDir) -> status_t {
912 if (fqName.isFullyQualified()) {
913 return generateSourcesForFile(fqName,
914 hidl_gen,
915 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700916 outputDir,
917 "java");
Andreas Huber2831d512016-08-15 09:33:47 -0700918 }
919 else {
920 return generateSourcesForPackage(fqName,
921 hidl_gen,
922 coordinator,
Andreas Huber0fa9e392016-08-31 09:05:44 -0700923 outputDir,
924 "java");
Andreas Huber2831d512016-08-15 09:33:47 -0700925 }
926 }
927 },
928
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700929 {"vts",
Andreas Huber019d21d2016-10-03 12:59:47 -0700930 OutputHandler::NEEDS_DIR /* mOutputMode */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700931 validateForSource,
932 [](const FQName &fqName,
933 const char * hidl_gen,
934 Coordinator *coordinator,
935 const std::string &outputDir) -> status_t {
936 if (fqName.isFullyQualified()) {
937 return generateSourcesForFile(fqName,
938 hidl_gen,
939 coordinator,
940 outputDir, "vts");
941 } else {
942 return generateSourcesForPackage(fqName,
943 hidl_gen,
944 coordinator,
945 outputDir, "vts");
946 }
947 }
948 },
949
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700950 {"makefile",
Andreas Huber019d21d2016-10-03 12:59:47 -0700951 OutputHandler::NOT_NEEDED /* mOutputMode */,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700952 validateForMakefile,
953 generateMakefileForPackage,
954 },
Steven Moreland197d56c2016-09-09 10:03:58 -0700955
Dan Willemsen676abdc2016-09-28 19:42:22 -0700956 {"androidbp",
Andreas Huber019d21d2016-10-03 12:59:47 -0700957 OutputHandler::NOT_NEEDED /* mOutputMode */,
Dan Willemsen676abdc2016-09-28 19:42:22 -0700958 validateForMakefile,
959 generateAndroidBpForPackage,
960 },
961
Steven Moreland197d56c2016-09-09 10:03:58 -0700962 {"makefile-impl",
Yifan Hong94bcea02016-10-06 13:51:31 -0700963 OutputHandler::NEEDS_DIR /* mOutputMode */,
Steven Moreland197d56c2016-09-09 10:03:58 -0700964 validateForMakefile,
965 generateMakefileImplForPackage,
966 }
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700967};
968
969static void usage(const char *me) {
970 fprintf(stderr,
971 "usage: %s -o output-path -L <language> (-r interface-root)+ fqname+\n",
972 me);
973
974 fprintf(stderr, " -o output path\n");
975
976 fprintf(stderr, " -L <language> (one of");
977 for (auto &e : formats) {
978 fprintf(stderr, " %s", e.mKey.c_str());
979 }
980 fprintf(stderr, ")\n");
981
982 fprintf(stderr,
983 " -r package:path root "
984 "(e.g., android.hardware:hardware/interfaces)\n");
985}
986
Andreas Huberb82318c2016-08-02 14:45:54 -0700987int main(int argc, char **argv) {
Andreas Huber019d21d2016-10-03 12:59:47 -0700988 std::string outputPath;
Andreas Huberdca261f2016-08-04 13:47:51 -0700989 std::vector<std::string> packageRootPaths;
990 std::vector<std::string> packageRoots;
Andreas Huberb82318c2016-08-02 14:45:54 -0700991
Andreas Huber737080b2016-08-02 15:38:04 -0700992 const char *me = argv[0];
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700993 OutputHandler *outputFormat = nullptr;
Andreas Huber737080b2016-08-02 15:38:04 -0700994
Andreas Huberb82318c2016-08-02 14:45:54 -0700995 int res;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700996 while ((res = getopt(argc, argv, "ho:r:L:")) >= 0) {
Andreas Huberb82318c2016-08-02 14:45:54 -0700997 switch (res) {
998 case 'o':
999 {
Andreas Huber019d21d2016-10-03 12:59:47 -07001000 outputPath = optarg;
Andreas Huberb82318c2016-08-02 14:45:54 -07001001 break;
1002 }
1003
Andreas Huberdca261f2016-08-04 13:47:51 -07001004 case 'r':
1005 {
1006 std::string val(optarg);
1007 auto index = val.find_first_of(':');
1008 CHECK(index != std::string::npos);
1009
1010 auto package = val.substr(0, index);
1011 auto path = val.substr(index + 1);
1012 packageRootPaths.push_back(path);
1013 packageRoots.push_back(package);
1014 break;
1015 }
1016
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001017 case 'L':
1018 {
1019 CHECK(outputFormat == nullptr); // only one -L option
1020 for (auto &e : formats) {
1021 if (e.mKey == optarg) {
1022 outputFormat = &e;
1023 break;
1024 }
1025 }
1026 CHECK(outputFormat != nullptr);
1027 break;
1028 }
1029
Andreas Huberb82318c2016-08-02 14:45:54 -07001030 case '?':
1031 case 'h':
1032 default:
1033 {
Andreas Huber737080b2016-08-02 15:38:04 -07001034 usage(me);
Andreas Huberb82318c2016-08-02 14:45:54 -07001035 exit(1);
1036 break;
1037 }
1038 }
1039 }
1040
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001041 if (outputFormat == nullptr) {
1042 usage(me);
1043 exit(1);
1044 }
1045
Andreas Huberb82318c2016-08-02 14:45:54 -07001046 argc -= optind;
1047 argv += optind;
1048
Andreas Huberdca261f2016-08-04 13:47:51 -07001049 if (packageRootPaths.empty()) {
1050 // Pick reasonable defaults.
1051
1052 packageRoots.push_back("android.hardware");
1053
1054 const char *TOP = getenv("TOP");
1055 CHECK(TOP != NULL);
1056
1057 std::string path = TOP;
1058 path.append("/hardware/interfaces");
1059
1060 packageRootPaths.push_back(path);
1061 }
1062
Andreas Huber737080b2016-08-02 15:38:04 -07001063 // Valid options are now in argv[0] .. argv[argc - 1].
1064
Andreas Huber019d21d2016-10-03 12:59:47 -07001065 switch (outputFormat->mOutputMode) {
1066 case OutputHandler::NEEDS_DIR:
1067 case OutputHandler::NEEDS_FILE:
1068 {
1069 if (outputPath.empty()) {
1070 usage(me);
1071 exit(1);
1072 }
1073
1074 if (outputFormat->mOutputMode == OutputHandler::NEEDS_DIR) {
1075 const size_t len = outputPath.size();
1076 if (outputPath[len - 1] != '/') {
1077 outputPath += "/";
1078 }
1079 }
1080 break;
Andreas Huberb82318c2016-08-02 14:45:54 -07001081 }
Andreas Huber019d21d2016-10-03 12:59:47 -07001082
1083 default:
1084 outputPath.clear(); // Unused.
1085 break;
Andreas Huberb82318c2016-08-02 14:45:54 -07001086 }
1087
Andreas Huberdca261f2016-08-04 13:47:51 -07001088 Coordinator coordinator(packageRootPaths, packageRoots);
Andreas Huber5345ec22016-07-29 13:33:27 -07001089
Andreas Huber737080b2016-08-02 15:38:04 -07001090 for (int i = 0; i < argc; ++i) {
Andreas Huber68f24592016-07-29 14:53:48 -07001091 FQName fqName(argv[i]);
Andreas Huber68f24592016-07-29 14:53:48 -07001092
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001093 if (!fqName.isValid()) {
Andreas Hubere61e3f72016-08-03 10:22:03 -07001094 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -07001095 "ERROR: Invalid fully-qualified name.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001096 exit(1);
1097 }
Andreas Huber881227d2016-08-02 14:20:21 -07001098
Andreas Huber0fa9e392016-08-31 09:05:44 -07001099 OutputHandler::ValRes valid =
1100 outputFormat->validate(fqName, outputFormat->mKey);
1101
Iliyan Malchev5bb14022016-08-09 15:04:39 -07001102 if (valid == OutputHandler::FAILED) {
Andreas Hubere61e3f72016-08-03 10:22:03 -07001103 exit(1);
1104 }
Andreas Huberd2943e12016-08-05 11:59:31 -07001105
1106 status_t err =
Andreas Huber019d21d2016-10-03 12:59:47 -07001107 outputFormat->generate(fqName, me, &coordinator, outputPath);
Andreas Huberd2943e12016-08-05 11:59:31 -07001108
1109 if (err != OK) {
Steven Moreland261370a2016-08-29 15:36:59 -07001110 exit(1);
Andreas Huberd2943e12016-08-05 11:59:31 -07001111 }
Andreas Hubereb1081f2016-07-28 13:13:24 -07001112 }
Andreas Huberc9410c72016-07-28 12:18:40 -07001113
Andreas Huberd2943e12016-08-05 11:59:31 -07001114 return 0;
Andreas Huberc9410c72016-07-28 12:18:40 -07001115}