diff --git a/BUILD b/BUILD index e2c2f41..079f426 100644 --- a/BUILD +++ b/BUILD @@ -1,4 +1,5 @@ load("@rules_license//rules:license.bzl", "license") +load("//proto:defs.bzl", "proto_toolchain") license( name = "license", @@ -8,3 +9,8 @@ license( licenses(["notice"]) exports_files(["LICENSE"]) + +proto_toolchain( + name = "proto_toolchain", + proto_compiler = "@com_google_protobuf//:protoc", +) diff --git a/MODULE.bazel b/MODULE.bazel index d69b785..30a64ac 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -17,3 +17,8 @@ bazel_dep(name = "rules_cc", version = "0.0.1", dev_dependency = True) bazel_dep(name = "googletest", version = "1.11.0", dev_dependency = True, repo_name = "com_google_googletest") bazel_dep(name = "protobuf", version = "23.1", dev_dependency = True, repo_name = "com_google_protobuf") bazel_dep(name = "platforms", version = "0.0.8", dev_dependency = True) + +register_toolchains( + "//:proto_toolchain_toolchain", + dev_dependency = True, +) diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 5d86542..a62fac8 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -1,6 +1,6 @@ { "lockFileVersion": 6, - "moduleFileHash": "7a83abe22db793fb1612f5cf942cc29bce39f91dcc76ce2f4ecc60a2f5f8a1e0", + "moduleFileHash": "321a56e76d8741956b8c24ffc3015b50ab2cc32e2b1d1712aa9916c248092be8", "flags": { "cmdRegistries": [ "https://bcr.bazel.build/" @@ -22,7 +22,9 @@ "key": "", "repoName": "rules_proto", "executionPlatformsToRegister": [], - "toolchainsToRegister": [], + "toolchainsToRegister": [ + "//:proto_toolchain_toolchain" + ], "extensionUsages": [], "deps": { "rules_license": "rules_license@0.0.7", @@ -1222,7 +1224,7 @@ }, "@@protobuf~//:non_module_deps.bzl%non_module_deps": { "general": { - "bzlTransitiveDigest": "aGnO/HqVtCmRLEQWGCuKp7jwX+lCh/nc3/hI3clfwD8=", + "bzlTransitiveDigest": "Ru/iB33/Fg7l06H1hBzJ1lPAZip3abmjbwD8z/MzBig=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, @@ -1250,7 +1252,7 @@ }, "@@rules_java~//java:extensions.bzl%toolchains": { "general": { - "bzlTransitiveDigest": "tJHbmWnq7m+9eUBnUdv7jZziQ26FmcGL9C5/hU3Q9UQ=", + "bzlTransitiveDigest": "0N5b5J9fUzo0sgvH4F3kIEaeXunz4Wy2/UtSFV/eXUY=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, diff --git a/WORKSPACE b/WORKSPACE index 2f65076..4bf62bf 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -27,3 +27,7 @@ rbe_preconfig( name = "buildkite_config", toolchain = "ubuntu1804-bazel-java11", ) + +register_toolchains( + "//:proto_toolchain_toolchain", +) diff --git a/docs/defs.md b/docs/defs.md index 2f5dc92..c554646 100644 --- a/docs/defs.md +++ b/docs/defs.md @@ -2,6 +2,29 @@ Starlark rules for building protocol buffers. + + +## current_proto_toolchain + +
+current_proto_toolchain(name)
+
+ + + This rule exists so that the current protoc toolchain can be used in the `toolchains` attribute of + other rules, such as genrule. It allows exposing a protoc toolchain after toolchain resolution has + happened, to a rule which expects a concrete implementation of a toolchain, rather than a + toolchain_type which could be resolved to that toolchain. + + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | + + ## proto_descriptor_set diff --git a/proto/defs.bzl b/proto/defs.bzl index 69a1969..b5219ae 100644 --- a/proto/defs.bzl +++ b/proto/defs.bzl @@ -15,7 +15,7 @@ """Starlark rules for building protocol buffers.""" load("//proto:proto_lang_toolchain.bzl", _proto_lang_toolchain = "proto_lang_toolchain") -load("//proto:proto_toolchain.bzl", _proto_toolchain = "proto_toolchain") +load("//proto:proto_toolchain.bzl", _current_proto_toolchain = "current_proto_toolchain", _proto_toolchain = "proto_toolchain") load("//proto/private:native.bzl", "NativeProtoInfo", "native_proto_common") load("//proto/private/rules:proto_descriptor_set.bzl", _proto_descriptor_set = "proto_descriptor_set") @@ -45,6 +45,7 @@ proto_descriptor_set = _proto_descriptor_set proto_lang_toolchain = _proto_lang_toolchain proto_toolchain = _proto_toolchain +current_proto_toolchain = _current_proto_toolchain # Encapsulates information provided by `proto_library`. # diff --git a/proto/private/rules/proto_toolchain.bzl b/proto/private/rules/proto_toolchain.bzl index a091b80..0d68206 100644 --- a/proto/private/rules/proto_toolchain.bzl +++ b/proto/private/rules/proto_toolchain.bzl @@ -38,3 +38,36 @@ def proto_toolchain(*, name, proto_compiler, exec_compatible_with = []): target_compatible_with = [], toolchain = name, ) + +def _current_proto_toolchain_impl(ctx): + toolchain = ctx.toolchains[ctx.attr._toolchain] + + direct = [toolchain.proto.proto_compiler.executable] + transitive = [] + files = depset(direct, transitive = transitive) + return [ + toolchain, + platform_common.TemplateVariableInfo({ + "PROTOC": str(toolchain.proto.proto_compiler.executable.path), + }), + DefaultInfo( + runfiles = ctx.runfiles(transitive_files = files), + files = files, + ), + ] + +current_proto_toolchain = rule( + doc = """ + This rule exists so that the current protoc toolchain can be used in the `toolchains` attribute of + other rules, such as genrule. It allows exposing a protoc toolchain after toolchain resolution has + happened, to a rule which expects a concrete implementation of a toolchain, rather than a + toolchain_type which could be resolved to that toolchain. + """, + implementation = _current_proto_toolchain_impl, + attrs = { + "_toolchain": attr.string(default = str(Label("@rules_proto//proto:toolchain_type"))), + }, + toolchains = [ + str(Label("@rules_proto//proto:toolchain_type")), + ], +) diff --git a/proto/proto_toolchain.bzl b/proto/proto_toolchain.bzl index e1a853c..f38df2f 100644 --- a/proto/proto_toolchain.bzl +++ b/proto/proto_toolchain.bzl @@ -14,6 +14,7 @@ """Export for proto_toolchain""" -load("//proto/private/rules:proto_toolchain.bzl", _proto_toolchain_macro = "proto_toolchain") +load("//proto/private/rules:proto_toolchain.bzl", _current_proto_toolchain = "current_proto_toolchain", _proto_toolchain_macro = "proto_toolchain") proto_toolchain = _proto_toolchain_macro +current_proto_toolchain = _current_proto_toolchain diff --git a/tests/current_toolchain/BUILD.bazel b/tests/current_toolchain/BUILD.bazel new file mode 100644 index 0000000..26a8ddf --- /dev/null +++ b/tests/current_toolchain/BUILD.bazel @@ -0,0 +1,35 @@ +load("//proto:defs.bzl", "current_proto_toolchain") + +current_proto_toolchain( + name = "current_proto_toolchain", +) + +genrule( + name = "gen_protoc_help_from_current_proto_toolchain", + srcs = [], + outs = ["protoc_help_from_current_proto_toolchain"], + cmd = """ + v=$$($(PROTOC) --help) + echo $$v > $(OUTS) + """, + target_compatible_with = select({ + "@platforms//os:windows": ["@platforms//:incompatible"], + "//conditions:default": [], + }), + toolchains = [":current_proto_toolchain"], +) + +# The genrule above will fail if PROTOC cannot be found, but using genrules for tests isn't recommended. +# This sh_test just checks if the output of the genrule has any content. +sh_test( + name = "test_protoc_help_from_current_proto_toolchain", + srcs = ["test_protoc_help_from_current_proto_toolchain.sh"], + data = [":protoc_help_from_current_proto_toolchain"], + env = { + "PROTOC_HELP_OUTPUT": "$(location :protoc_help_from_current_proto_toolchain)", + }, + target_compatible_with = select({ + "@platforms//os:windows": ["@platforms//:incompatible"], + "//conditions:default": [], + }), +) diff --git a/tests/current_toolchain/test_protoc_help_from_current_proto_toolchain.sh b/tests/current_toolchain/test_protoc_help_from_current_proto_toolchain.sh new file mode 100755 index 0000000..fbb031e --- /dev/null +++ b/tests/current_toolchain/test_protoc_help_from_current_proto_toolchain.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env sh + +# Fail if the file in the PROTOC_HELP_OUTPUT environment variable is empty +[ -s "$PROTOC_HELP_OUTPUT" ]