mirror of https://github.com/bazelbuild/rules_cc
BEGIN_PUBLIC
Implement cc_tool END_PUBLIC PiperOrigin-RevId: 609307150 Change-Id: I2e135a59e06a56ca8ec071254d340ac4b984b234
This commit is contained in:
parent
9eb790fe47
commit
916074ec32
|
@ -124,7 +124,7 @@ ToolInfo = provider(
|
|||
# @unsorted-dict-items
|
||||
fields = {
|
||||
"label": "(Label) The label defining this provider. Place in error messages to simplify debugging",
|
||||
"exe": "(Optional[File]) The file corresponding to the tool",
|
||||
"exe": "(File) The file corresponding to the tool",
|
||||
"runfiles": "(depset[File]) The files required to run the tool",
|
||||
"requires_any_of": "(Sequence[FeatureConstraintInfo]) A set of constraints, one of which is required to enable the tool. Equivalent to with_features",
|
||||
"execution_requirements": "(Sequence[str]) A set of execution requirements of the tool",
|
||||
|
|
|
@ -16,15 +16,19 @@
|
|||
load(
|
||||
"//cc/toolchains:cc_toolchain_info.bzl",
|
||||
"ActionTypeSetInfo",
|
||||
"ToolInfo",
|
||||
)
|
||||
|
||||
visibility("//cc/toolchains/...")
|
||||
visibility([
|
||||
"//cc/toolchains/...",
|
||||
"//tests/rule_based_toolchain/...",
|
||||
])
|
||||
|
||||
def collect_provider(targets, provider):
|
||||
"""Collects providers from a label list.
|
||||
|
||||
Args:
|
||||
targets: (list[Target]) An attribute from attr.label_list
|
||||
targets: (List[Target]) An attribute from attr.label_list
|
||||
provider: (provider) The provider to look up
|
||||
Returns:
|
||||
A list of the providers
|
||||
|
@ -35,7 +39,7 @@ def collect_defaultinfo(targets):
|
|||
"""Collects DefaultInfo from a label list.
|
||||
|
||||
Args:
|
||||
targets: (list[Target]) An attribute from attr.label_list
|
||||
targets: (List[Target]) An attribute from attr.label_list
|
||||
Returns:
|
||||
A list of the associated defaultinfo
|
||||
"""
|
||||
|
@ -53,3 +57,55 @@ def _make_collector(provider, field):
|
|||
|
||||
collect_action_types = _make_collector(ActionTypeSetInfo, "actions")
|
||||
collect_files = _make_collector(DefaultInfo, "files")
|
||||
|
||||
def collect_data(ctx, targets):
|
||||
"""Collects from a 'data' attribute.
|
||||
|
||||
This is distinguished from collect_files by the fact that data attributes
|
||||
attributes include runfiles.
|
||||
|
||||
Args:
|
||||
ctx: (Context) The ctx for the current rule
|
||||
targets: (List[Target]) A list of files or executables
|
||||
|
||||
Returns:
|
||||
A depset containing all files for each of the targets, and all runfiles
|
||||
required to run them.
|
||||
"""
|
||||
return ctx.runfiles(transitive_files = collect_files(targets)).merge_all([
|
||||
info.default_runfiles
|
||||
for info in collect_defaultinfo(targets)
|
||||
if info.default_runfiles != None
|
||||
])
|
||||
|
||||
def collect_tools(ctx, targets, fail = fail):
|
||||
"""Collects tools from a label_list.
|
||||
|
||||
Each entry in the label list may either be a cc_tool or a binary.
|
||||
|
||||
Args:
|
||||
ctx: (Context) The ctx for the current rule
|
||||
targets: (List[Target]) A list of targets. Each of these targets may be
|
||||
either a cc_tool or an executable.
|
||||
fail: (function) The fail function. Should only be used in tests.
|
||||
|
||||
Returns:
|
||||
A List[ToolInfo], with regular executables creating custom tool info.
|
||||
"""
|
||||
tools = []
|
||||
for target in targets:
|
||||
info = target[DefaultInfo]
|
||||
if ToolInfo in target:
|
||||
tools.append(target[ToolInfo])
|
||||
elif info.files_to_run != None and info.files_to_run.executable != None:
|
||||
tools.append(ToolInfo(
|
||||
label = target.label,
|
||||
exe = info.files_to_run.executable,
|
||||
runfiles = collect_data(ctx, [target]),
|
||||
requires_any_of = tuple(),
|
||||
execution_requirements = tuple(),
|
||||
))
|
||||
else:
|
||||
fail("Expected %s to be a cc_tool or a binary rule" % target.label)
|
||||
|
||||
return tools
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
# Copyright 2023 The Bazel Authors. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""Implementation of cc_tool"""
|
||||
|
||||
load("//cc/toolchains/impl:collect.bzl", "collect_data", "collect_provider")
|
||||
load(
|
||||
":cc_toolchain_info.bzl",
|
||||
"FeatureConstraintInfo",
|
||||
"ToolInfo",
|
||||
)
|
||||
|
||||
def _cc_tool_impl(ctx):
|
||||
exe = ctx.executable.executable
|
||||
runfiles = collect_data(ctx, ctx.attr.data + [ctx.attr.executable])
|
||||
tool = ToolInfo(
|
||||
label = ctx.label,
|
||||
exe = exe,
|
||||
runfiles = runfiles,
|
||||
requires_any_of = tuple(collect_provider(
|
||||
ctx.attr.requires_any_of,
|
||||
FeatureConstraintInfo,
|
||||
)),
|
||||
execution_requirements = tuple(ctx.attr.execution_requirements),
|
||||
)
|
||||
|
||||
link = ctx.actions.declare_file(ctx.label.name)
|
||||
ctx.actions.symlink(
|
||||
output = link,
|
||||
target_file = ctx.executable.executable,
|
||||
is_executable = True,
|
||||
)
|
||||
return [
|
||||
tool,
|
||||
# This isn't required, but now we can do "bazel run <tool>", which can
|
||||
# be very helpful when debugging toolchains.
|
||||
DefaultInfo(
|
||||
files = depset([link]),
|
||||
runfiles = runfiles,
|
||||
executable = link,
|
||||
),
|
||||
]
|
||||
|
||||
cc_tool = rule(
|
||||
implementation = _cc_tool_impl,
|
||||
# @unsorted-dict-items
|
||||
attrs = {
|
||||
"executable": attr.label(
|
||||
allow_files = True,
|
||||
executable = True,
|
||||
cfg = "exec",
|
||||
doc = """The underlying binary that this tool represents.
|
||||
|
||||
Usually just a single prebuilt (eg. @sysroot//:bin/clang), but may be any
|
||||
executable label.
|
||||
""",
|
||||
),
|
||||
"data": attr.label_list(
|
||||
allow_files = True,
|
||||
doc = "Additional files that are required for this tool to run.",
|
||||
),
|
||||
"execution_requirements": attr.string_list(
|
||||
doc = "A list of strings that provide hints for execution environment compatibility (e.g. `requires-mac`).",
|
||||
),
|
||||
"requires_any_of": attr.label_list(
|
||||
providers = [FeatureConstraintInfo],
|
||||
doc = """This will be enabled when any of the constraints are met.
|
||||
|
||||
If omitted, this tool will be enabled unconditionally.
|
||||
""",
|
||||
),
|
||||
},
|
||||
provides = [ToolInfo],
|
||||
doc = """Declares a tool that can be bound to action configs.
|
||||
|
||||
A tool is a binary with extra metadata for the action config rule to consume
|
||||
(eg. execution_requirements).
|
||||
|
||||
Example:
|
||||
```
|
||||
cc_tool(
|
||||
name = "clang_tool",
|
||||
executable = "@llvm_toolchain//:bin/clang",
|
||||
# Suppose clang needs libc to run.
|
||||
data = ["@llvm_toolchain//:lib/x86_64-linux-gnu/libc.so.6"]
|
||||
)
|
||||
```
|
||||
""",
|
||||
executable = True,
|
||||
)
|
|
@ -18,7 +18,7 @@ load(
|
|||
"ArgsInfo",
|
||||
)
|
||||
|
||||
visibility("//tests/rule_based_toolchain/...")
|
||||
visibility("private")
|
||||
|
||||
def _test_simple_args_impl(env, targets):
|
||||
simple = env.expect.that_target(targets.simple).provider(ArgsInfo)
|
||||
|
|
|
@ -34,6 +34,10 @@ load(":generics.bzl", "optional_subject", "result_subject", "struct_subject", _r
|
|||
|
||||
visibility("//tests/rule_based_toolchain/...")
|
||||
|
||||
# The default runfiles subject uses path instead of short_path.
|
||||
# This makes it rather awkward for copybara.
|
||||
runfiles_subject = lambda value, meta: _subjects.depset_file(value.files, meta = meta)
|
||||
|
||||
# buildifier: disable=name-conventions
|
||||
_ActionTypeFactory = generate_factory(
|
||||
ActionTypeInfo,
|
||||
|
@ -135,7 +139,7 @@ _ToolFactory = generate_factory(
|
|||
"ToolInfo",
|
||||
dict(
|
||||
exe = _subjects.file,
|
||||
runfiles = _subjects.depset_file,
|
||||
runfiles = runfiles_subject,
|
||||
requires_any_of = ProviderSequence(_FeatureConstraintFactory),
|
||||
execution_requirements = _subjects.collection,
|
||||
),
|
||||
|
@ -196,5 +200,6 @@ subjects = struct(
|
|||
result = result_subject,
|
||||
optional = optional_subject,
|
||||
struct = struct_subject,
|
||||
runfiles = runfiles_subject,
|
||||
) | {factory.name: factory.factory for factory in FACTORIES})
|
||||
)
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
load("@bazel_skylib//rules:native_binary.bzl", "native_binary")
|
||||
|
||||
package(default_visibility = ["//tests/rule_based_toolchain:__subpackages__"])
|
||||
|
||||
exports_files(
|
||||
|
@ -7,6 +9,13 @@ exports_files(
|
|||
),
|
||||
)
|
||||
|
||||
native_binary(
|
||||
name = "bin_wrapper",
|
||||
src = "bin_wrapper.sh",
|
||||
out = "bin_wrapper",
|
||||
data = [":bin"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "multiple",
|
||||
srcs = [
|
||||
|
@ -14,3 +23,10 @@ filegroup(
|
|||
"multiple2",
|
||||
],
|
||||
)
|
||||
|
||||
# Analysis_test is unable to depend on source files directly, but it can depend
|
||||
# on a filegroup containing a single file.
|
||||
filegroup(
|
||||
name = "bin_filegroup",
|
||||
srcs = ["bin"],
|
||||
)
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
echo "Running unwrapped tool"
|
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
echo "Running tool wrapper"
|
|
@ -0,0 +1,30 @@
|
|||
load("@rules_testing//lib:util.bzl", "util")
|
||||
load("//cc/toolchains:tool.bzl", "cc_tool")
|
||||
load("//tests/rule_based_toolchain:analysis_test_suite.bzl", "analysis_test_suite")
|
||||
load(":tool_test.bzl", "TARGETS", "TESTS")
|
||||
|
||||
util.helper_target(
|
||||
cc_tool,
|
||||
name = "tool",
|
||||
data = ["//tests/rule_based_toolchain/testdata:bin"],
|
||||
executable = "//tests/rule_based_toolchain/testdata:bin_wrapper.sh",
|
||||
execution_requirements = ["requires-mac"],
|
||||
)
|
||||
|
||||
util.helper_target(
|
||||
cc_tool,
|
||||
name = "wrapped_tool",
|
||||
executable = "//tests/rule_based_toolchain/testdata:bin_wrapper",
|
||||
)
|
||||
|
||||
util.helper_target(
|
||||
cc_tool,
|
||||
name = "data_with_runfiles",
|
||||
executable = "//tests/rule_based_toolchain/testdata:file1",
|
||||
)
|
||||
|
||||
analysis_test_suite(
|
||||
name = "test_suite",
|
||||
targets = TARGETS,
|
||||
tests = TESTS,
|
||||
)
|
|
@ -0,0 +1,104 @@
|
|||
# Copyright 2024 The Bazel Authors. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
"""Tests for the cc_args rule."""
|
||||
|
||||
load("//cc/toolchains:cc_toolchain_info.bzl", "ToolInfo")
|
||||
load("//cc/toolchains/impl:collect.bzl", _collect_tools = "collect_tools")
|
||||
load("//tests/rule_based_toolchain:subjects.bzl", "result_fn_wrapper", "subjects")
|
||||
|
||||
visibility("private")
|
||||
|
||||
collect_tools = result_fn_wrapper(_collect_tools)
|
||||
collection_result = subjects.result(subjects.collection)
|
||||
|
||||
collect_tool = result_fn_wrapper(
|
||||
lambda ctx, target, fail: _collect_tools(ctx, [target], fail = fail)[0],
|
||||
)
|
||||
tool_result = subjects.result(subjects.ToolInfo)
|
||||
|
||||
# Generated by native_binary.
|
||||
_BIN_WRAPPER_SYMLINK = "tests/rule_based_toolchain/testdata/bin_wrapper"
|
||||
_BIN_WRAPPER = "tests/rule_based_toolchain/testdata/bin_wrapper.sh"
|
||||
_BIN = "tests/rule_based_toolchain/testdata/bin"
|
||||
|
||||
def _tool_test(env, targets):
|
||||
tool = env.expect.that_target(targets.tool).provider(ToolInfo)
|
||||
tool.exe().short_path_equals(_BIN_WRAPPER)
|
||||
tool.runfiles().contains_exactly([
|
||||
_BIN_WRAPPER,
|
||||
_BIN,
|
||||
])
|
||||
|
||||
def _wrapped_tool_includes_runfiles_test(env, targets):
|
||||
tool = env.expect.that_target(targets.wrapped_tool).provider(ToolInfo)
|
||||
tool.exe().short_path_equals(_BIN_WRAPPER_SYMLINK)
|
||||
tool.runfiles().contains_exactly([
|
||||
_BIN_WRAPPER_SYMLINK,
|
||||
_BIN,
|
||||
])
|
||||
|
||||
def _collect_tools_collects_tools_test(env, targets):
|
||||
env.expect.that_value(
|
||||
value = collect_tools(env.ctx, [targets.tool, targets.wrapped_tool]),
|
||||
factory = collection_result,
|
||||
).ok().contains_exactly(
|
||||
[targets.tool[ToolInfo], targets.wrapped_tool[ToolInfo]],
|
||||
).in_order()
|
||||
|
||||
def _collect_tools_collects_binaries_test(env, targets):
|
||||
tool_wrapper = env.expect.that_value(
|
||||
value = collect_tool(env.ctx, targets.bin_wrapper),
|
||||
factory = tool_result,
|
||||
).ok()
|
||||
tool_wrapper.label().equals(targets.bin_wrapper.label)
|
||||
tool_wrapper.exe().short_path_equals(_BIN_WRAPPER_SYMLINK)
|
||||
tool_wrapper.runfiles().contains_exactly([
|
||||
_BIN_WRAPPER_SYMLINK,
|
||||
_BIN,
|
||||
])
|
||||
|
||||
def _collect_tools_collects_single_files_test(env, targets):
|
||||
bin = env.expect.that_value(
|
||||
value = collect_tool(env.ctx, targets.bin_filegroup),
|
||||
factory = tool_result,
|
||||
expr = "bin_filegroup",
|
||||
).ok()
|
||||
bin.label().equals(targets.bin_filegroup.label)
|
||||
bin.exe().short_path_equals(_BIN)
|
||||
bin.runfiles().contains_exactly([_BIN])
|
||||
|
||||
def _collect_tools_fails_on_non_binary_test(env, targets):
|
||||
env.expect.that_value(
|
||||
value = collect_tools(env.ctx, [targets.multiple]),
|
||||
factory = collection_result,
|
||||
expr = "multiple_non_binary",
|
||||
).err()
|
||||
|
||||
TARGETS = [
|
||||
"//tests/rule_based_toolchain/tool:tool",
|
||||
"//tests/rule_based_toolchain/tool:wrapped_tool",
|
||||
"//tests/rule_based_toolchain/testdata:bin_wrapper",
|
||||
"//tests/rule_based_toolchain/testdata:multiple",
|
||||
"//tests/rule_based_toolchain/testdata:bin_filegroup",
|
||||
]
|
||||
|
||||
# @unsorted-dict-items
|
||||
TESTS = {
|
||||
"tool_test": _tool_test,
|
||||
"wrapped_tool_includes_runfiles_test": _wrapped_tool_includes_runfiles_test,
|
||||
"collect_tools_collects_tools_test": _collect_tools_collects_tools_test,
|
||||
"collect_tools_collects_binaries_test": _collect_tools_collects_binaries_test,
|
||||
"collect_tools_collects_single_files_test": _collect_tools_collects_single_files_test,
|
||||
"collect_tools_fails_on_non_binary_test": _collect_tools_fails_on_non_binary_test,
|
||||
}
|
Loading…
Reference in New Issue