feat: add a way to reference well-known types without protobuf repo The files were already in the include/ folder of every protoc zip file we fetched. We just have to generate proto_library targets for them, similar to what go_repository does to generate BUILD files for Go libraries
diff --git a/MODULE.bazel b/MODULE.bazel index 951361e..3510429 100644 --- a/MODULE.bazel +++ b/MODULE.bazel
@@ -11,8 +11,8 @@ bazel_dep(name = "platforms", version = "0.0.8") protoc = use_extension("//protoc:extensions.bzl", "protoc") -protoc.toolchain(version = "v25.3") -use_repo(protoc, "toolchains_protoc_hub") +protoc.toolchain(google_protobuf = "com_google_protobuf", version = "v25.3") +use_repo(protoc, "com_google_protobuf", "toolchains_protoc_hub") register_toolchains("@toolchains_protoc_hub//:all")
diff --git a/examples/BUILD b/examples/BUILD index 8f3509a..c5925bf 100644 --- a/examples/BUILD +++ b/examples/BUILD
@@ -6,6 +6,7 @@ proto_library( name = "foo_proto", srcs = ["foo.proto"], + deps = ["@com_google_protobuf//:any_proto"], ) py_proto_library(
diff --git a/examples/foo.proto b/examples/foo.proto index f81f088..f9fca4a 100644 --- a/examples/foo.proto +++ b/examples/foo.proto
@@ -1,7 +1,10 @@ syntax = "proto3"; +import "google/protobuf/any.proto"; + option java_package = "proto"; message Foo { string msg = 1; + repeated google.protobuf.Any details = 2; }
diff --git a/protoc/extensions.bzl b/protoc/extensions.bzl index 0d40f21..4f24079 100644 --- a/protoc/extensions.bzl +++ b/protoc/extensions.bzl
@@ -17,7 +17,7 @@ # Ensure the root wins in case of differences if mod.is_root: - protoc_toolchains(toolchain.name, register = False, version = toolchain.version) + protoc_toolchains(toolchain.name, register = False, google_protobuf = toolchain.google_protobuf, version = toolchain.version) root_name = toolchain.name else: registrations[toolchain.name] = toolchain.version @@ -33,6 +33,9 @@ Base name for generated repositories, allowing more than one toolchain to be registered. Overriding the default is only permitted in the root module. """, default = DEFAULT_REPOSITORY), + "google_protobuf": attr.string(doc = """A repository containing the exported 'built-in' types: + https://protobuf.dev/reference/protobuf/google.protobuf/ + """), "version": attr.string(doc = "A tag of protocolbuffers/protobuf repository."), }), },
diff --git a/protoc/private/prebuilt_protoc_toolchain.bzl b/protoc/private/prebuilt_protoc_toolchain.bzl index fe8af5a..d725f6b 100644 --- a/protoc/private/prebuilt_protoc_toolchain.bzl +++ b/protoc/private/prebuilt_protoc_toolchain.bzl
@@ -25,11 +25,21 @@ # Generated by @rules_proto//proto/toolchains:prebuilt_protoc_toolchain.bzl load("@rules_proto//proto/private/rules:proto_toolchain_rule.bzl", "proto_toolchain") +package(default_visibility=["//visibility:public"]) + proto_toolchain( name = "prebuilt_protoc_toolchain", proto_compiler = "{protoc_label}", visibility = ["//visibility:public"], ) + +# TODO: add proto_library for each .proto file +# and add deps[] in cases where they dep on each other +proto_library( + name = "any_proto", + srcs = ["include/google/protobuf/any.proto"], + strip_import_prefix = "include", +) """.format( protoc_label = ":bin/protoc.exe" if rctx.attr.platform.startswith("win") else ":bin/protoc", ))
diff --git a/protoc/private/protoc_toolchains.bzl b/protoc/private/protoc_toolchains.bzl index b3dd4ce..19d9388 100644 --- a/protoc/private/protoc_toolchains.bzl +++ b/protoc/private/protoc_toolchains.bzl
@@ -42,7 +42,7 @@ toolchain_type = "@rules_proto//proto:toolchain_type", ) """.format( - platform = platform, + platform = platform.replace("-", "_"), user_repository_name = repository_ctx.attr.user_repository_name, compatible_with = meta["compatible_with"], )
diff --git a/protoc/toolchain.bzl b/protoc/toolchain.bzl index 47a6855..1731658 100644 --- a/protoc/toolchain.bzl +++ b/protoc/toolchain.bzl
@@ -18,18 +18,39 @@ load("//protoc/private:protoc_toolchains.bzl", "protoc_toolchains_repo") load("//protoc/private:versions.bzl", "PROTOC_PLATFORMS") -def protoc_toolchains(name, version, register = True): +def _google_protobuf_alias_repo_impl(rctx): + rctx.file("BUILD", """package(default_visibility=["//visibility:public"]) +alias(name = "any_proto", actual = "@{0}//:any_proto") +""".format(rctx.attr.alias_to)) + +_google_protobuf_alias_repo = repository_rule(_google_protobuf_alias_repo_impl, attrs={"alias_to": attr.string()}) + +def protoc_toolchains(name, version, google_protobuf = None, alias_to = "osx-aarch_64", register = True): """A utility method to load all Protobuf toolchains. Args: name: base name for generated repositories, allowing multiple protoc versions. version: a release tag from protocolbuffers/protobuf, e.g. 'v25.3' + google_protobuf: a repository to expose the google.protobuf package, providing the well-known-types. + alias_to: a platform whose download of protoc.zip will become eager, as it will be used to back aliases for the + google_protobuf repo. We cannot rely on toolchain resolution because that doesn't give a way for a label + to reference one of the concrete toolchain targets. We don't want to use select() because that makes + cquery eager-fetch ALL platforms. register: whether to register the resulting toolchains. Should be True for WORKSPACE and False under bzlmod. """ for platform in PROTOC_PLATFORMS.keys(): - prebuilt_protoc_repo(name = ".".join([name, platform]), platform = platform, version = version) + prebuilt_protoc_repo( + # We must replace hyphen with underscore to workaround rules_python + # File "/output-base/external/rules_python~override/python/private/proto/py_proto_library.bzl", line 62, column 17, in _py_proto_aspect_impl + # Error in fail: Cannot generate Python code for a .proto whose path contains '-' + # (external/_main~protoc~toolchains_protoc_hub.osx-aarch_64/include/google/protobuf/any.proto). + name = ".".join([name, platform.replace("-", "_")]), + platform = platform, + version = version) protoc_toolchains_repo(name = name, user_repository_name = name) if register: native.register_toolchains("@{}//:all".format(name)) + if google_protobuf: + _google_protobuf_alias_repo(name = google_protobuf, alias_to = ".".join([name, alias_to.replace("-", "_")]))