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/AST.cpp b/AST.cpp
index 555f084..a1fab37 100644
--- a/AST.cpp
+++ b/AST.cpp
@@ -393,4 +393,9 @@
return iface->isJavaCompatible();
}
+void AST::appendToExportedTypesVector(
+ std::vector<const Type *> *exportedTypes) const {
+ mRootScope->appendToExportedTypesVector(exportedTypes);
+}
+
} // namespace android;
diff --git a/AST.h b/AST.h
index 88f2a43..33c41e1 100644
--- a/AST.h
+++ b/AST.h
@@ -99,6 +99,9 @@
return mImportedNames;
}
+ void appendToExportedTypesVector(
+ std::vector<const Type *> *exportedTypes) const;
+
private:
Coordinator *mCoordinator;
std::string mPath;
diff --git a/Annotation.cpp b/Annotation.cpp
index 62a7563..d3b4d01 100644
--- a/Annotation.cpp
+++ b/Annotation.cpp
@@ -56,7 +56,7 @@
return *mParams;
}
-const AnnotationParam *Annotation::getParam(const std::string &name) {
+const AnnotationParam *Annotation::getParam(const std::string &name) const {
for (auto *i: *mParams) {
if (i->getName() == name) {
return i;
diff --git a/Annotation.h b/Annotation.h
index f2826a0..063b8e4 100644
--- a/Annotation.h
+++ b/Annotation.h
@@ -49,7 +49,7 @@
std::string name() const;
const AnnotationParamVector ¶ms() const;
- const AnnotationParam *getParam(const std::string &name);
+ const AnnotationParam *getParam(const std::string &name) const;
void dump(Formatter &out) const;
diff --git a/EnumType.cpp b/EnumType.cpp
index efc0f08..5a8706b 100644
--- a/EnumType.cpp
+++ b/EnumType.cpp
@@ -16,6 +16,7 @@
#include "EnumType.h"
+#include "Annotation.h"
#include "ScalarType.h"
#include <inttypes.h>
@@ -286,6 +287,86 @@
mStorageType->getAlignmentAndSize(align, size);
}
+const Annotation *EnumType::findExportAnnotation() const {
+ for (const auto &annotation : annotations()) {
+ if (annotation->name() == "export") {
+ return annotation;
+ }
+ }
+
+ return nullptr;
+}
+
+void EnumType::appendToExportedTypesVector(
+ std::vector<const Type *> *exportedTypes) const {
+ if (findExportAnnotation() != nullptr) {
+ exportedTypes->push_back(this);
+ }
+}
+
+status_t EnumType::emitExportedHeader(Formatter &out) const {
+ const Annotation *annotation = findExportAnnotation();
+ CHECK(annotation != nullptr);
+
+ std::string name = localName();
+
+ const AnnotationParam *nameParam = annotation->getParam("name");
+ if (nameParam != nullptr) {
+ CHECK_EQ(nameParam->getValues()->size(), 1u);
+
+ std::string quotedString = nameParam->getValues()->at(0);
+ name = quotedString.substr(1, quotedString.size() - 2);
+ }
+
+ const ScalarType *scalarType = mStorageType->resolveToScalarType();
+ CHECK(scalarType != NULL);
+
+ std::string extra;
+
+ if (!name.empty()) {
+ out << "typedef ";
+ }
+
+ out << "enum {\n";
+
+ out.indent();
+
+ std::vector<const EnumType *> chain;
+ getTypeChain(&chain);
+
+ for (auto it = chain.rbegin(); it != chain.rend(); ++it) {
+ const auto &type = *it;
+
+ for (const auto &entry : type->values()) {
+ out << entry->name();
+
+ std::string value = entry->cppValue(scalarType->getKind());
+ CHECK(!value.empty()); // use autofilled values for c++.
+ out << " = " << value;
+
+ out << ",";
+
+ std::string comment = entry->comment();
+ if (!comment.empty() && comment != value) {
+ out << " // " << comment;
+ }
+
+ out << "\n";
+ }
+ }
+
+ out.unindent();
+ out << "}";
+
+ if (!name.empty()) {
+ out << " " << name;
+ }
+
+ out << ";\n\n";
+
+ return OK;
+}
+
////////////////////////////////////////////////////////////////////////////////
EnumValue::EnumValue(const char *name, ConstantExpression *value)
diff --git a/EnumType.h b/EnumType.h
index 8090e92..1e6a334 100644
--- a/EnumType.h
+++ b/EnumType.h
@@ -79,8 +79,15 @@
void getAlignmentAndSize(size_t *align, size_t *size) const override;
+ void appendToExportedTypesVector(
+ std::vector<const Type *> *exportedTypes) const override;
+
+ status_t emitExportedHeader(Formatter &out) const override;
+
private:
void getTypeChain(std::vector<const EnumType *> *out) const;
+ const Annotation *findExportAnnotation() const;
+
std::vector<EnumValue *> mValues;
Type *mStorageType;
diff --git a/Scope.cpp b/Scope.cpp
index 92b9858..452a41f 100644
--- a/Scope.cpp
+++ b/Scope.cpp
@@ -191,6 +191,13 @@
return true;
}
+void Scope::appendToExportedTypesVector(
+ std::vector<const Type *> *exportedTypes) const {
+ for (const NamedType *type : mTypes) {
+ type->appendToExportedTypesVector(exportedTypes);
+ }
+}
+
LocalIdentifier::LocalIdentifier(){}
LocalIdentifier::~LocalIdentifier(){}
diff --git a/Scope.h b/Scope.h
index 6365bb4..08683dd 100644
--- a/Scope.h
+++ b/Scope.h
@@ -65,6 +65,9 @@
bool isJavaCompatible() const override;
+ void appendToExportedTypesVector(
+ std::vector<const Type *> *exportedTypes) const override;
+
private:
std::vector<NamedType *> mTypes;
std::map<std::string, size_t> mTypeIndexByName;
diff --git a/Type.cpp b/Type.cpp
index 54f5956..5c65a3e 100644
--- a/Type.cpp
+++ b/Type.cpp
@@ -390,6 +390,14 @@
CHECK(!"Should not be here");
}
+void Type::appendToExportedTypesVector(
+ std::vector<const Type *> * /* exportedTypes */) const {
+}
+
+status_t Type::emitExportedHeader(Formatter & /* out */) const {
+ return OK;
+}
+
////////////////////////////////////////
TemplatedType::TemplatedType() : mElementType(nullptr) {
diff --git a/Type.h b/Type.h
index b693b5f..da97f80 100644
--- a/Type.h
+++ b/Type.h
@@ -188,6 +188,11 @@
void setAnnotations(std::vector<Annotation *> *annotations);
const std::vector<Annotation *> &annotations() const;
+ virtual void appendToExportedTypesVector(
+ std::vector<const Type *> *exportedTypes) const;
+
+ virtual status_t emitExportedHeader(Formatter &out) const;
+
protected:
void handleError(Formatter &out, ErrorMode mode) const;
void handleError2(Formatter &out, ErrorMode mode) const;
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);