extends nuhidl-gen to optionally generate an Android.mk makefile that
produces a shared-library module exporting the necessary header, stub and
proxy code for the packages specified.
diff --git a/main.cpp b/main.cpp
index 4059202..eef9e55 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,5 +1,6 @@
#include "AST.h"
#include "Coordinator.h"
+#include "Formatter.h"
#include "FQName.h"
#include <android-base/logging.h>
@@ -12,26 +13,173 @@
static void usage(const char *me) {
fprintf(stderr,
- "usage: %s -o output-path (-r interface-root)+ fqname+\n",
+ "usage: %s -o output-path [-m] (-r interface-root)+ fqname+\n",
me);
fprintf(stderr, " -o output path\n");
+ fprintf(stderr, " -m generate makefile instead of sources\n");
fprintf(stderr,
" -r package:path root "
"(e.g., android.hardware:hardware/interfaces)\n");
}
+static std::string makeLibraryName(const FQName &packageFQName) {
+ std::vector<std::string> components;
+ packageFQName.getPackageAndVersionComponents(
+ &components, true /* cpp_compatible */);
+
+ const std::string libraryName =
+ "lib_" + FQName::JoinStrings(components, "_");
+
+ return libraryName;
+}
+
+static status_t generateMakefileOrSourcesForPackage(
+ Coordinator *coordinator,
+ const std::string &outputDir,
+ bool createMakefile,
+ const FQName &packageFQName) {
+ std::vector<FQName> packageInterfaces;
+
+ status_t err =
+ coordinator->getPackageInterfaces(packageFQName, &packageInterfaces);
+
+ if (err != OK) {
+ return err;
+ }
+
+ std::set<FQName> importedPackages;
+ for (const auto &fqName : packageInterfaces) {
+ AST *ast = coordinator->parse(fqName);
+
+ if (ast == NULL) {
+ fprintf(stderr,
+ "Could not parse %s. Aborting.\n",
+ fqName.string().c_str());
+
+ return UNKNOWN_ERROR;
+ }
+
+ if (!createMakefile) {
+ status_t err = ast->generateCpp(outputDir);
+
+ if (err != OK) {
+ return err;
+ }
+ } else {
+ ast->addImportedPackages(&importedPackages);
+ }
+ }
+
+ if (!createMakefile) {
+ return OK;
+ }
+
+ std::string path =
+ coordinator->getPackagePath(packageFQName, false /* relative */);
+
+ path.append("Android.mk");
+
+ CHECK(Coordinator::MakeParentHierarchy(path));
+ FILE *file = fopen(path.c_str(), "w");
+
+ if (file == NULL) {
+ return -errno;
+ }
+
+ const std::string libraryName = makeLibraryName(packageFQName);
+
+ Formatter out(file);
+
+ out << "LOCAL_PATH := $(call my-dir)\n"
+ << "include $(CLEAR_VARS)\n\n"
+ << "LOCAL_MODULE := "
+ << libraryName
+ << "\n"
+ << "LOCAL_MODULE_CLASS := SHARED_LIBRARIES\n\n"
+ << "intermediates := $(local-generated-sources-dir)\n\n"
+ << "GEN := \\\n";
+
+ out.indent();
+ for (const auto &fqName : packageInterfaces) {
+ out << "$(intermediates)/"
+ << coordinator->convertPackageRootToPath(packageFQName)
+ << coordinator->getPackagePath(packageFQName, true /* relative */);
+
+ if (fqName.name() == "types") {
+ out << "types.cpp";
+ } else {
+ out << fqName.name().substr(1) << "All.cpp";
+ }
+
+ out << " \\\n";
+ }
+
+ out.unindent();
+
+ out << "\n$(GEN): PRIVATE_OUTPUT_DIR := $(intermediates)\n\n"
+ << "$(GEN): PRIVATE_CUSTOM_TOOL = \\\n";
+
+ out.indent();
+
+ out << "nuhidl-gen -o $(PRIVATE_OUTPUT_DIR) "
+ << packageFQName.string()
+ << "\n";
+
+ out.unindent();
+
+ out << "\n$(GEN): ";
+
+ bool first = true;
+ for (const auto &fqName : packageInterfaces) {
+ if (!first) {
+ out << " ";
+ }
+
+ out << "$(LOCAL_PATH)/" << fqName.name() << ".hal";
+
+ first = false;
+ }
+ out << "\n\t$(transform-generated-source)\n\n";
+
+ out << "LOCAL_GENERATED_SOURCES += $(GEN)\n\n"
+ << "LOCAL_EXPORT_C_INCLUDE_DIRS := $(intermediates)\n\n"
+ << "LOCAL_SHARED_LIBRARIES := \\\n";
+
+ out.indent();
+ out << "libhwbinder \\\n"
+ << "libutils \\\n";
+
+ for (const auto &importedPackage : importedPackages) {
+ out << makeLibraryName(importedPackage) << " \\\n";
+ }
+
+ out.unindent();
+
+ out << "\n"
+ << "include $(BUILD_SHARED_LIBRARY)\n";
+
+ return OK;
+}
+
int main(int argc, char **argv) {
std::string outputDir;
std::vector<std::string> packageRootPaths;
std::vector<std::string> packageRoots;
+ bool createMakefile = false;
const char *me = argv[0];
int res;
- while ((res = getopt(argc, argv, "ho:r:")) >= 0) {
+ while ((res = getopt(argc, argv, "hmo:r:")) >= 0) {
switch (res) {
+ case 'm':
+ {
+ createMakefile = true;
+ break;
+ }
+
case 'o':
{
outputDir = optarg;
@@ -81,7 +229,9 @@
// Valid options are now in argv[0] .. argv[argc - 1].
- if (outputDir.empty()) {
+ if (createMakefile) {
+ outputDir.clear(); // Unused.
+ } else if (outputDir.empty()) {
usage(me);
exit(1);
} else {
@@ -95,25 +245,25 @@
for (int i = 0; i < argc; ++i) {
FQName fqName(argv[i]);
- CHECK(fqName.isValid() && fqName.isFullyQualified());
- AST *ast = coordinator.parse(fqName);
-
- if (ast == NULL) {
+ if (!fqName.isValid()
+ || fqName.package().empty()
+ || fqName.version().empty()
+ || !fqName.name().empty()) {
fprintf(stderr,
- "Could not parse %s. Aborting.\n",
- fqName.string().c_str());
+ "Each fqname argument should specify a valid package.\n");
exit(1);
}
+
+ status_t err =
+ generateMakefileOrSourcesForPackage(
+ &coordinator, outputDir, createMakefile, fqName);
+
+ if (err != OK) {
+ break;
+ }
}
- // Now that we've found the transitive hull of all necessary interfaces
- // and types to process, go ahead and do the work.
- status_t err = coordinator.forEachAST(
- [&](const AST *ast) {
- return ast->generateCpp(outputDir);
- });
-
- return (err == OK) ? 0 : 1;
+ return 0;
}