summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDerek Bailey <derekbailey@google.com>2023-01-08 15:01:33 -0800
committerGitHub <noreply@github.com>2023-01-08 15:01:33 -0800
commit3b8644d32c50e86872584829af4b8caf180235ab (patch)
treeed48a7cc7106470cfa9d1eb775d5b2d76d1bc1cd /src
parent641fbe46583c04c56bf33284ceb7971102ea4583 (diff)
downloadflatbuffers-3b8644d32c50e86872584829af4b8caf180235ab.tar.gz
flatbuffers-3b8644d32c50e86872584829af4b8caf180235ab.tar.bz2
flatbuffers-3b8644d32c50e86872584829af4b8caf180235ab.zip
Defined CodeGenerator Interface and implement C++ (#7771)
Diffstat (limited to 'src')
-rw-r--r--src/flatc.cpp107
-rw-r--r--src/flatc_main.cpp9
-rw-r--r--src/idl_gen_cpp.cpp47
3 files changed, 152 insertions, 11 deletions
diff --git a/src/flatc.cpp b/src/flatc.cpp
index 4827ee77..c61efd4c 100644
--- a/src/flatc.cpp
+++ b/src/flatc.cpp
@@ -24,6 +24,7 @@
#include "annotated_binary_text_gen.h"
#include "binary_annotator.h"
+#include "flatbuffers/code_generator.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
@@ -308,6 +309,7 @@ std::string FlatCompiler::GetShortUsageString(
const std::string &program_name) const {
std::stringstream ss;
ss << "Usage: " << program_name << " [";
+ // TODO(derekbailey): These should be generated from this.generators
for (size_t i = 0; i < params_.num_generators; ++i) {
const Generator &g = params_.generators[i];
AppendShortOption(ss, g.option);
@@ -330,6 +332,7 @@ std::string FlatCompiler::GetUsageString(
std::stringstream ss;
ss << "Usage: " << program_name
<< " [OPTION]... FILE... [-- BINARY_FILE...]\n";
+ // TODO(derekbailey): These should be generated from this.generators
for (size_t i = 0; i < params_.num_generators; ++i) {
const Generator &g = params_.generators[i];
AppendOption(ss, g.option, 80, 25);
@@ -613,20 +616,41 @@ FlatCOptions FlatCompiler::ParseFromCommandLineArguments(int argc,
if (++argi >= argc) Error("missing path following: " + arg, true);
options.annotate_schema = flatbuffers::PosixPath(argv[argi]);
} else {
- for (size_t i = 0; i < params_.num_generators; ++i) {
- if (arg == "--" + params_.generators[i].option.long_opt ||
- arg == "-" + params_.generators[i].option.short_opt) {
- options.generator_enabled[i] = true;
- options.any_generator = true;
- opts.lang_to_generate |= params_.generators[i].lang;
- if (params_.generators[i].bfbs_generator) {
- opts.binary_schema_comments = true;
- options.requires_bfbs = true;
+ // Look up if the command line argument refers to a code generator.
+ auto code_generator_it = code_generators_.find(arg);
+ if (code_generator_it != code_generators_.end()) {
+ std::shared_ptr<CodeGenerator> code_generator =
+ code_generator_it->second;
+
+ // TODO(derekbailey): remove in favor of just checking if
+ // generators.empty().
+ options.any_generator = true;
+ opts.lang_to_generate |= code_generator->Language();
+
+ if (code_generator->SupportsBfbsGeneration()) {
+ opts.binary_schema_comments = true;
+ options.requires_bfbs = true;
+ }
+
+ options.generators.push_back(std::move(code_generator));
+ } else {
+ // TODO(derekbailey): deprecate the following logic in favor of the
+ // code generator map above.
+ for (size_t i = 0; i < params_.num_generators; ++i) {
+ if (arg == "--" + params_.generators[i].option.long_opt ||
+ arg == "-" + params_.generators[i].option.short_opt) {
+ options.generator_enabled[i] = true;
+ options.any_generator = true;
+ opts.lang_to_generate |= params_.generators[i].lang;
+ if (params_.generators[i].bfbs_generator) {
+ opts.binary_schema_comments = true;
+ options.requires_bfbs = true;
+ }
+ goto found;
}
- goto found;
}
+ Error("unknown commandline argument: " + arg, true);
}
- Error("unknown commandline argument: " + arg, true);
found:;
}
@@ -789,6 +813,57 @@ std::unique_ptr<Parser> FlatCompiler::GenerateCode(const FlatCOptions &options,
bfbs_length = parser->builder_.GetSize();
}
+ for (const std::shared_ptr<CodeGenerator> &code_generator :
+ options.generators) {
+ if (options.print_make_rules) {
+ std::string make_rule;
+ const CodeGenerator::Status status = code_generator->GenerateMakeRule(
+ *parser, options.output_path, filename, make_rule);
+ if (status == CodeGenerator::Status::OK && !make_rule.empty()) {
+ printf("%s\n",
+ flatbuffers::WordWrap(make_rule, 80, " ", " \\").c_str());
+ } else {
+ Error("Cannot generate make rule for " +
+ code_generator->LanguageName());
+ }
+ } else {
+ flatbuffers::EnsureDirExists(options.output_path);
+
+ // Prefer bfbs generators if present.
+ if (code_generator->SupportsBfbsGeneration()) {
+ const CodeGenerator::Status status =
+ code_generator->GenerateCode(bfbs_buffer, bfbs_length);
+ if (status != CodeGenerator::Status::OK) {
+ Error("Unable to generate " + code_generator->LanguageName() +
+ " for " + filebase + " using bfbs generator.");
+ }
+ } else {
+ if ((!code_generator->IsSchemaOnly() ||
+ (is_schema || is_binary_schema)) &&
+ code_generator->GenerateCode(*parser, options.output_path,
+ filebase) !=
+ CodeGenerator::Status::OK) {
+ Error("Unable to generate " + code_generator->LanguageName() +
+ " for " + filebase);
+ }
+ }
+ }
+
+ if (options.grpc_enabled) {
+ const CodeGenerator::Status status = code_generator->GenerateGrpcCode(
+ *parser, options.output_path, filebase);
+
+ if (status == CodeGenerator::Status::NOT_IMPLEMENTED) {
+ Warn("GRPC interface generator not implemented for " +
+ code_generator->LanguageName());
+ } else if (status == CodeGenerator::Status::ERROR) {
+ Error("Unable to generate GRPC interface for " +
+ code_generator->LanguageName());
+ }
+ }
+ }
+
+ // TODO(derekbailey): Deprecate the following in favor to the above.
for (size_t i = 0; i < params_.num_generators; ++i) {
if (options.generator_enabled[i]) {
if (!options.print_make_rules) {
@@ -934,4 +1009,14 @@ int FlatCompiler::Compile(const FlatCOptions &options) {
return 0;
}
+bool FlatCompiler::RegisterCodeGenerator(
+ const std::string &flag, std::shared_ptr<CodeGenerator> code_generator) {
+ if (code_generators_.find(flag) != code_generators_.end()) {
+ Error("multiple generators registered under: " + flag, false, false);
+ return false;
+ }
+ code_generators_[flag] = std::move(code_generator);
+ return true;
+}
+
} // namespace flatbuffers
diff --git a/src/flatc_main.cpp b/src/flatc_main.cpp
index dc9e3625..5092c29f 100644
--- a/src/flatc_main.cpp
+++ b/src/flatc_main.cpp
@@ -20,9 +20,12 @@
#include "bfbs_gen_lua.h"
#include "bfbs_gen_nim.h"
#include "flatbuffers/base.h"
+#include "flatbuffers/code_generator.h"
#include "flatbuffers/flatc.h"
#include "flatbuffers/util.h"
+
+
static const char *g_program_name = nullptr;
static void Warn(const flatbuffers::FlatCompiler *flatc,
@@ -159,6 +162,12 @@ int main(int argc, const char *argv[]) {
flatbuffers::FlatCompiler flatc(params);
+ std::shared_ptr<flatbuffers::CodeGenerator> cpp_generator =
+ flatbuffers::NewCppCodeGenerator();
+
+ flatc.RegisterCodeGenerator("--cpp", cpp_generator);
+ flatc.RegisterCodeGenerator("-c", cpp_generator);
+
// Create the FlatC options by parsing the command line arguments.
const flatbuffers::FlatCOptions &options =
flatc.ParseFromCommandLineArguments(argc, argv);
diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp
index 262eb1ab..ad534b64 100644
--- a/src/idl_gen_cpp.cpp
+++ b/src/idl_gen_cpp.cpp
@@ -17,6 +17,7 @@
// independent from idl_parser, since this code is not needed for most clients
#include <limits>
+#include <memory>
#include <string>
#include <unordered_set>
@@ -3871,4 +3872,50 @@ std::string CPPMakeRule(const Parser &parser, const std::string &path,
return make_rule;
}
+namespace {
+
+class CppCodeGenerator : public CodeGenerator {
+ public:
+ Status GenerateCode(const Parser &parser, const std::string &path,
+ const std::string &filename) override {
+ if (!GenerateCPP(parser, path, filename)) { return Status::ERROR; }
+ return Status::OK;
+ }
+
+ // Generate code from the provided `buffer` of given `length`. The buffer is a
+ // serialized reflection.fbs.
+ Status GenerateCode(const uint8_t *buffer, int64_t length) override {
+ (void) buffer;
+ (void) length;
+ return Status::NOT_IMPLEMENTED;
+ }
+
+ Status GenerateMakeRule(const Parser &parser, const std::string &path,
+ const std::string &filename,
+ std::string &output) override {
+ output = CPPMakeRule(parser, path, filename);
+ return Status::OK;
+ }
+
+ Status GenerateGrpcCode(const Parser &parser, const std::string &path,
+ const std::string &filename) override {
+ if (!GenerateCppGRPC(parser, path, filename)) { return Status::ERROR; }
+ return Status::OK;
+ }
+
+ bool IsSchemaOnly() const override { return true; }
+
+ bool SupportsBfbsGeneration() const override { return false; }
+
+ IDLOptions::Language Language() const override { return IDLOptions::kCpp; }
+
+ std::string LanguageName() const override { return "C++"; }
+};
+
+} // namespace
+
+std::unique_ptr<CodeGenerator> NewCppCodeGenerator() {
+ return std::unique_ptr<CppCodeGenerator>(new CppCodeGenerator());
+}
+
} // namespace flatbuffers