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 34927b1dde
PiperOrigin-RevId: 642622258
pull/17105/head
h-vetinari 9 months ago committed by Copybara-Service
parent a9387b5016
commit 94d5f12369
  1. 4
      upb_generator/common.cc
  2. 2
      upb_generator/common.h
  3. 46
      upb_generator/protoc-gen-upbdefs.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());
}

@ -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);

@ -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;
}

Loading…
Cancel
Save