diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java index e3b2b062e4daf5..45088bc8cb1fc4 100644 --- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java +++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java @@ -103,10 +103,10 @@ import com.google.devtools.build.lib.rules.platform.PlatformRules; import com.google.devtools.build.lib.rules.proto.BazelProtoCommon; import com.google.devtools.build.lib.rules.proto.BazelProtoLibraryRule; +import com.google.devtools.build.lib.rules.proto.BazelProtoToolchainRule; import com.google.devtools.build.lib.rules.proto.ProtoConfiguration; import com.google.devtools.build.lib.rules.proto.ProtoInfo; import com.google.devtools.build.lib.rules.proto.ProtoLangToolchainRule; -import com.google.devtools.build.lib.rules.proto.ProtoToolchainRule; import com.google.devtools.build.lib.rules.python.PyInfo; import com.google.devtools.build.lib.rules.python.PyRuleClasses.PySymlink; import com.google.devtools.build.lib.rules.python.PyRuntimeInfo; @@ -292,7 +292,7 @@ public void init(ConfiguredRuleClassProvider.Builder builder) { builder.addConfigurationFragment(new ProtoConfiguration.Loader()); builder.addRuleDefinition(new BazelProtoLibraryRule()); builder.addRuleDefinition(new ProtoLangToolchainRule()); - builder.addRuleDefinition(new ProtoToolchainRule()); + builder.addRuleDefinition(new BazelProtoToolchainRule()); ProtoBootstrap bootstrap = new ProtoBootstrap( diff --git a/src/main/java/com/google/devtools/build/lib/rules/proto/BazelProtoLibraryRule.java b/src/main/java/com/google/devtools/build/lib/rules/proto/BazelProtoLibraryRule.java index 44e354316c1238..698a30cdf79d33 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/proto/BazelProtoLibraryRule.java +++ b/src/main/java/com/google/devtools/build/lib/rules/proto/BazelProtoLibraryRule.java @@ -33,16 +33,14 @@ */ public final class BazelProtoLibraryRule implements RuleDefinition { - private static final Label DEFAULT_PROTO_COMPILER = - Label.parseAbsoluteUnchecked("@com_google_protobuf//:protoc"); private static final Attribute.LabelLateBoundDefault PROTO_COMPILER = Attribute.LabelLateBoundDefault.fromTargetConfiguration( ProtoConfiguration.class, - DEFAULT_PROTO_COMPILER, + BazelProtoToolchainRule.DEFAULT_PROTO_COMPILER, (rule, attributes, protoConfig) -> protoConfig.protoCompiler() != null ? protoConfig.protoCompiler() - : DEFAULT_PROTO_COMPILER); + : BazelProtoToolchainRule.DEFAULT_PROTO_COMPILER); @Override public RuleClass build(RuleClass.Builder builder, final RuleDefinitionEnvironment env) { diff --git a/src/main/java/com/google/devtools/build/lib/rules/proto/BazelProtoToolchainRule.java b/src/main/java/com/google/devtools/build/lib/rules/proto/BazelProtoToolchainRule.java new file mode 100644 index 00000000000000..327a61d0dfeeba --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/proto/BazelProtoToolchainRule.java @@ -0,0 +1,12 @@ +package com.google.devtools.build.lib.rules.proto; + +import com.google.devtools.build.lib.cmdline.Label; + +public class BazelProtoToolchainRule extends ProtoToolchainRule { + static final Label DEFAULT_PROTO_COMPILER = + Label.parseAbsoluteUnchecked("@com_google_protobuf//:protoc"); + + public BazelProtoToolchainRule() { + super(DEFAULT_PROTO_COMPILER); + } +} diff --git a/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoToolchain.java b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoToolchain.java index 9922ff5fec8a8d..fc37efb14b928f 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoToolchain.java +++ b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoToolchain.java @@ -16,6 +16,7 @@ import com.google.devtools.build.lib.actions.MutableActionGraph.ActionConflictException; import com.google.devtools.build.lib.analysis.ConfiguredTarget; +import com.google.devtools.build.lib.analysis.FilesToRunProvider; import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder; import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory; import com.google.devtools.build.lib.analysis.RuleContext; @@ -27,7 +28,10 @@ public class ProtoToolchain implements RuleConfiguredTargetFactory { @Override public ConfiguredTarget create(RuleContext ruleContext) throws ActionConflictException, RuleErrorException, InterruptedException { - ProtoToolchainInfo toolchain = new ProtoToolchainInfo(); + FilesToRunProvider protoCompiler = ruleContext.getExecutablePrerequisite(":proto_compiler"); + + ProtoToolchainInfo toolchain = new ProtoToolchainInfo(protoCompiler); + RuleConfiguredTargetBuilder builder = new RuleConfiguredTargetBuilder(ruleContext) .addNativeDeclaredProvider(toolchain) diff --git a/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoToolchainInfo.java b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoToolchainInfo.java index 9764929d3f904d..91288338de4e3d 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoToolchainInfo.java +++ b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoToolchainInfo.java @@ -14,7 +14,9 @@ package com.google.devtools.build.lib.rules.proto; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.lib.analysis.FilesToRunProvider; import com.google.devtools.build.lib.analysis.platform.ToolchainInfo; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec; @@ -25,9 +27,18 @@ */ @Immutable @AutoCodec -public class ProtoToolchainInfo extends ToolchainInfo implements ProtoToolchainInfoApi { +public class ProtoToolchainInfo extends ToolchainInfo implements ProtoToolchainInfoApi { + private final FilesToRunProvider protoCompiler; + @AutoCodec.Instantiator - public ProtoToolchainInfo() { + public ProtoToolchainInfo(FilesToRunProvider protoCompiler) { super(ImmutableMap.of()); + + this.protoCompiler = Preconditions.checkNotNull(protoCompiler); + } + + @Override + public FilesToRunProvider getProtoCompiler() { + return protoCompiler; } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoToolchainRule.java b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoToolchainRule.java index e1b4e412320cab..8532b6ebfe24a0 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoToolchainRule.java +++ b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoToolchainRule.java @@ -14,16 +14,43 @@ package com.google.devtools.build.lib.rules.proto; +import static com.google.devtools.build.lib.packages.Attribute.attr; +import static com.google.devtools.build.lib.packages.BuildType.LABEL; + +import com.google.common.base.Preconditions; import com.google.devtools.build.lib.analysis.BaseRuleClasses; import com.google.devtools.build.lib.analysis.RuleDefinition; import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment; +import com.google.devtools.build.lib.analysis.config.ExecutionTransitionFactory; +import com.google.devtools.build.lib.cmdline.Label; +import com.google.devtools.build.lib.packages.Attribute; import com.google.devtools.build.lib.packages.RuleClass; /** Rule definition of the proto_toolchain rule. */ -public class ProtoToolchainRule implements RuleDefinition { +class ProtoToolchainRule implements RuleDefinition { + static final String PROTO_COMPILER_ATTR_NAME = ":proto_compiler"; + + private final Label defaultProtoCompiler; + + public ProtoToolchainRule(Label defaultProtoCompiler) { + this.defaultProtoCompiler = Preconditions.checkNotNull(defaultProtoCompiler); + } + @Override public RuleClass build(RuleClass.Builder builder, final RuleDefinitionEnvironment env) { return builder + .add( + attr(PROTO_COMPILER_ATTR_NAME, LABEL) + .cfg(ExecutionTransitionFactory.create()) + .exec() + .value( + Attribute.LabelLateBoundDefault.fromTargetConfiguration( + ProtoConfiguration.class, + defaultProtoCompiler, + (rule, attributes, protoConfig) -> + protoConfig.protoCompiler() != null + ? protoConfig.protoCompiler() + : defaultProtoCompiler))) .requiresConfigurationFragments(ProtoConfiguration.class) .advertiseProvider(ProtoToolchainInfo.class) .build(); diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/proto/ProtoToolchainInfoApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/proto/ProtoToolchainInfoApi.java index 7d1ec1efb0be01..ead3ee1c53b195 100644 --- a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/proto/ProtoToolchainInfoApi.java +++ b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/proto/ProtoToolchainInfoApi.java @@ -15,12 +15,20 @@ package com.google.devtools.build.lib.starlarkbuildapi.proto; import com.google.devtools.build.docgen.annot.DocCategory; +import com.google.devtools.build.lib.starlarkbuildapi.FilesToRunProviderApi; import com.google.devtools.build.lib.starlarkbuildapi.platform.ToolchainInfoApi; import net.starlark.java.annot.StarlarkBuiltin; +import net.starlark.java.annot.StarlarkMethod; /** Provides access to information about the Protobuf toolchain rule. */ @StarlarkBuiltin( name = "ProtoToolchainInfo", category = DocCategory.PROVIDER, doc = "Provides access to information about the Protobuf toolchain rule.") -public interface ProtoToolchainInfoApi extends ToolchainInfoApi {} +public interface ProtoToolchainInfoApi extends ToolchainInfoApi { + @StarlarkMethod( + name = "proto_compiler", + doc = "The protoc executable.", + structField = true) + FilesToRunProviderT getProtoCompiler(); +} diff --git a/src/test/shell/bazel/bazel_proto_library_test.sh b/src/test/shell/bazel/bazel_proto_library_test.sh index 05df5df7389ac4..01c807ee58a848 100755 --- a/src/test/shell/bazel/bazel_proto_library_test.sh +++ b/src/test/shell/bazel/bazel_proto_library_test.sh @@ -681,4 +681,47 @@ EOF bazel build //h || fail "build failed" } +function test_have_implicitly_defined_proto_toolchain() { + write_workspace "" + + mkdir -p foo + cat > foo/BUILD < foo/write_proto_toolchain_info.bzl < " + protoc_version.path, + ) + + return [ + DefaultInfo( + files = depset([protoc_version]), + ), + ] + +write_proto_toolchain_info = rule( + implementation = _write_proto_toolchain_info_impl, + toolchains = [ + "@bazel_tools//tools/proto:toolchain_type", + ], +) +EOF + + bazel build //foo || fail "build failed" + assert_contains "^libprotoc " bazel-bin/foo/protoc_version.txt +} + run_suite "Integration tests for proto_library"