Yet another backend for hidl-gen, this one generates a C-compatible header file
containing those enum types annotated in the package like so:
@export
enum Foo {
...
};
Optionally, the name to be used for the type declaration in the header file
can be different from that used in the .hal interface description by specifying
@export(name="foo_t")
enum Foo {
...
};
Finally, overriding the name to be empty, i.e.
@export(name="")
enum Foo {
...
};
will cause the generator to emit an anonymous enum.
Bug: 31800672
Change-Id: Idffb2c1700af1c7fd312941d80c3373add8ae558
Test: make
diff --git a/main.cpp b/main.cpp
index 91fc81c..b81f004 100644
--- a/main.cpp
+++ b/main.cpp
@@ -31,7 +31,12 @@
struct OutputHandler {
std::string mKey;
- bool mNeedsOutputDir;
+ enum OutputMode {
+ NEEDS_DIR,
+ NEEDS_FILE,
+ NOT_NEEDED
+ } mOutputMode;
+
enum ValRes {
FAILED,
PASS_PACKAGE,
@@ -678,9 +683,104 @@
return OutputHandler::PASS_PACKAGE;
}
+OutputHandler::ValRes validateForExportHeader(
+ const FQName &fqName, const std::string & /* language */) {
+ if (fqName.package().empty()) {
+ fprintf(stderr, "ERROR: Expecting package name\n");
+ return OutputHandler::FAILED;
+ }
+
+ if (fqName.version().empty()) {
+ fprintf(stderr, "ERROR: Expecting package version\n");
+ return OutputHandler::FAILED;
+ }
+
+ if (!fqName.name().empty()) {
+ fprintf(stderr,
+ "ERROR: Expecting only package name and version.\n");
+ return OutputHandler::FAILED;
+ }
+
+ return OutputHandler::PASS_PACKAGE;
+}
+
+
+static status_t generateExportHeaderForPackage(
+ const FQName &packageFQName,
+ const char * /* hidl_gen */,
+ Coordinator *coordinator,
+ const std::string &outputPath) {
+
+ CHECK(packageFQName.isValid()
+ && !packageFQName.isFullyQualified()
+ && packageFQName.name().empty());
+
+ std::vector<FQName> packageInterfaces;
+
+ status_t err = coordinator->appendPackageInterfacesToVector(
+ packageFQName, &packageInterfaces);
+
+ if (err != OK) {
+ return err;
+ }
+
+ std::vector<const Type *> exportedTypes;
+
+ for (const auto &fqName : packageInterfaces) {
+ AST *ast = coordinator->parse(fqName);
+
+ if (ast == NULL) {
+ fprintf(stderr,
+ "ERROR: Could not parse %s. Aborting.\n",
+ fqName.string().c_str());
+
+ return UNKNOWN_ERROR;
+ }
+
+ ast->appendToExportedTypesVector(&exportedTypes);
+ }
+
+ if (exportedTypes.empty()) {
+ return OK;
+ }
+
+ CHECK(Coordinator::MakeParentHierarchy(outputPath));
+ FILE *file = fopen(outputPath.c_str(), "w");
+
+ if (file == nullptr) {
+ return -errno;
+ }
+
+ Formatter out(file);
+
+ out << "// This file is autogenerated by hidl-gen. Do not edit manually."
+ "\n\n";
+
+ std::string guard = "HIDL_GENERATED_";
+ guard += packageFQName.tokenName();
+ guard += "_";
+ guard += "EXPORTED_CONSTANTS_H_";
+
+ out << "#ifndef "
+ << guard
+ << "\n#define "
+ << guard
+ << "\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n";
+
+ for (const auto &type : exportedTypes) {
+ type->emitExportedHeader(out);
+ }
+
+ out << "#ifdef __cplusplus\n}\n#endif\n\n#endif // "
+ << guard
+ << "\n";
+
+ return OK;
+}
+
static std::vector<OutputHandler> formats = {
{"c++",
- true /* mNeedsOutputDir */,
+ OutputHandler::NEEDS_DIR /* mOutputMode */,
validateForSource,
[](const FQName &fqName,
const char *hidl_gen, Coordinator *coordinator,
@@ -701,8 +801,25 @@
}
},
+ {"export-header",
+ OutputHandler::NEEDS_FILE /* mOutputMode */,
+ validateForExportHeader,
+ [](const FQName &fqName,
+ const char *hidl_gen,
+ Coordinator *coordinator,
+ const std::string &outputPath) -> status_t {
+ CHECK(!fqName.isFullyQualified());
+
+ return generateExportHeaderForPackage(
+ fqName,
+ hidl_gen,
+ coordinator,
+ outputPath);
+ }
+ },
+
{"c++-impl",
- true /* mNeedsOutputDir */,
+ OutputHandler::NEEDS_DIR /* mOutputMode */,
validateForSource,
[](const FQName &fqName,
const char *hidl_gen, Coordinator *coordinator,
@@ -723,7 +840,7 @@
{"java",
- true /* mNeedsOutputDir */,
+ OutputHandler::NEEDS_DIR /* mOutputMode */,
validateForSource,
[](const FQName &fqName,
const char *hidl_gen, Coordinator *coordinator,
@@ -746,7 +863,7 @@
},
{"vts",
- true,
+ OutputHandler::NEEDS_DIR /* mOutputMode */,
validateForSource,
[](const FQName &fqName,
const char * hidl_gen,
@@ -767,19 +884,19 @@
},
{"makefile",
- false /* mNeedsOutputDir */,
+ OutputHandler::NOT_NEEDED /* mOutputMode */,
validateForMakefile,
generateMakefileForPackage,
},
{"androidbp",
- false /* mNeedsOutputDir */,
+ OutputHandler::NOT_NEEDED /* mOutputMode */,
validateForMakefile,
generateAndroidBpForPackage,
},
{"makefile-impl",
- true /* mNeedsOutputDir */,
+ OutputHandler::NOT_NEEDED /* mOutputMode */,
validateForMakefile,
generateMakefileImplForPackage,
}
@@ -804,7 +921,7 @@
}
int main(int argc, char **argv) {
- std::string outputDir;
+ std::string outputPath;
std::vector<std::string> packageRootPaths;
std::vector<std::string> packageRoots;
@@ -816,7 +933,7 @@
switch (res) {
case 'o':
{
- outputDir = optarg;
+ outputPath = optarg;
break;
}
@@ -881,16 +998,27 @@
// Valid options are now in argv[0] .. argv[argc - 1].
- if (!outputFormat->mNeedsOutputDir) {
- outputDir.clear(); // Unused.
- } else if (outputDir.empty()) {
- usage(me);
- exit(1);
- } else {
- const size_t len = outputDir.size();
- if (outputDir[len - 1] != '/') {
- outputDir += "/";
+ switch (outputFormat->mOutputMode) {
+ case OutputHandler::NEEDS_DIR:
+ case OutputHandler::NEEDS_FILE:
+ {
+ if (outputPath.empty()) {
+ usage(me);
+ exit(1);
+ }
+
+ if (outputFormat->mOutputMode == OutputHandler::NEEDS_DIR) {
+ const size_t len = outputPath.size();
+ if (outputPath[len - 1] != '/') {
+ outputPath += "/";
+ }
+ }
+ break;
}
+
+ default:
+ outputPath.clear(); // Unused.
+ break;
}
Coordinator coordinator(packageRootPaths, packageRoots);
@@ -912,7 +1040,7 @@
}
status_t err =
- outputFormat->generate(fqName, me, &coordinator, outputDir);
+ outputFormat->generate(fqName, me, &coordinator, outputPath);
if (err != OK) {
exit(1);