blob: d691916cbc7127a251fc8c3ceb657aa32e4dcecf [file] [log] [blame]
Andreas Huberc9410c72016-07-28 12:18:40 -07001#include "AST.h"
Andreas Huber5345ec22016-07-29 13:33:27 -07002#include "Coordinator.h"
Andreas Huberd2943e12016-08-05 11:59:31 -07003#include "Formatter.h"
Andreas Huber84f89de2016-07-28 15:39:51 -07004#include "FQName.h"
Andreas Huberc9410c72016-07-28 12:18:40 -07005
Andreas Huber68f24592016-07-29 14:53:48 -07006#include <android-base/logging.h>
Iliyan Malchev5bb14022016-08-09 15:04:39 -07007#include <set>
Andreas Huberc9410c72016-07-28 12:18:40 -07008#include <stdio.h>
Andreas Huberdca261f2016-08-04 13:47:51 -07009#include <string>
Andreas Huberb82318c2016-08-02 14:45:54 -070010#include <unistd.h>
Andreas Huberdca261f2016-08-04 13:47:51 -070011#include <vector>
Andreas Huberc9410c72016-07-28 12:18:40 -070012
13using namespace android;
14
Iliyan Malchev5bb14022016-08-09 15:04:39 -070015struct OutputHandler {
16 std::string mKey;
17 bool mNeedsOutputDir;
18 enum ValRes {
19 FAILED,
20 PASS_PACKAGE,
21 PASS_FULL
22 };
23 ValRes (*validate)(const FQName &);
24 status_t (*generate)(const FQName &fqName,
25 const char *hidl_gen,
26 Coordinator *coordinator,
27 const std::string &outputDir);
28};
Andreas Huberdca261f2016-08-04 13:47:51 -070029
Iliyan Malchev5bb14022016-08-09 15:04:39 -070030static status_t generateSourcesForFile(
31 const FQName &fqName,
32 const char *,
33 Coordinator *coordinator,
Andreas Huber2831d512016-08-15 09:33:47 -070034 const std::string &outputDir,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070035 const std::string &lang) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -070036 CHECK(fqName.isFullyQualified());
37
38 AST *ast = coordinator->parse(fqName);
39
40 if (ast == NULL) {
41 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -070042 "ERROR: Could not parse %s. Aborting.\n",
Iliyan Malchev5bb14022016-08-09 15:04:39 -070043 fqName.string().c_str());
44
45 return UNKNOWN_ERROR;
46 }
47
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070048 if (lang == "c++") {
49 return ast->generateCpp(outputDir);
50 }
51 if (lang == "java") {
52 return ast->generateJava(outputDir);
53 }
54 if (lang == "vts") {
55 return ast->generateVts(outputDir);
56 }
57 // Unknown language.
58 return UNKNOWN_ERROR;
Iliyan Malchev5bb14022016-08-09 15:04:39 -070059}
60
61static status_t generateSourcesForPackage(
62 const FQName &packageFQName,
63 const char *hidl_gen,
64 Coordinator *coordinator,
Andreas Huber2831d512016-08-15 09:33:47 -070065 const std::string &outputDir,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070066 const std::string &lang) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -070067 CHECK(packageFQName.isValid() &&
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070068 !packageFQName.isFullyQualified() &&
69 packageFQName.name().empty());
Iliyan Malchev5bb14022016-08-09 15:04:39 -070070
71 std::vector<FQName> packageInterfaces;
72
73 status_t err =
74 coordinator->appendPackageInterfacesToSet(packageFQName,
75 &packageInterfaces);
76
77 if (err != OK) {
78 return err;
79 }
80
81 for (const auto &fqName : packageInterfaces) {
Andreas Huber2831d512016-08-15 09:33:47 -070082 err = generateSourcesForFile(
Zhuoyao Zhang5158db42016-08-10 10:25:20 -070083 fqName, hidl_gen, coordinator, outputDir, lang);
Iliyan Malchev5bb14022016-08-09 15:04:39 -070084 if (err != OK) {
85 return err;
86 }
87 }
88
89 return OK;
Andreas Huberb82318c2016-08-02 14:45:54 -070090}
91
Andreas Huberd2943e12016-08-05 11:59:31 -070092static std::string makeLibraryName(const FQName &packageFQName) {
Iliyan Malcheve2c595a2016-08-07 21:20:04 -070093 return packageFQName.string();
Andreas Huberd2943e12016-08-05 11:59:31 -070094}
95
Iliyan Malchev5bb14022016-08-09 15:04:39 -070096static status_t generateMakefileForPackage(
97 const FQName &packageFQName,
Iliyan Malchevb66c3992016-08-07 21:18:13 -070098 const char *hidl_gen,
Andreas Huberd2943e12016-08-05 11:59:31 -070099 Coordinator *coordinator,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700100 const std::string &) {
101
102 CHECK(packageFQName.isValid() &&
103 !packageFQName.isFullyQualified() &&
104 packageFQName.name().empty());
105
Andreas Huberd2943e12016-08-05 11:59:31 -0700106 std::vector<FQName> packageInterfaces;
107
108 status_t err =
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700109 coordinator->appendPackageInterfacesToSet(packageFQName,
110 &packageInterfaces);
Andreas Huberd2943e12016-08-05 11:59:31 -0700111
112 if (err != OK) {
113 return err;
114 }
115
116 std::set<FQName> importedPackages;
117 for (const auto &fqName : packageInterfaces) {
118 AST *ast = coordinator->parse(fqName);
119
120 if (ast == NULL) {
121 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700122 "ERROR: Could not parse %s. Aborting.\n",
Andreas Huberd2943e12016-08-05 11:59:31 -0700123 fqName.string().c_str());
124
125 return UNKNOWN_ERROR;
126 }
127
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700128 ast->getImportedPackages(&importedPackages);
Andreas Huberd2943e12016-08-05 11:59:31 -0700129 }
130
131 std::string path =
132 coordinator->getPackagePath(packageFQName, false /* relative */);
133
134 path.append("Android.mk");
135
136 CHECK(Coordinator::MakeParentHierarchy(path));
137 FILE *file = fopen(path.c_str(), "w");
138
139 if (file == NULL) {
140 return -errno;
141 }
142
143 const std::string libraryName = makeLibraryName(packageFQName);
144
145 Formatter out(file);
146
147 out << "LOCAL_PATH := $(call my-dir)\n"
148 << "include $(CLEAR_VARS)\n\n"
149 << "LOCAL_MODULE := "
150 << libraryName
151 << "\n"
152 << "LOCAL_MODULE_CLASS := SHARED_LIBRARIES\n\n"
153 << "intermediates := $(local-generated-sources-dir)\n\n"
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700154 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
155 << hidl_gen << "$(HOST_EXECUTABLE_SUFFIX)";
Andreas Huberd2943e12016-08-05 11:59:31 -0700156
Andreas Huberd2943e12016-08-05 11:59:31 -0700157 for (const auto &fqName : packageInterfaces) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700158
159 out << "\n"
160 << "\n#"
161 << "\n# Build " << fqName.name() << ".hal"
162 << "\n#";
163 out << "\nGEN := $(intermediates)/"
Andreas Huberd2943e12016-08-05 11:59:31 -0700164 << coordinator->convertPackageRootToPath(packageFQName)
165 << coordinator->getPackagePath(packageFQName, true /* relative */);
Andreas Huberd2943e12016-08-05 11:59:31 -0700166 if (fqName.name() == "types") {
167 out << "types.cpp";
168 } else {
169 out << fqName.name().substr(1) << "All.cpp";
170 }
171
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700172 out << "\n$(GEN): $(HIDL)";
173 out << "\n$(GEN): PRIVATE_HIDL := $(HIDL)";
174 out << "\n$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/"
175 << fqName.name() << ".hal";
176 out << "\n$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)"
177 << "\n$(GEN): PRIVATE_CUSTOM_TOOL = \\";
178 out.indent();
179 out.indent();
180 out << "\n$(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \\"
181 << "\n-Lc++ -r"
182 << coordinator->getPackageRoot(packageFQName) << ":"
183 << coordinator->getPackageRootPath(packageFQName) << "\\";
184 out << "\n"
185 << packageFQName.string()
186 << "::$(patsubst %.hal,%,$(notdir $(PRIVATE_DEPS)))"
187 << "\n";
188 out.unindent();
189 out.unindent();
190
191 out << "\n$(GEN): $(LOCAL_PATH)/" << fqName.name() << ".hal";
192 out << "\n\t$(transform-generated-source)";
193 out << "\nLOCAL_GENERATED_SOURCES += $(GEN)";
Andreas Huberd2943e12016-08-05 11:59:31 -0700194 }
195
Andreas Huberd2943e12016-08-05 11:59:31 -0700196 out << "\n"
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700197 << "\nLOCAL_EXPORT_C_INCLUDE_DIRS := $(intermediates)"
198 << "\nLOCAL_SHARED_LIBRARIES := \\";
199 out.indent();
Martijn Coenen7473fab2016-08-19 14:05:40 +0200200 out << "\nlibhidl \\"
201 << "\nlibhwbinder \\"
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700202 << "\nlibutils \\";
203
204 for (const auto &importedPackage : importedPackages) {
205 out << "\n" << makeLibraryName(importedPackage) << " \\";
206 }
207 out << "\n";
208 out.unindent();
209
210 out << "\ninclude $(BUILD_SHARED_LIBRARY)\n";
Andreas Huberd2943e12016-08-05 11:59:31 -0700211
212 return OK;
213}
214
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700215OutputHandler::ValRes validateForMakefile(const FQName &fqName) {
216 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700217 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700218 return OutputHandler::FAILED;
219 }
220
221 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700222 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700223 return OutputHandler::FAILED;
224 }
225
226 if (!fqName.name().empty()) {
227 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700228 "ERROR: Expecting only package name and version.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700229 return OutputHandler::FAILED;
230 }
231
232 return OutputHandler::PASS_PACKAGE;
233}
234
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700235OutputHandler::ValRes validateForSource(const FQName &fqName) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700236 if (fqName.package().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700237 fprintf(stderr, "ERROR: Expecting package name\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700238 return OutputHandler::FAILED;
239 }
240
241 if (fqName.version().empty()) {
Andreas Huber70a59e12016-08-16 12:57:01 -0700242 fprintf(stderr, "ERROR: Expecting package version\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700243 return OutputHandler::FAILED;
244 }
245
246 return fqName.name().empty() ?
247 OutputHandler::PASS_PACKAGE :
248 OutputHandler::PASS_FULL;
249}
250
251static std::vector<OutputHandler> formats = {
252 {"c++",
Andreas Huber2831d512016-08-15 09:33:47 -0700253 true /* mNeedsOutputDir */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700254 validateForSource,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700255 [](const FQName &fqName,
256 const char *hidl_gen, Coordinator *coordinator,
257 const std::string &outputDir) -> status_t {
258 if (fqName.isFullyQualified()) {
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700259 return generateSourcesForFile(fqName,
260 hidl_gen,
261 coordinator,
262 outputDir, "c++");
263 } else {
264 return generateSourcesForPackage(fqName,
265 hidl_gen,
266 coordinator,
267 outputDir, "c++");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700268 }
269 }
270 },
271
Andreas Huber2831d512016-08-15 09:33:47 -0700272 {"java",
273 true /* mNeedsOutputDir */,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700274 validateForSource,
Andreas Huber2831d512016-08-15 09:33:47 -0700275 [](const FQName &fqName,
276 const char *hidl_gen, Coordinator *coordinator,
277 const std::string &outputDir) -> status_t {
278 if (fqName.isFullyQualified()) {
279 return generateSourcesForFile(fqName,
280 hidl_gen,
281 coordinator,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700282 outputDir, "java");
Andreas Huber2831d512016-08-15 09:33:47 -0700283 }
284 else {
285 return generateSourcesForPackage(fqName,
286 hidl_gen,
287 coordinator,
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700288 outputDir, "java");
Andreas Huber2831d512016-08-15 09:33:47 -0700289 }
290 }
291 },
292
Zhuoyao Zhang5158db42016-08-10 10:25:20 -0700293 {"vts",
294 true,
295 validateForSource,
296 [](const FQName &fqName,
297 const char * hidl_gen,
298 Coordinator *coordinator,
299 const std::string &outputDir) -> status_t {
300 if (fqName.isFullyQualified()) {
301 return generateSourcesForFile(fqName,
302 hidl_gen,
303 coordinator,
304 outputDir, "vts");
305 } else {
306 return generateSourcesForPackage(fqName,
307 hidl_gen,
308 coordinator,
309 outputDir, "vts");
310 }
311 }
312 },
313
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700314 {"makefile",
Andreas Huber2831d512016-08-15 09:33:47 -0700315 false /* mNeedsOutputDir */,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700316 validateForMakefile,
317 generateMakefileForPackage,
318 },
319};
320
321static void usage(const char *me) {
322 fprintf(stderr,
323 "usage: %s -o output-path -L <language> (-r interface-root)+ fqname+\n",
324 me);
325
326 fprintf(stderr, " -o output path\n");
327
328 fprintf(stderr, " -L <language> (one of");
329 for (auto &e : formats) {
330 fprintf(stderr, " %s", e.mKey.c_str());
331 }
332 fprintf(stderr, ")\n");
333
334 fprintf(stderr,
335 " -r package:path root "
336 "(e.g., android.hardware:hardware/interfaces)\n");
337}
338
Andreas Huberb82318c2016-08-02 14:45:54 -0700339int main(int argc, char **argv) {
340 std::string outputDir;
Andreas Huberdca261f2016-08-04 13:47:51 -0700341 std::vector<std::string> packageRootPaths;
342 std::vector<std::string> packageRoots;
Andreas Huberb82318c2016-08-02 14:45:54 -0700343
Andreas Huber737080b2016-08-02 15:38:04 -0700344 const char *me = argv[0];
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700345 OutputHandler *outputFormat = nullptr;
Andreas Huber737080b2016-08-02 15:38:04 -0700346
Andreas Huberb82318c2016-08-02 14:45:54 -0700347 int res;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700348 while ((res = getopt(argc, argv, "ho:r:L:")) >= 0) {
Andreas Huberb82318c2016-08-02 14:45:54 -0700349 switch (res) {
350 case 'o':
351 {
352 outputDir = optarg;
353 break;
354 }
355
Andreas Huberdca261f2016-08-04 13:47:51 -0700356 case 'r':
357 {
358 std::string val(optarg);
359 auto index = val.find_first_of(':');
360 CHECK(index != std::string::npos);
361
362 auto package = val.substr(0, index);
363 auto path = val.substr(index + 1);
364 packageRootPaths.push_back(path);
365 packageRoots.push_back(package);
366 break;
367 }
368
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700369 case 'L':
370 {
371 CHECK(outputFormat == nullptr); // only one -L option
372 for (auto &e : formats) {
373 if (e.mKey == optarg) {
374 outputFormat = &e;
375 break;
376 }
377 }
378 CHECK(outputFormat != nullptr);
379 break;
380 }
381
Andreas Huberb82318c2016-08-02 14:45:54 -0700382 case '?':
383 case 'h':
384 default:
385 {
Andreas Huber737080b2016-08-02 15:38:04 -0700386 usage(me);
Andreas Huberb82318c2016-08-02 14:45:54 -0700387 exit(1);
388 break;
389 }
390 }
391 }
392
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700393 if (outputFormat == nullptr) {
394 usage(me);
395 exit(1);
396 }
397
Andreas Huberb82318c2016-08-02 14:45:54 -0700398 argc -= optind;
399 argv += optind;
400
Andreas Huberdca261f2016-08-04 13:47:51 -0700401 if (packageRootPaths.empty()) {
402 // Pick reasonable defaults.
403
404 packageRoots.push_back("android.hardware");
405
406 const char *TOP = getenv("TOP");
407 CHECK(TOP != NULL);
408
409 std::string path = TOP;
410 path.append("/hardware/interfaces");
411
412 packageRootPaths.push_back(path);
413 }
414
Andreas Huber737080b2016-08-02 15:38:04 -0700415 // Valid options are now in argv[0] .. argv[argc - 1].
416
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700417 if (!outputFormat->mNeedsOutputDir) {
Andreas Huberd2943e12016-08-05 11:59:31 -0700418 outputDir.clear(); // Unused.
419 } else if (outputDir.empty()) {
Andreas Huber737080b2016-08-02 15:38:04 -0700420 usage(me);
Andreas Huberb82318c2016-08-02 14:45:54 -0700421 exit(1);
422 } else {
423 const size_t len = outputDir.size();
424 if (outputDir[len - 1] != '/') {
425 outputDir += "/";
426 }
427 }
428
Andreas Huberdca261f2016-08-04 13:47:51 -0700429 Coordinator coordinator(packageRootPaths, packageRoots);
Andreas Huber5345ec22016-07-29 13:33:27 -0700430
Andreas Huber737080b2016-08-02 15:38:04 -0700431 for (int i = 0; i < argc; ++i) {
Andreas Huber68f24592016-07-29 14:53:48 -0700432 FQName fqName(argv[i]);
Andreas Huber68f24592016-07-29 14:53:48 -0700433
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700434 if (!fqName.isValid()) {
Andreas Hubere61e3f72016-08-03 10:22:03 -0700435 fprintf(stderr,
Andreas Huber70a59e12016-08-16 12:57:01 -0700436 "ERROR: Invalid fully-qualified name.\n");
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700437 exit(1);
438 }
Andreas Huber881227d2016-08-02 14:20:21 -0700439
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700440 OutputHandler::ValRes valid = outputFormat->validate(fqName);
441 if (valid == OutputHandler::FAILED) {
Andreas Hubere61e3f72016-08-03 10:22:03 -0700442 exit(1);
443 }
Andreas Huberd2943e12016-08-05 11:59:31 -0700444
445 status_t err =
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700446 outputFormat->generate(fqName, me, &coordinator, outputDir);
Andreas Huberd2943e12016-08-05 11:59:31 -0700447
448 if (err != OK) {
449 break;
450 }
Andreas Hubereb1081f2016-07-28 13:13:24 -0700451 }
Andreas Huberc9410c72016-07-28 12:18:40 -0700452
Andreas Huberd2943e12016-08-05 11:59:31 -0700453 return 0;
Andreas Huberc9410c72016-07-28 12:18:40 -0700454}