Generate one source file per message/enum/extension on Android/iOS.
The functionality is enabled when the `proto_one_output_per_message` option used by C++ Lite is enabled.
This mirrors the behavior of C++ lite protos.
PiperOrigin-RevId: 640592937
diff --git a/bazel/private/upb_proto_library_internal/aspect.bzl b/bazel/private/upb_proto_library_internal/aspect.bzl
index 6f7b317..a247229 100644
--- a/bazel/private/upb_proto_library_internal/aspect.bzl
+++ b/bazel/private/upb_proto_library_internal/aspect.bzl
@@ -1,5 +1,6 @@
"""Implementation of the aspect that powers the upb_*_proto_library() rules."""
+load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
load("//bazel/common:proto_common.bzl", "proto_common")
load(":upb_proto_library_internal/cc_library_func.bzl", "cc_library_func")
load(":upb_proto_library_internal/copts.bzl", "UpbProtoLibraryCoptsInfo")
@@ -54,7 +55,51 @@
thunks = _concat_lists([s.thunks for s in srcs]),
)
-def _generate_upb_protos(ctx, generator, proto_info):
+def _get_implicit_weak_field_sources(ctx, proto_info):
+ # Creating one .cc file for each Message in a proto allows the linker to be more aggressive
+ # about removing unused classes. However, since the number of outputs won't be known at Blaze
+ # analysis time, all of the generated source files are put in a directory and a TreeArtifact is
+ # used to represent them.
+ proto_artifacts = []
+ for proto_source in proto_info.direct_sources:
+ # We can have slashes in the target name. For example, proto_source can be:
+ # dir/a.proto. However proto_source.basename will return a.proto, when in reality
+ # the BUILD file declares it as dir/a.proto, because target name contains a slash.
+ # There is no good workaround for this.
+ # I am using ctx.label.package to check if the name of the target contains slash or not.
+ # This is similar to what declare_directory does.
+ if not proto_source.short_path.startswith(ctx.label.package):
+ fail("This should never happen, proto source {} path does not start with {}.".format(
+ proto_source.short_path,
+ ctx.label.package,
+ ))
+ proto_source_name = proto_source.short_path[len(ctx.label.package) + 1:]
+ last_dot = proto_source_name.rfind(".")
+ if last_dot != -1:
+ proto_source_name = proto_source_name[:last_dot]
+ proto_artifacts.append(ctx.actions.declare_directory(proto_source_name + ".upb_weak_minitables"))
+
+ return proto_artifacts
+
+def _get_feature_configuration(ctx, cc_toolchain, proto_info):
+ requested_features = list(ctx.features)
+
+ # Disable the whole-archive behavior for protobuf generated code when the
+ # proto_one_output_per_message feature is enabled.
+ requested_features.append("disable_whole_archive_for_static_lib_if_proto_one_output_per_message")
+ unsupported_features = list(ctx.disabled_features)
+ if len(proto_info.direct_sources) != 0:
+ requested_features.append("header_modules")
+ else:
+ unsupported_features.append("header_modules")
+ return cc_common.configure_features(
+ ctx = ctx,
+ cc_toolchain = cc_toolchain,
+ requested_features = requested_features,
+ unsupported_features = unsupported_features,
+ )
+
+def _generate_srcs_list(ctx, generator, proto_info):
if len(proto_info.direct_sources) == 0:
return GeneratedSrcsInfo(srcs = [], hdrs = [], thunks = [], includes = [])
@@ -92,20 +137,36 @@
mnemonic = "GenUpbProtosThunks",
)
- proto_common.compile(
- actions = ctx.actions,
- proto_info = proto_info,
- proto_lang_toolchain_info = _get_lang_toolchain(ctx, generator),
- generated_files = srcs + hdrs,
- experimental_exec_group = "proto_compiler",
- )
-
return GeneratedSrcsInfo(
srcs = srcs,
hdrs = hdrs,
thunks = thunks,
)
+def _generate_upb_protos(ctx, generator, proto_info, feature_configuration):
+ implicit_weak = generator == "upb_minitable" and cc_common.is_enabled(
+ feature_configuration = feature_configuration,
+ feature_name = "proto_one_output_per_message",
+ )
+
+ srcs = _generate_srcs_list(ctx, generator, proto_info)
+ additional_args = ctx.actions.args()
+
+ if implicit_weak:
+ srcs.srcs.extend(_get_implicit_weak_field_sources(ctx, proto_info))
+ additional_args.add("--upb_minitable_opt=one_output_per_message")
+
+ proto_common.compile(
+ actions = ctx.actions,
+ proto_info = proto_info,
+ proto_lang_toolchain_info = _get_lang_toolchain(ctx, generator),
+ generated_files = srcs.srcs + srcs.hdrs,
+ experimental_exec_group = "proto_compiler",
+ additional_args = additional_args,
+ )
+
+ return srcs
+
def _generate_name(ctx, generator, thunks = False):
if thunks:
return ctx.rule.attr.name + "." + generator + ".thunks"
@@ -217,10 +278,13 @@
)
else:
proto_info = target[ProtoInfo]
+ cc_toolchain = find_cpp_toolchain(ctx)
+ feature_configuration = _get_feature_configuration(ctx, cc_toolchain, proto_info)
files = _generate_upb_protos(
ctx,
generator,
proto_info,
+ feature_configuration,
)
wrapped_cc_info = _compile_upb_protos(
ctx,
diff --git a/upb_generator/BUILD b/upb_generator/BUILD
index 757d840..4bd1ac6 100644
--- a/upb_generator/BUILD
+++ b/upb_generator/BUILD
@@ -318,6 +318,7 @@
"//upb:mini_table",
"//upb:port",
"//upb:wire_reader",
+ "//upb/mini_table:internal",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/container:flat_hash_set",
"@com_google_absl//absl/log:absl_check",
@@ -345,6 +346,7 @@
":common",
":plugin",
":protoc-gen-upb_minitable_lib",
+ "//upb/reflection:reflection",
],
copts = UPB_DEFAULT_CPPOPTS,
visibility = ["//pkg:__pkg__"],
@@ -353,6 +355,7 @@
"//upb:port",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/log:absl_log",
+ "@com_google_absl//absl/strings",
],
)
diff --git a/upb_generator/protoc-gen-upb_minitable-main.cc b/upb_generator/protoc-gen-upb_minitable-main.cc
index 5aa6fc5..e58d3ed 100644
--- a/upb_generator/protoc-gen-upb_minitable-main.cc
+++ b/upb_generator/protoc-gen-upb_minitable-main.cc
@@ -6,11 +6,13 @@
// https://developers.google.com/open-source/licenses/bsd
#include <string>
-#include <vector>
#include "absl/log/absl_log.h"
+#include "absl/strings/string_view.h"
+#include "absl/strings/substitute.h"
#include "upb/base/status.hpp"
#include "upb/base/string_view.h"
+#include "upb/reflection/def.hpp"
#include "upb_generator/common.h"
#include "upb_generator/file_layout.h"
#include "upb_generator/plugin.h"
@@ -31,20 +33,26 @@
}
void GenerateFile(const DefPoolPair& pools, upb::FileDefPtr file,
- Plugin* plugin) {
+ const MiniTableOptions& options, Plugin* plugin) {
Output h_output;
WriteMiniTableHeader(pools, file, h_output);
plugin->AddOutputFile(MiniTableHeaderFilename(file), h_output.output());
Output c_output;
- WriteMiniTableSource(pools, file, c_output);
+ WriteMiniTableSource(pools, file, options, c_output);
plugin->AddOutputFile(SourceFilename(file), c_output.output());
+
+ if (options.one_output_per_message) {
+ WriteMiniTableMultipleSources(pools, file, options, plugin);
+ }
}
-bool ParseOptions(Plugin* plugin) {
+bool ParseOptions(MiniTableOptions* options, Plugin* plugin) {
for (const auto& pair : ParseGeneratorParameter(plugin->parameter())) {
if (pair.first == "experimental_strip_nonfunctional_codegen") {
continue;
+ } else if (pair.first == "one_output_per_message") {
+ options->one_output_per_message = true;
} else {
plugin->SetError(absl::Substitute("Unknown parameter: $0", pair.first));
return false;
@@ -56,8 +64,9 @@
int PluginMain(int argc, char** argv) {
DefPoolPair pools;
+ MiniTableOptions options;
Plugin plugin;
- if (!ParseOptions(&plugin)) return 0;
+ if (!ParseOptions(&options, &plugin)) return 0;
plugin.GenerateFilesRaw(
[&](const UPB_DESC(FileDescriptorProto) * file_proto, bool generate) {
upb::Status status;
@@ -68,7 +77,7 @@
ABSL_LOG(FATAL) << "Couldn't add file " << name
<< " to DefPool: " << status.error_message();
}
- if (generate) GenerateFile(pools, file, &plugin);
+ if (generate) GenerateFile(pools, file, options, &plugin);
});
return 0;
}
diff --git a/upb_generator/protoc-gen-upb_minitable.cc b/upb_generator/protoc-gen-upb_minitable.cc
index 9e80e19..d4a2ade 100644
--- a/upb_generator/protoc-gen-upb_minitable.cc
+++ b/upb_generator/protoc-gen-upb_minitable.cc
@@ -5,6 +5,8 @@
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
+#include "upb_generator/protoc-gen-upb_minitable.h"
+
#include <string.h>
#include <algorithm>
@@ -24,6 +26,7 @@
#include "upb/base/descriptor_constants.h"
#include "upb/mini_table/enum.h"
#include "upb/mini_table/field.h"
+#include "upb/mini_table/internal/field.h"
#include "upb/mini_table/message.h"
#include "upb/reflection/def.hpp"
#include "upb/wire/types.h"
@@ -32,6 +35,7 @@
// Must be last.
#include "upb/port/def.inc"
+#include "upb_generator/plugin.h"
namespace upb {
namespace generator {
@@ -455,90 +459,13 @@
output("\n");
}
-int WriteEnums(const DefPoolPair& pools, upb::FileDefPtr file, Output& output) {
- std::vector<upb::EnumDefPtr> this_file_enums =
- SortedEnums(file, kClosedEnums);
-
- for (const auto e : this_file_enums) {
- WriteEnum(e, output);
- }
-
- if (!this_file_enums.empty()) {
- output("static const upb_MiniTableEnum *$0[$1] = {\n", kEnumsInit,
- this_file_enums.size());
- for (const auto e : this_file_enums) {
- output(" &$0,\n", EnumInit(e));
- }
- output("};\n");
- output("\n");
- }
-
- return this_file_enums.size();
-}
-
-int WriteMessages(const DefPoolPair& pools, upb::FileDefPtr file,
- Output& output) {
- std::vector<upb::MessageDefPtr> file_messages = SortedMessages(file);
-
- if (file_messages.empty()) return 0;
-
- for (auto message : file_messages) {
- WriteMessage(message, pools, output);
- }
-
- output("static const upb_MiniTable *$0[$1] = {\n", kMessagesInit,
- file_messages.size());
- for (auto message : file_messages) {
- output(" &$0,\n", MessageInitName(message));
- }
- output("};\n");
- output("\n");
- return file_messages.size();
-}
-
-void WriteExtension(upb::FieldDefPtr ext, const DefPoolPair& pools,
+void WriteExtension(const DefPoolPair& pools, upb::FieldDefPtr ext,
Output& output) {
+ output("const upb_MiniTableExtension $0 = {\n ", ExtensionLayout(ext));
output("$0,\n", FieldInitializer(pools, ext));
output(" &$0,\n", MessageInitName(ext.containing_type()));
output(" $0,\n", GetSub(ext, true));
-}
-
-int WriteExtensions(const DefPoolPair& pools, upb::FileDefPtr file,
- Output& output) {
- auto exts = SortedExtensions(file);
-
- if (exts.empty()) return 0;
-
- // Order by full name for consistent ordering.
- std::map<std::string, upb::MessageDefPtr> forward_messages;
-
- for (auto ext : exts) {
- forward_messages[ext.containing_type().full_name()] = ext.containing_type();
- if (ext.message_type()) {
- forward_messages[ext.message_type().full_name()] = ext.message_type();
- }
- }
-
- for (auto ext : exts) {
- output("const upb_MiniTableExtension $0 = {\n ", ExtensionLayout(ext));
- WriteExtension(ext, pools, output);
- output("\n};\n");
- }
-
- output(
- "\n"
- "UPB_LINKARR_APPEND(upb_AllExts)\n"
- "static const upb_MiniTableExtension *$0[$1] = {\n",
- kExtensionsInit, exts.size());
-
- for (auto ext : exts) {
- output(" &$0,\n", ExtensionLayout(ext));
- }
-
- output(
- "};\n"
- "\n");
- return exts.size();
+ output("\n};\n");
}
} // namespace
@@ -607,8 +534,7 @@
ToPreproc(file.name()));
}
-void WriteMiniTableSource(const DefPoolPair& pools, upb::FileDefPtr file,
- Output& output) {
+void WriteMiniTableSourceIncludes(upb::FileDefPtr file, Output& output) {
EmitFileWarning(file.name(), output);
output(
@@ -626,23 +552,126 @@
"// Must be last.\n"
"#include \"upb/port/def.inc\"\n"
"\n");
+}
- int msg_count = WriteMessages(pools, file, output);
- int ext_count = WriteExtensions(pools, file, output);
- int enum_count = WriteEnums(pools, file, output);
+void WriteMiniTableSource(const DefPoolPair& pools, upb::FileDefPtr file,
+ const MiniTableOptions& options, Output& output) {
+ WriteMiniTableSourceIncludes(file, output);
+
+ std::vector<upb::MessageDefPtr> messages = SortedMessages(file);
+ std::vector<upb::FieldDefPtr> extensions = SortedExtensions(file);
+ std::vector<upb::EnumDefPtr> enums = SortedEnums(file, kClosedEnums);
+
+ if (options.one_output_per_message) {
+ for (auto message : messages) {
+ output("extern const upb_MiniTable* $0;\n", MessagePtrName(message));
+ }
+ for (const auto e : enums) {
+ output("extern const upb_MiniTableEnum $0;\n", EnumInit(e));
+ }
+ for (const auto ext : extensions) {
+ output("extern const upb_MiniTableExtension $0;\n", ExtensionLayout(ext));
+ }
+ } else {
+ for (auto message : messages) {
+ WriteMessage(message, pools, output);
+ }
+ for (const auto e : enums) {
+ WriteEnum(e, output);
+ }
+ for (const auto ext : extensions) {
+ WriteExtension(pools, ext, output);
+ }
+ }
+
+ // Messages.
+ if (!messages.empty()) {
+ output("static const upb_MiniTable *$0[$1] = {\n", kMessagesInit,
+ messages.size());
+ for (auto message : messages) {
+ output(" &$0,\n", MessageInitName(message));
+ }
+ output("};\n");
+ output("\n");
+ }
+
+ // Enums.
+ if (!enums.empty()) {
+ output("static const upb_MiniTableEnum *$0[$1] = {\n", kEnumsInit,
+ enums.size());
+ for (const auto e : enums) {
+ output(" &$0,\n", EnumInit(e));
+ }
+ output("};\n");
+ output("\n");
+ }
+
+ if (!extensions.empty()) {
+ // Extensions.
+ output(
+ "\n"
+ "UPB_LINKARR_APPEND(upb_AllExts)\n"
+ "static const upb_MiniTableExtension *$0[$1] = {\n",
+ kExtensionsInit, extensions.size());
+
+ for (auto ext : extensions) {
+ output(" &$0,\n", ExtensionLayout(ext));
+ }
+
+ output(
+ "};\n"
+ "\n");
+ }
output("const upb_MiniTableFile $0 = {\n", FileLayoutName(file));
- output(" $0,\n", msg_count ? kMessagesInit : "NULL");
- output(" $0,\n", enum_count ? kEnumsInit : "NULL");
- output(" $0,\n", ext_count ? kExtensionsInit : "NULL");
- output(" $0,\n", msg_count);
- output(" $0,\n", enum_count);
- output(" $0,\n", ext_count);
+ output(" $0,\n", messages.empty() ? "NULL" : kMessagesInit);
+ output(" $0,\n", enums.empty() ? "NULL" : kEnumsInit);
+ output(" $0,\n", extensions.empty() ? "NULL" : kExtensionsInit);
+ output(" $0,\n", messages.size());
+ output(" $0,\n", enums.size());
+ output(" $0,\n", extensions.size());
output("};\n\n");
output("#include \"upb/port/undef.inc\"\n");
output("\n");
}
+std::string MultipleSourceFilename(upb::FileDefPtr file,
+ absl::string_view full_name) {
+ return absl::StrCat(StripExtension(file.name()), ".upb_weak_minitables/",
+ full_name, ".upb.c");
+}
+
+void WriteMiniTableMultipleSources(const DefPoolPair& pools,
+ upb::FileDefPtr file,
+ const MiniTableOptions& options,
+ Plugin* plugin) {
+ std::vector<upb::MessageDefPtr> messages = SortedMessages(file);
+ std::vector<upb::FieldDefPtr> extensions = SortedExtensions(file);
+ std::vector<upb::EnumDefPtr> enums = SortedEnums(file, kClosedEnums);
+
+ for (auto message : messages) {
+ Output output;
+ WriteMiniTableSourceIncludes(file, output);
+ WriteMessage(message, pools, output);
+ plugin->AddOutputFile(MultipleSourceFilename(file, message.full_name()),
+ output.output());
+ }
+ for (const auto e : enums) {
+ Output output;
+ WriteMiniTableSourceIncludes(file, output);
+ WriteEnum(e, output);
+ plugin->AddOutputFile(MultipleSourceFilename(file, e.full_name()),
+ output.output());
+ }
+ for (const auto ext : extensions) {
+ Output output;
+ WriteMiniTableSourceIncludes(file, output);
+ WriteExtension(pools, ext, output);
+ plugin->AddOutputFile(MultipleSourceFilename(file, ext.full_name()),
+ output.output());
+ }
+}
+
} // namespace generator
} // namespace upb
diff --git a/upb_generator/protoc-gen-upb_minitable.h b/upb_generator/protoc-gen-upb_minitable.h
index 4bad8d5..cbc3e8d 100644
--- a/upb_generator/protoc-gen-upb_minitable.h
+++ b/upb_generator/protoc-gen-upb_minitable.h
@@ -24,8 +24,16 @@
namespace upb {
namespace generator {
+struct MiniTableOptions {
+ bool one_output_per_message = false;
+};
+
void WriteMiniTableSource(const DefPoolPair& pools, upb::FileDefPtr file,
- Output& output);
+ const MiniTableOptions& options, Output& output);
+void WriteMiniTableMultipleSources(const DefPoolPair& pools,
+ upb::FileDefPtr file,
+ const MiniTableOptions& options,
+ Plugin* plugin);
void WriteMiniTableHeader(const DefPoolPair& pools, upb::FileDefPtr file,
Output& output);