diff options
author | Derek Bailey <derekbailey@google.com> | 2023-01-08 15:01:33 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-01-08 15:01:33 -0800 |
commit | 3b8644d32c50e86872584829af4b8caf180235ab (patch) | |
tree | ed48a7cc7106470cfa9d1eb775d5b2d76d1bc1cd /src | |
parent | 641fbe46583c04c56bf33284ceb7971102ea4583 (diff) | |
download | flatbuffers-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.cpp | 107 | ||||
-rw-r--r-- | src/flatc_main.cpp | 9 | ||||
-rw-r--r-- | src/idl_gen_cpp.cpp | 47 |
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 |