blob: 9b0bfabece83093154a6c8f3a492cdb150b1706b [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,
35 bool java = false) {
Andreas Huberdca261f2016-08-04 13:47:51 -070036
Iliyan Malchev5bb14022016-08-09 15:04:39 -070037 CHECK(fqName.isFullyQualified());
38
39 AST *ast = coordinator->parse(fqName);
40
41 if (ast == NULL) {
42 fprintf(stderr,
43 "Could not parse %s. Aborting.\n",
44 fqName.string().c_str());
45
46 return UNKNOWN_ERROR;
47 }
48
Andreas Huber2831d512016-08-15 09:33:47 -070049 status_t err =
50 java ? ast->generateJava(outputDir) : ast->generateCpp(outputDir);
Iliyan Malchev5bb14022016-08-09 15:04:39 -070051
52 return err;
53}
54
55static status_t generateSourcesForPackage(
56 const FQName &packageFQName,
57 const char *hidl_gen,
58 Coordinator *coordinator,
Andreas Huber2831d512016-08-15 09:33:47 -070059 const std::string &outputDir,
60 bool java = false) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -070061
62 CHECK(packageFQName.isValid() &&
63 !packageFQName.isFullyQualified() &&
64 packageFQName.name().empty());
65
66 std::vector<FQName> packageInterfaces;
67
68 status_t err =
69 coordinator->appendPackageInterfacesToSet(packageFQName,
70 &packageInterfaces);
71
72 if (err != OK) {
73 return err;
74 }
75
76 for (const auto &fqName : packageInterfaces) {
Andreas Huber2831d512016-08-15 09:33:47 -070077 err = generateSourcesForFile(
78 fqName, hidl_gen, coordinator, outputDir, java);
79
Iliyan Malchev5bb14022016-08-09 15:04:39 -070080 if (err != OK) {
81 return err;
82 }
83 }
84
85 return OK;
Andreas Huberb82318c2016-08-02 14:45:54 -070086}
87
Andreas Huberd2943e12016-08-05 11:59:31 -070088static std::string makeLibraryName(const FQName &packageFQName) {
Iliyan Malcheve2c595a2016-08-07 21:20:04 -070089 return packageFQName.string();
Andreas Huberd2943e12016-08-05 11:59:31 -070090}
91
Iliyan Malchev5bb14022016-08-09 15:04:39 -070092static status_t generateMakefileForPackage(
93 const FQName &packageFQName,
Iliyan Malchevb66c3992016-08-07 21:18:13 -070094 const char *hidl_gen,
Andreas Huberd2943e12016-08-05 11:59:31 -070095 Coordinator *coordinator,
Iliyan Malchev5bb14022016-08-09 15:04:39 -070096 const std::string &) {
97
98 CHECK(packageFQName.isValid() &&
99 !packageFQName.isFullyQualified() &&
100 packageFQName.name().empty());
101
Andreas Huberd2943e12016-08-05 11:59:31 -0700102 std::vector<FQName> packageInterfaces;
103
104 status_t err =
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700105 coordinator->appendPackageInterfacesToSet(packageFQName,
106 &packageInterfaces);
Andreas Huberd2943e12016-08-05 11:59:31 -0700107
108 if (err != OK) {
109 return err;
110 }
111
112 std::set<FQName> importedPackages;
113 for (const auto &fqName : packageInterfaces) {
114 AST *ast = coordinator->parse(fqName);
115
116 if (ast == NULL) {
117 fprintf(stderr,
118 "Could not parse %s. Aborting.\n",
119 fqName.string().c_str());
120
121 return UNKNOWN_ERROR;
122 }
123
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700124 ast->getImportedPackages(&importedPackages);
Andreas Huberd2943e12016-08-05 11:59:31 -0700125 }
126
127 std::string path =
128 coordinator->getPackagePath(packageFQName, false /* relative */);
129
130 path.append("Android.mk");
131
132 CHECK(Coordinator::MakeParentHierarchy(path));
133 FILE *file = fopen(path.c_str(), "w");
134
135 if (file == NULL) {
136 return -errno;
137 }
138
139 const std::string libraryName = makeLibraryName(packageFQName);
140
141 Formatter out(file);
142
143 out << "LOCAL_PATH := $(call my-dir)\n"
144 << "include $(CLEAR_VARS)\n\n"
145 << "LOCAL_MODULE := "
146 << libraryName
147 << "\n"
148 << "LOCAL_MODULE_CLASS := SHARED_LIBRARIES\n\n"
149 << "intermediates := $(local-generated-sources-dir)\n\n"
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700150 << "HIDL := $(HOST_OUT_EXECUTABLES)/"
151 << hidl_gen << "$(HOST_EXECUTABLE_SUFFIX)";
Andreas Huberd2943e12016-08-05 11:59:31 -0700152
Andreas Huberd2943e12016-08-05 11:59:31 -0700153 for (const auto &fqName : packageInterfaces) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700154
155 out << "\n"
156 << "\n#"
157 << "\n# Build " << fqName.name() << ".hal"
158 << "\n#";
159 out << "\nGEN := $(intermediates)/"
Andreas Huberd2943e12016-08-05 11:59:31 -0700160 << coordinator->convertPackageRootToPath(packageFQName)
161 << coordinator->getPackagePath(packageFQName, true /* relative */);
Andreas Huberd2943e12016-08-05 11:59:31 -0700162 if (fqName.name() == "types") {
163 out << "types.cpp";
164 } else {
165 out << fqName.name().substr(1) << "All.cpp";
166 }
167
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700168 out << "\n$(GEN): $(HIDL)";
169 out << "\n$(GEN): PRIVATE_HIDL := $(HIDL)";
170 out << "\n$(GEN): PRIVATE_DEPS := $(LOCAL_PATH)/"
171 << fqName.name() << ".hal";
172 out << "\n$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)"
173 << "\n$(GEN): PRIVATE_CUSTOM_TOOL = \\";
174 out.indent();
175 out.indent();
176 out << "\n$(PRIVATE_HIDL) -o $(PRIVATE_OUTPUT_DIR) \\"
177 << "\n-Lc++ -r"
178 << coordinator->getPackageRoot(packageFQName) << ":"
179 << coordinator->getPackageRootPath(packageFQName) << "\\";
180 out << "\n"
181 << packageFQName.string()
182 << "::$(patsubst %.hal,%,$(notdir $(PRIVATE_DEPS)))"
183 << "\n";
184 out.unindent();
185 out.unindent();
186
187 out << "\n$(GEN): $(LOCAL_PATH)/" << fqName.name() << ".hal";
188 out << "\n\t$(transform-generated-source)";
189 out << "\nLOCAL_GENERATED_SOURCES += $(GEN)";
Andreas Huberd2943e12016-08-05 11:59:31 -0700190 }
191
Andreas Huberd2943e12016-08-05 11:59:31 -0700192 out << "\n"
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700193 << "\nLOCAL_EXPORT_C_INCLUDE_DIRS := $(intermediates)"
194 << "\nLOCAL_SHARED_LIBRARIES := \\";
195 out.indent();
196 out << "\nlibhwbinder \\"
197 << "\nlibutils \\";
198
199 for (const auto &importedPackage : importedPackages) {
200 out << "\n" << makeLibraryName(importedPackage) << " \\";
201 }
202 out << "\n";
203 out.unindent();
204
205 out << "\ninclude $(BUILD_SHARED_LIBRARY)\n";
Andreas Huberd2943e12016-08-05 11:59:31 -0700206
207 return OK;
208}
209
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700210OutputHandler::ValRes validateForMakefile(const FQName &fqName) {
211 if (fqName.package().empty()) {
212 fprintf(stderr, "Expecting package name\n");
213 return OutputHandler::FAILED;
214 }
215
216 if (fqName.version().empty()) {
217 fprintf(stderr, "Expecting package version\n");
218 return OutputHandler::FAILED;
219 }
220
221 if (!fqName.name().empty()) {
222 fprintf(stderr,
223 "Expecting only package name and version.\n");
224 return OutputHandler::FAILED;
225 }
226
227 return OutputHandler::PASS_PACKAGE;
228}
229
Andreas Huber2831d512016-08-15 09:33:47 -0700230OutputHandler::ValRes validateForCppOrJava(const FQName &fqName) {
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700231 if (fqName.package().empty()) {
232 fprintf(stderr, "Expecting package name\n");
233 return OutputHandler::FAILED;
234 }
235
236 if (fqName.version().empty()) {
237 fprintf(stderr, "Expecting package version\n");
238 return OutputHandler::FAILED;
239 }
240
241 return fqName.name().empty() ?
242 OutputHandler::PASS_PACKAGE :
243 OutputHandler::PASS_FULL;
244}
245
246static std::vector<OutputHandler> formats = {
247 {"c++",
Andreas Huber2831d512016-08-15 09:33:47 -0700248 true /* mNeedsOutputDir */,
249 validateForCppOrJava,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700250 [](const FQName &fqName,
251 const char *hidl_gen, Coordinator *coordinator,
252 const std::string &outputDir) -> status_t {
253 if (fqName.isFullyQualified()) {
254 return generateSourcesForFile(fqName,
255 hidl_gen,
256 coordinator,
257 outputDir);
258 }
259 else {
260 return generateSourcesForPackage(fqName,
261 hidl_gen,
262 coordinator,
263 outputDir);
264 }
265 }
266 },
267
Andreas Huber2831d512016-08-15 09:33:47 -0700268 {"java",
269 true /* mNeedsOutputDir */,
270 validateForCppOrJava,
271 [](const FQName &fqName,
272 const char *hidl_gen, Coordinator *coordinator,
273 const std::string &outputDir) -> status_t {
274 if (fqName.isFullyQualified()) {
275 return generateSourcesForFile(fqName,
276 hidl_gen,
277 coordinator,
278 outputDir,
279 true /* java */);
280 }
281 else {
282 return generateSourcesForPackage(fqName,
283 hidl_gen,
284 coordinator,
285 outputDir,
286 true /* java */);
287 }
288 }
289 },
290
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700291 {"makefile",
Andreas Huber2831d512016-08-15 09:33:47 -0700292 false /* mNeedsOutputDir */,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700293 validateForMakefile,
294 generateMakefileForPackage,
295 },
296};
297
298static void usage(const char *me) {
299 fprintf(stderr,
300 "usage: %s -o output-path -L <language> (-r interface-root)+ fqname+\n",
301 me);
302
303 fprintf(stderr, " -o output path\n");
304
305 fprintf(stderr, " -L <language> (one of");
306 for (auto &e : formats) {
307 fprintf(stderr, " %s", e.mKey.c_str());
308 }
309 fprintf(stderr, ")\n");
310
311 fprintf(stderr,
312 " -r package:path root "
313 "(e.g., android.hardware:hardware/interfaces)\n");
314}
315
Andreas Huberb82318c2016-08-02 14:45:54 -0700316int main(int argc, char **argv) {
317 std::string outputDir;
Andreas Huberdca261f2016-08-04 13:47:51 -0700318 std::vector<std::string> packageRootPaths;
319 std::vector<std::string> packageRoots;
Andreas Huberb82318c2016-08-02 14:45:54 -0700320
Andreas Huber737080b2016-08-02 15:38:04 -0700321 const char *me = argv[0];
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700322 OutputHandler *outputFormat = nullptr;
Andreas Huber737080b2016-08-02 15:38:04 -0700323
Andreas Huberb82318c2016-08-02 14:45:54 -0700324 int res;
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700325 while ((res = getopt(argc, argv, "ho:r:L:")) >= 0) {
Andreas Huberb82318c2016-08-02 14:45:54 -0700326 switch (res) {
327 case 'o':
328 {
329 outputDir = optarg;
330 break;
331 }
332
Andreas Huberdca261f2016-08-04 13:47:51 -0700333 case 'r':
334 {
335 std::string val(optarg);
336 auto index = val.find_first_of(':');
337 CHECK(index != std::string::npos);
338
339 auto package = val.substr(0, index);
340 auto path = val.substr(index + 1);
341 packageRootPaths.push_back(path);
342 packageRoots.push_back(package);
343 break;
344 }
345
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700346 case 'L':
347 {
348 CHECK(outputFormat == nullptr); // only one -L option
349 for (auto &e : formats) {
350 if (e.mKey == optarg) {
351 outputFormat = &e;
352 break;
353 }
354 }
355 CHECK(outputFormat != nullptr);
356 break;
357 }
358
Andreas Huberb82318c2016-08-02 14:45:54 -0700359 case '?':
360 case 'h':
361 default:
362 {
Andreas Huber737080b2016-08-02 15:38:04 -0700363 usage(me);
Andreas Huberb82318c2016-08-02 14:45:54 -0700364 exit(1);
365 break;
366 }
367 }
368 }
369
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700370 if (outputFormat == nullptr) {
371 usage(me);
372 exit(1);
373 }
374
Andreas Huberb82318c2016-08-02 14:45:54 -0700375 argc -= optind;
376 argv += optind;
377
Andreas Huberdca261f2016-08-04 13:47:51 -0700378 if (packageRootPaths.empty()) {
379 // Pick reasonable defaults.
380
381 packageRoots.push_back("android.hardware");
382
383 const char *TOP = getenv("TOP");
384 CHECK(TOP != NULL);
385
386 std::string path = TOP;
387 path.append("/hardware/interfaces");
388
389 packageRootPaths.push_back(path);
390 }
391
Andreas Huber737080b2016-08-02 15:38:04 -0700392 // Valid options are now in argv[0] .. argv[argc - 1].
393
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700394 if (!outputFormat->mNeedsOutputDir) {
Andreas Huberd2943e12016-08-05 11:59:31 -0700395 outputDir.clear(); // Unused.
396 } else if (outputDir.empty()) {
Andreas Huber737080b2016-08-02 15:38:04 -0700397 usage(me);
Andreas Huberb82318c2016-08-02 14:45:54 -0700398 exit(1);
399 } else {
400 const size_t len = outputDir.size();
401 if (outputDir[len - 1] != '/') {
402 outputDir += "/";
403 }
404 }
405
Andreas Huberdca261f2016-08-04 13:47:51 -0700406 Coordinator coordinator(packageRootPaths, packageRoots);
Andreas Huber5345ec22016-07-29 13:33:27 -0700407
Andreas Huber737080b2016-08-02 15:38:04 -0700408 for (int i = 0; i < argc; ++i) {
Andreas Huber68f24592016-07-29 14:53:48 -0700409 FQName fqName(argv[i]);
Andreas Huber68f24592016-07-29 14:53:48 -0700410
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700411 if (!fqName.isValid()) {
Andreas Hubere61e3f72016-08-03 10:22:03 -0700412 fprintf(stderr,
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700413 "Invalid fully-qualified name.\n");
414 exit(1);
415 }
Andreas Huber881227d2016-08-02 14:20:21 -0700416
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700417 OutputHandler::ValRes valid = outputFormat->validate(fqName);
418 if (valid == OutputHandler::FAILED) {
Andreas Hubere61e3f72016-08-03 10:22:03 -0700419 exit(1);
420 }
Andreas Huberd2943e12016-08-05 11:59:31 -0700421
422 status_t err =
Iliyan Malchev5bb14022016-08-09 15:04:39 -0700423 outputFormat->generate(fqName, me, &coordinator, outputDir);
Andreas Huberd2943e12016-08-05 11:59:31 -0700424
425 if (err != OK) {
426 break;
427 }
Andreas Hubereb1081f2016-07-28 13:13:24 -0700428 }
Andreas Huberc9410c72016-07-28 12:18:40 -0700429
Andreas Huberd2943e12016-08-05 11:59:31 -0700430 return 0;
Andreas Huberc9410c72016-07-28 12:18:40 -0700431}