From 94d5f1236986103d03582b0e53e4daef0760bf93 Mon Sep 17 00:00:00 2001 From: h-vetinari <h.vetinari@gmx.com> Date: Wed, 12 Jun 2024 08:24:41 -0700 Subject: [PATCH] Adding DLL export/import tags to generated public upb API (redux) (#17079) Picking up #14981 from @dawidcha after several months of radio silence. Quoting the OP of that PR: > I have been collaborating with the grpc developers to make it possible to build that library as a Windows DLL - a couple of PRs were already merged, more like [grpc/grpc#34345](https://github.com/grpc/grpc/pull/34345) are pending. > > The grpc library incorporates some upb-generated, and upbdefs-generated code into grpc.dll, which is referenced by other code that consumes the library. Since this is now a DLL, that code doesn't know how to link to these generated symbols because they are not annotated with __declspec(dllimport). > > This PR aims to fix that by introducing a parameter 'dllexport_tag' to the upb and upbdefs plugins. That parameter should be a string e.g. MYAPP_DLL and when set, the extern symbols are annotated with a macro with that name. This can either be set externally to __declspec(dllimport) or, as is usual practice, when compiling code into a DLL, the macro <dllexport_tag>_EXPORT (i.e. MYAPP_DLL_EXPORT) is defined, and when consuming the DLL <dllexport_tag>_IMPORT is defined if neither are defined then the MYAPP_DLL macro becomes empty string which is what you want for building a static library. > > This is a continuation of #14230 > > Fixes: #14255 Towards #13726 Closes #14981 Closes #17079 COPYBARA_INTEGRATE_REVIEW=https://github.com/protocolbuffers/protobuf/pull/17079 from h-vetinari:add_dll_tags 34927b1ddeff6bac1a36dfa7eefb414894f1a538 PiperOrigin-RevId: 642622258 --- upb_generator/common.cc | 4 +++ upb_generator/common.h | 2 ++ upb_generator/protoc-gen-upbdefs.cc | 46 +++++++++++++++++++++-------- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/upb_generator/common.cc b/upb_generator/common.cc index f7f408128e..2dbe9d7f78 100644 --- a/upb_generator/common.cc +++ b/upb_generator/common.cc @@ -63,6 +63,10 @@ std::string MessageInitName(upb::MessageDefPtr descriptor) { return MessageInit(descriptor.full_name()); } +std::string PadPrefix(absl::string_view tag) { + return tag.empty() ? "" : absl::StrCat(" ", tag); +} + std::string MessageName(upb::MessageDefPtr descriptor) { return ToCIdent(descriptor.full_name()); } diff --git a/upb_generator/common.h b/upb_generator/common.h index 42bad45cfe..ce92f4f63f 100644 --- a/upb_generator/common.h +++ b/upb_generator/common.h @@ -8,6 +8,7 @@ #ifndef UPB_GENERATOR_COMMON_H #define UPB_GENERATOR_COMMON_H +#include <string> #include <vector> #include "absl/strings/str_replace.h" @@ -64,6 +65,7 @@ std::string MessageName(upb::MessageDefPtr descriptor); std::string FileLayoutName(upb::FileDefPtr file); std::string MiniTableHeaderFilename(upb::FileDefPtr file); std::string CApiHeaderFilename(upb::FileDefPtr file); +std::string PadPrefix(absl::string_view tag); std::string EnumInit(upb::EnumDefPtr descriptor); diff --git a/upb_generator/protoc-gen-upbdefs.cc b/upb_generator/protoc-gen-upbdefs.cc index 6ee6bafe9b..ac1b3e4d59 100644 --- a/upb_generator/protoc-gen-upbdefs.cc +++ b/upb_generator/protoc-gen-upbdefs.cc @@ -18,6 +18,10 @@ namespace upb { namespace generator { namespace { +struct Options { + std::string dllexport_decl; +}; + std::string DefInitSymbol(upb::FileDefPtr file) { return ToCIdent(file.name()) + "_upbdefinit"; } @@ -39,7 +43,8 @@ void GenerateMessageDefAccessor(upb::MessageDefPtr d, Output& output) { output("\n"); } -void WriteDefHeader(upb::FileDefPtr file, Output& output) { +void WriteDefHeader(upb::FileDefPtr file, const Options& options, + Output& output) { EmitFileWarning(file.name(), output); output( @@ -54,7 +59,8 @@ void WriteDefHeader(upb::FileDefPtr file, Output& output) { "#endif\n\n", ToPreproc(file.name())); - output("extern _upb_DefPool_Init $0;\n", DefInitSymbol(file)); + output("extern$1 _upb_DefPool_Init $0;\n", DefInitSymbol(file), + PadPrefix(options.dllexport_decl)); output("\n"); for (auto msg : SortedMessages(file)) { @@ -72,7 +78,8 @@ void WriteDefHeader(upb::FileDefPtr file, Output& output) { ToPreproc(file.name())); } -void WriteDefSource(upb::FileDefPtr file, Output& output) { +void WriteDefSource(upb::FileDefPtr file, const Options& options, + Output& output) { EmitFileWarning(file.name(), output); output("#include \"upb/reflection/def.h\"\n"); @@ -81,7 +88,9 @@ void WriteDefSource(upb::FileDefPtr file, Output& output) { output("\n"); for (int i = 0; i < file.dependency_count(); i++) { - output("extern _upb_DefPool_Init $0;\n", DefInitSymbol(file.dependency(i))); + output("extern$1 _upb_DefPool_Init $0;\n", + DefInitSymbol(file.dependency(i)), + PadPrefix(options.dllexport_decl)); } upb::Arena arena; @@ -123,29 +132,40 @@ void WriteDefSource(upb::FileDefPtr file, Output& output) { output("};\n"); } -void GenerateFile(upb::FileDefPtr file, Plugin* plugin) { +void GenerateFile(upb::FileDefPtr file, const Options& options, + Plugin* plugin) { Output h_def_output; - WriteDefHeader(file, h_def_output); + WriteDefHeader(file, options, h_def_output); plugin->AddOutputFile(DefHeaderFilename(file), h_def_output.output()); Output c_def_output; - WriteDefSource(file, c_def_output); + WriteDefSource(file, options, c_def_output); plugin->AddOutputFile(DefSourceFilename(file), c_def_output.output()); } +bool ParseOptions(Plugin* plugin, Options* options) { + for (const auto& pair : ParseGeneratorParameter(plugin->parameter())) { + if (pair.first == "dllexport_decl") { + options->dllexport_decl = pair.second; + } else { + plugin->SetError(absl::Substitute("Unknown parameter: $0", pair.first)); + return false; + } + } + + return true; +} + } // namespace } // namespace generator } // namespace upb int main(int argc, char** argv) { upb::generator::Plugin plugin; - if (!plugin.parameter().empty()) { - plugin.SetError( - absl::StrCat("Expected no parameters, got: ", plugin.parameter())); - return 0; - } + upb::generator::Options options; + if (!ParseOptions(&plugin, &options)) return 0; plugin.GenerateFiles([&](upb::FileDefPtr file) { - upb::generator::GenerateFile(file, &plugin); + upb::generator::GenerateFile(file, options, &plugin); }); return 0; }