Skip to content

Commit e8ac967

Browse files
comiusiancha1992
andauthored
* Rollforward of 482d2be: Compute the value of plugin_output from proto_info NEW: don't try to compute plugin_output automatically Additional information is needed whether protoc generates a single file or multiple files. Add output_files to proto_lang_toolchain (enum "single","multiple") and propagate it through ProtoLangToolchainInfo. Add experimental_output_files to proto_common.compile, that can override the value, for faster migration path. When the value is set, automatically compute plugin_output. When the (legacy) plugin_output is not set to a file, set it automatically to correct directory. AI: Cherry-pick this change to Bazel minor release and follow up with updates to proto_lang_toolchain. Fixes: #18263 Tracking issue: #18623 PiperOrigin-RevId: 541964181 Change-Id: Ie4b4792287723798ffdd4047562d62eb05d1b731 * Fix tests --------- Co-authored-by: Ian (Hee) Cha <[email protected]>
1 parent af1b791 commit e8ac967

File tree

8 files changed

+104
-33
lines changed

8 files changed

+104
-33
lines changed

src/main/java/com/google/devtools/build/lib/rules/proto/ProtoLangToolchainRule.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.google.devtools.build.lib.analysis.config.ExecutionTransitionFactory;
2525
import com.google.devtools.build.lib.cmdline.Label;
2626
import com.google.devtools.build.lib.packages.Attribute;
27+
import com.google.devtools.build.lib.packages.Attribute.AllowedValueSet;
2728
import com.google.devtools.build.lib.packages.RuleClass;
2829
import com.google.devtools.build.lib.packages.StarlarkProviderIdentifier;
2930
import com.google.devtools.build.lib.packages.Type;
@@ -69,6 +70,16 @@ public RuleClass build(RuleClass.Builder builder, RuleDefinitionEnvironment envi
6970
<!-- #END_BLAZE_RULE.ATTRIBUTE --> */
7071
.add(attr("command_line", Type.STRING).mandatory())
7172

73+
/* <!-- #BLAZE_RULE(proto_lang_toolchain).ATTRIBUTE(output_files) -->
74+
Controls how <code>$(OUT)</code> in <code>command_line</code> is formatted, either by
75+
a path to a single file or output directory in case of multiple files.
76+
Possible values are: "single", "multiple".
77+
<!-- #END_BLAZE_RULE.ATTRIBUTE --> */
78+
.add(
79+
attr("output_files", Type.STRING)
80+
.allowedValues(new AllowedValueSet("single", "multiple", "legacy"))
81+
.value("legacy"))
82+
7283
/* <!-- #BLAZE_RULE(proto_lang_toolchain).ATTRIBUTE(plugin_format_flag) -->
7384
If provided, this value will be passed to proto-compiler to use the plugin. The value must
7485
contain a single %s which is replaced with plugin executable.

src/main/starlark/builtins_bzl/common/cc/cc_proto_library.bzl

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -48,25 +48,6 @@ def _check_proto_libraries_in_deps(deps):
4848
if ProtoInfo in dep and CcInfo not in dep:
4949
fail("proto_library '{}' does not produce output for C++".format(dep.label), "deps")
5050

51-
def _create_proto_compile_action(ctx, outputs, proto_info):
52-
proto_root = proto_info.proto_source_root
53-
if proto_root.startswith(ctx.genfiles_dir.path):
54-
genfiles_path = proto_root
55-
else:
56-
genfiles_path = ctx.genfiles_dir.path + "/" + proto_root
57-
58-
if proto_root == ".":
59-
genfiles_path = ctx.genfiles_dir.path
60-
61-
if len(outputs) != 0:
62-
proto_common.compile(
63-
actions = ctx.actions,
64-
proto_info = proto_info,
65-
proto_lang_toolchain_info = ctx.attr._aspect_cc_proto_toolchain[ProtoLangToolchainInfo],
66-
generated_files = outputs,
67-
plugin_output = genfiles_path,
68-
)
69-
7051
def _get_output_files(ctx, target, suffixes):
7152
result = []
7253
for suffix in suffixes:
@@ -171,7 +152,13 @@ def _aspect_impl(target, ctx):
171152
header_provider = ProtoCcHeaderInfo(headers = depset(transitive = transitive_headers))
172153

173154
files_to_build = list(outputs)
174-
_create_proto_compile_action(ctx, outputs, proto_info)
155+
proto_common.compile(
156+
actions = ctx.actions,
157+
proto_info = proto_info,
158+
proto_lang_toolchain_info = ctx.attr._aspect_cc_proto_toolchain[ProtoLangToolchainInfo],
159+
generated_files = outputs,
160+
experimental_output_files = "multiple",
161+
)
175162

176163
(cc_compilation_context, cc_compilation_outputs) = cc_common.compile(
177164
name = ctx.label.name,

src/main/starlark/builtins_bzl/common/java/proto/java_lite_proto_library.bzl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def _aspect_impl(target, ctx):
5050
target[ProtoInfo],
5151
proto_toolchain_info,
5252
[source_jar],
53-
source_jar,
53+
experimental_output_files = "single",
5454
)
5555
runtime = proto_toolchain_info.runtime
5656
if runtime:

src/main/starlark/builtins_bzl/common/java/proto/java_proto_library.bzl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def _bazel_java_proto_aspect_impl(target, ctx):
5757
target[ProtoInfo],
5858
proto_toolchain_info,
5959
[source_jar],
60-
source_jar,
60+
experimental_output_files = "single",
6161
)
6262

6363
# Compile Java sources (or just merge if there aren't any)

src/main/starlark/builtins_bzl/common/proto/proto_common.bzl

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,13 @@
1515
"""Definition of proto_common module, together with bazel providers for proto rules."""
1616

1717
ProtoLangToolchainInfo = provider(
18-
doc = "Specifies how to generate language-specific code from .proto files. Used by LANG_proto_library rules.",
18+
doc = """Specifies how to generate language-specific code from .proto files.
19+
Used by LANG_proto_library rules.""",
1920
fields = dict(
20-
out_replacement_format_flag = "(str) Format string used when passing output to the plugin used by proto compiler.",
21+
out_replacement_format_flag = """(str) Format string used when passing output to the plugin
22+
used by proto compiler.""",
23+
output_files = """("single","multiple","legacy") Format out_replacement_format_flag with
24+
a path to single file or a directory in case of multiple files.""",
2125
plugin_format_flag = "(str) Format string used when passing plugin to proto compiler.",
2226
plugin = "(FilesToRunProvider) Proto compiler plugin.",
2327
runtime = "(Target) Runtime.",
@@ -37,6 +41,17 @@ def _proto_path_flag(path):
3741
def _Iimport_path_equals_fullpath(proto_source):
3842
return "-I%s=%s" % (proto_source.import_path(), proto_source.source_file().path)
3943

44+
def _output_directory(proto_info, root):
45+
proto_source_root = proto_info.proto_source_root
46+
if proto_source_root.startswith(root.path):
47+
#TODO(b/281812523): remove this branch when bin_dir is removed from proto_source_root
48+
proto_source_root = proto_source_root.removeprefix(root.path).removeprefix("/")
49+
50+
if proto_source_root == "" or proto_source_root == ".":
51+
return root.path
52+
53+
return root.path + "/" + proto_source_root
54+
4055
def _compile(
4156
actions,
4257
proto_info,
@@ -48,7 +63,8 @@ def _compile(
4863
additional_inputs = depset(),
4964
resource_set = None,
5065
experimental_exec_group = None,
51-
experimental_progress_message = None):
66+
experimental_progress_message = None,
67+
experimental_output_files = "legacy"):
5268
"""Creates proto compile action for compiling *.proto files to language specific sources.
5369
5470
Args:
@@ -59,8 +75,10 @@ def _compile(
5975
generated_files: (list[File]) The output files generated by the proto compiler.
6076
Callee needs to declare files using `ctx.actions.declare_file`.
6177
See also: `proto_common.declare_generated_files`.
62-
plugin_output: (File|str) The file or directory passed to the plugin.
63-
Formatted with `proto_lang_toolchain.out_replacement_format_flag`
78+
plugin_output: (File|str) Deprecated: Set `proto_lang_toolchain.output_files`
79+
and remove the parameter.
80+
For backwards compatibility, when the proto_lang_toolchain isn't updated
81+
the value is used.
6482
additional_args: (Args) Additional arguments to add to the action.
6583
Accepts an ctx.actions.args() object that is added at the beginning
6684
of the command line.
@@ -73,12 +91,34 @@ def _compile(
7391
Avoid using this parameter.
7492
experimental_progress_message: Overrides progress_message from the toolchain.
7593
Don't use this parameter. It's only intended for the transition.
94+
experimental_output_files: (str) Overwrites output_files from the toolchain.
95+
Don't use this parameter. It's only intended for the transition.
7696
"""
97+
if type(generated_files) != type([]):
98+
fail("generated_files is expected to be a list of Files")
99+
if not generated_files:
100+
return # nothing to do
101+
if experimental_output_files not in ["single", "multiple", "legacy"]:
102+
fail('experimental_output_files expected to be one of ["single", "multiple", "legacy"]')
103+
77104
args = actions.args()
78105
args.use_param_file(param_file_arg = "@%s")
79106
args.set_param_file_format("multiline")
80107
tools = list(additional_tools)
81108

109+
if experimental_output_files != "legacy":
110+
output_files = experimental_output_files
111+
else:
112+
output_files = getattr(proto_lang_toolchain_info, "output_files", "legacy")
113+
if output_files != "legacy":
114+
if proto_lang_toolchain_info.out_replacement_format_flag:
115+
if output_files == "single":
116+
if len(generated_files) > 1:
117+
fail("generated_files only expected a single file")
118+
plugin_output = generated_files[0]
119+
else:
120+
plugin_output = _output_directory(proto_info, generated_files[0].root)
121+
82122
if plugin_output:
83123
args.add(plugin_output, format = proto_lang_toolchain_info.out_replacement_format_flag)
84124
if proto_lang_toolchain_info.plugin:

src/main/starlark/builtins_bzl/common/proto/proto_lang_toolchain.bzl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ def _rule_impl(ctx):
4141
),
4242
ProtoLangToolchainInfo(
4343
out_replacement_format_flag = flag,
44+
output_files = ctx.attr.output_files,
4445
plugin_format_flag = ctx.attr.plugin_format_flag,
4546
plugin = plugin,
4647
runtime = ctx.attr.runtime,
@@ -60,6 +61,7 @@ def make_proto_lang_toolchain(custom_proto_compiler):
6061
"progress_message": attr.string(default = "Generating proto_library %{label}"),
6162
"mnemonic": attr.string(default = "GenProto"),
6263
"command_line": attr.string(mandatory = True),
64+
"output_files": attr.string(values = ["single", "multiple", "legacy"], default = "legacy"),
6365
"plugin_format_flag": attr.string(),
6466
"plugin": attr.label(
6567
executable = True,

src/main/starlark/builtins_bzl/common/proto/proto_library.bzl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,7 @@ def _write_descriptor_set(ctx, direct_sources, deps, exports, proto_info, descri
253253
args.add_joined("--allowed_public_imports", public_import_protos, map_each = _get_import_path, join_with = ":")
254254
proto_lang_toolchain_info = proto_common.ProtoLangToolchainInfo(
255255
out_replacement_format_flag = "--descriptor_set_out=%s",
256+
output_files = "single",
256257
mnemonic = "GenProtoDescriptorSet",
257258
progress_message = "Generating Descriptor Set proto_library %{label}",
258259
proto_compiler = ctx.executable._proto_compiler,
@@ -264,7 +265,6 @@ def _write_descriptor_set(ctx, direct_sources, deps, exports, proto_info, descri
264265
proto_info,
265266
proto_lang_toolchain_info,
266267
generated_files = [descriptor_set],
267-
plugin_output = descriptor_set,
268268
additional_inputs = dependencies_descriptor_sets,
269269
additional_args = args,
270270
)

src/test/java/com/google/devtools/build/lib/rules/proto/BazelProtoCommonTest.java

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,12 @@ public final void setup() throws Exception {
9595
"def _impl(ctx):",
9696
" outfile = ctx.actions.declare_file('out')",
9797
" kwargs = {}",
98-
" if ctx.attr.plugin_output:",
99-
" kwargs['plugin_output'] = ctx.attr.plugin_output",
98+
" if ctx.attr.plugin_output == 'single':",
99+
" kwargs['plugin_output'] = outfile.path",
100+
" elif ctx.attr.plugin_output == 'multiple':",
101+
" kwargs['plugin_output'] = ctx.genfiles_dir.path",
102+
" elif ctx.attr.plugin_output == 'wrong':",
103+
" kwargs['plugin_output'] = ctx.genfiles_dir.path + '///'",
100104
" if ctx.attr.additional_args:",
101105
" additional_args = ctx.actions.args()",
102106
" additional_args.add_all(ctx.attr.additional_args)",
@@ -211,7 +215,7 @@ public void generateCode_noPlugin() throws Exception {
211215

212216
/**
213217
* Verifies usage of <code>proto_common.generate_code</code> with <code>plugin_output</code>
214-
* parameter.
218+
* parameter set to file.
215219
*/
216220
@Test
217221
public void generateCode_withPluginOutput() throws Exception {
@@ -220,7 +224,34 @@ public void generateCode_withPluginOutput() throws Exception {
220224
TestConstants.LOAD_PROTO_LIBRARY,
221225
"load('//foo:generate.bzl', 'generate_rule')",
222226
"proto_library(name = 'proto', srcs = ['A.proto'])",
223-
"generate_rule(name = 'simple', proto_dep = ':proto', plugin_output = 'foo.srcjar')");
227+
"generate_rule(name = 'simple', proto_dep = ':proto', plugin_output = 'single')");
228+
229+
ConfiguredTarget target = getConfiguredTarget("//bar:simple");
230+
231+
List<String> cmdLine =
232+
getGeneratingSpawnAction(getBinArtifact("out", target)).getRemainingArguments();
233+
assertThat(cmdLine)
234+
.comparingElementsUsing(MATCHES_REGEX)
235+
.containsExactly(
236+
"--java_out=param1,param2:bl?azel?-out/k8-fastbuild/bin/bar/out",
237+
"--plugin=bl?azel?-out/[^/]*-exec-[^/]*/bin/third_party/x/plugin",
238+
"-Ibar/A.proto=bar/A.proto",
239+
"bar/A.proto")
240+
.inOrder();
241+
}
242+
243+
/**
244+
* Verifies usage of <code>proto_common.generate_code</code> with <code>plugin_output</code>
245+
* parameter set to directory.
246+
*/
247+
@Test
248+
public void generateCode_withDirectoryPluginOutput() throws Exception {
249+
scratch.file(
250+
"bar/BUILD",
251+
TestConstants.LOAD_PROTO_LIBRARY,
252+
"load('//foo:generate.bzl', 'generate_rule')",
253+
"proto_library(name = 'proto', srcs = ['A.proto'])",
254+
"generate_rule(name = 'simple', proto_dep = ':proto', plugin_output = 'multiple')");
224255

225256
ConfiguredTarget target = getConfiguredTarget("//bar:simple");
226257

@@ -229,7 +260,7 @@ public void generateCode_withPluginOutput() throws Exception {
229260
assertThat(cmdLine)
230261
.comparingElementsUsing(MATCHES_REGEX)
231262
.containsExactly(
232-
"--java_out=param1,param2:foo.srcjar",
263+
"--java_out=param1,param2:bl?azel?-out/k8-fastbuild/bin",
233264
"--plugin=bl?azel?-out/[^/]*-exec-[^/]*/bin/third_party/x/plugin",
234265
"-Ibar/A.proto=bar/A.proto",
235266
"bar/A.proto")

0 commit comments

Comments
 (0)