diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index ac24113d03..1da4d9fb6b 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -113,8 +113,19 @@ tasks: <<: *reusable_config name: Test on RBE using minimum supported Bazel version platform: rbe_ubuntu1604 + build_flags: + # BazelCI sets --action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1, + # which prevents cc toolchain autodetection from working correctly + # on Bazel 5.4 and earlier. To workaround this, manually specify the + # build kite cc toolchain. + - "--extra_toolchains=@buildkite_config//config:cc-toolchain" test_flags: - "--test_tag_filters=-integration-test,-acceptance-test" + # BazelCI sets --action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1, + # which prevents cc toolchain autodetection from working correctly + # on Bazel 5.4 and earlier. To workaround this, manually specify the + # build kite cc toolchain. + - "--extra_toolchains=@buildkite_config//config:cc-toolchain" rbe: <<: *reusable_config name: Test on RBE diff --git a/.bazelrc b/.bazelrc index d5b0566f05..3611999dac 100644 --- a/.bazelrc +++ b/.bazelrc @@ -3,8 +3,8 @@ # This lets us glob() up all the files inside the examples to make them inputs to tests # (Note, we cannot use `common --deleted_packages` because the bazel version command doesn't support it) # To update these lines, run tools/bazel_integration_test/update_deleted_packages.sh -build --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod/entry_point,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_install,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,tests/compile_pip_requirements,tests/compile_pip_requirements_test_from_external_workspace,tests/ignore_root_user_error,tests/pip_repository_entry_points -query --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod/entry_point,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_install,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,tests/compile_pip_requirements,tests/compile_pip_requirements_test_from_external_workspace,tests/ignore_root_user_error,tests/pip_repository_entry_points +build --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_point,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_install,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,tests/compile_pip_requirements,tests/compile_pip_requirements_test_from_external_workspace,tests/ignore_root_user_error,tests/pip_repository_entry_points +query --deleted_packages=examples/build_file_generation,examples/build_file_generation/random_number_generator,examples/bzlmod,examples/bzlmod_build_file_generation,examples/bzlmod_build_file_generation/other_module/other_module/pkg,examples/bzlmod_build_file_generation/runfiles,examples/bzlmod/entry_point,examples/bzlmod/libs/my_lib,examples/bzlmod/other_module/other_module/pkg,examples/bzlmod/runfiles,examples/bzlmod/tests,examples/multi_python_versions/libs/my_lib,examples/multi_python_versions/requirements,examples/multi_python_versions/tests,examples/pip_install,examples/pip_parse,examples/pip_parse_vendored,examples/pip_repository_annotations,examples/py_proto_library,tests/compile_pip_requirements,tests/compile_pip_requirements_test_from_external_workspace,tests/ignore_root_user_error,tests/pip_repository_entry_points test --test_output=errors diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel index 938ba85dd5..1fb4f81484 100644 --- a/docs/BUILD.bazel +++ b/docs/BUILD.bazel @@ -25,6 +25,8 @@ _DOCS = { "packaging": "//docs:packaging-docs", "pip": "//docs:pip-docs", "pip_repository": "//docs:pip-repository", + "py_cc_toolchain": "//docs:py_cc_toolchain-docs", + "py_cc_toolchain_info": "//docs:py_cc_toolchain_info-docs", "python": "//docs:core-docs", } @@ -134,6 +136,25 @@ stardoc( deps = [":packaging_bzl"], ) +stardoc( + name = "py_cc_toolchain-docs", + out = "py_cc_toolchain.md_", + # NOTE: The public file isn't used as the input because it would document + # the macro, which doesn't have the attribute documentation. The macro + # doesn't do anything interesting to users, so bypass it to avoid having to + # copy/paste all the rule's doc in the macro. + input = "//python/private:py_cc_toolchain_rule.bzl", + target_compatible_with = _NOT_WINDOWS, + deps = ["//python/private:py_cc_toolchain_bzl"], +) + +stardoc( + name = "py_cc_toolchain_info-docs", + out = "py_cc_toolchain_info.md_", + input = "//python/cc:py_cc_toolchain_info.bzl", + deps = ["//python/cc:py_cc_toolchain_info_bzl"], +) + [ diff_test( name = "check_" + k, diff --git a/docs/py_cc_toolchain.md b/docs/py_cc_toolchain.md new file mode 100644 index 0000000000..3a59ea90c8 --- /dev/null +++ b/docs/py_cc_toolchain.md @@ -0,0 +1,32 @@ + + +Implementation of py_cc_toolchain rule. + +NOTE: This is a beta-quality feature. APIs subject to change until +https://github.com/bazelbuild/rules_python/issues/824 is considered done. + + + + +## py_cc_toolchain + +
+py_cc_toolchain(name, headers, python_version)
+
+ +A toolchain for a Python runtime's C/C++ information (e.g. headers) + +This rule carries information about the C/C++ side of a Python runtime, e.g. +headers, shared libraries, etc. + + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| headers | Target that provides the Python headers. Typically this is a cc_library target. | Label | required | | +| python_version | The Major.minor Python version, e.g. 3.11 | String | required | | + + diff --git a/docs/py_cc_toolchain_info.md b/docs/py_cc_toolchain_info.md new file mode 100644 index 0000000000..4e59a78415 --- /dev/null +++ b/docs/py_cc_toolchain_info.md @@ -0,0 +1,27 @@ + + +Provider for C/C++ information about the Python runtime. + +NOTE: This is a beta-quality feature. APIs subject to change until +https://github.com/bazelbuild/rules_python/issues/824 is considered done. + + + + +## PyCcToolchainInfo + +
+PyCcToolchainInfo(headers, python_version)
+
+ +C/C++ information about the Python runtime. + +**FIELDS** + + +| Name | Description | +| :------------- | :------------- | +| headers | (struct) Information about the header files, with fields: * providers_map: a dict of string to provider instances. The key should be a fully qualified name (e.g. @rules_foo//bar:baz.bzl#MyInfo) of the provider to uniquely identify its type.

The following keys are always present: * CcInfo: the CcInfo provider instance for the headers. * DefaultInfo: the DefaultInfo provider instance for the headers.

A map is used to allow additional providers from the originating headers target (typically a cc_library) to be propagated to consumers (directly exposing a Target object can cause memory issues and is an anti-pattern).

When consuming this map, it's suggested to use providers_map.values() to return all providers; or copy the map and filter out or replace keys as appropriate. Note that any keys begining with _ (underscore) are considered private and should be forward along as-is (this better allows e.g. :current_py_cc_headers to act as the underlying headers target it represents). | +| python_version | (str) The Python Major.Minor version. | + + diff --git a/python/BUILD.bazel b/python/BUILD.bazel index d75889d188..c5f25803c7 100644 --- a/python/BUILD.bazel +++ b/python/BUILD.bazel @@ -33,6 +33,7 @@ licenses(["notice"]) filegroup( name = "distribution", srcs = glob(["**"]) + [ + "//python/cc:distribution", "//python/config_settings:distribution", "//python/constraints:distribution", "//python/private:distribution", diff --git a/python/cc/BUILD.bazel b/python/cc/BUILD.bazel new file mode 100644 index 0000000000..d4a6bb8f6d --- /dev/null +++ b/python/cc/BUILD.bazel @@ -0,0 +1,44 @@ +# Package for C/C++ specific functionality of the Python rules. + +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") +load("//python/private:current_py_cc_headers.bzl", "current_py_cc_headers") +load("//python/private:util.bzl", "BZLMOD_ENABLED") + +package( + default_visibility = ["//:__subpackages__"], +) + +# This target provides the C headers for whatever the current toolchain is +# for the consuming rule. It basically acts like a cc_library by forwarding +# on the providers for the underlying cc_library that the toolchain is using. +current_py_cc_headers( + name = "current_py_cc_headers", + # Building this directly will fail unless a py cc toolchain is registered, + # and it's only under bzlmod that one is registered by default. + tags = [] if BZLMOD_ENABLED else ["manual"], + visibility = ["//visibility:public"], +) + +toolchain_type( + name = "toolchain_type", + visibility = ["//visibility:public"], +) + +bzl_library( + name = "py_cc_toolchain_bzl", + srcs = ["py_cc_toolchain.bzl"], + visibility = ["//visibility:public"], + deps = ["//python/private:py_cc_toolchain_bzl"], +) + +bzl_library( + name = "py_cc_toolchain_info_bzl", + srcs = ["py_cc_toolchain_info.bzl"], + visibility = ["//visibility:public"], + deps = ["//python/private:py_cc_toolchain_info_bzl"], +) + +filegroup( + name = "distribution", + srcs = glob(["**"]), +) diff --git a/python/cc/py_cc_toolchain.bzl b/python/cc/py_cc_toolchain.bzl new file mode 100644 index 0000000000..2e782ef9f0 --- /dev/null +++ b/python/cc/py_cc_toolchain.bzl @@ -0,0 +1,19 @@ +# 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. + +"""Public entry point for py_cc_toolchain rule.""" + +load("//python/private:py_cc_toolchain_macro.bzl", _py_cc_toolchain = "py_cc_toolchain") + +py_cc_toolchain = _py_cc_toolchain diff --git a/python/cc/py_cc_toolchain_info.bzl b/python/cc/py_cc_toolchain_info.bzl new file mode 100644 index 0000000000..9ea394ad9f --- /dev/null +++ b/python/cc/py_cc_toolchain_info.bzl @@ -0,0 +1,23 @@ +# 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. + +"""Provider for C/C++ information about the Python runtime. + +NOTE: This is a beta-quality feature. APIs subject to change until +https://github.com/bazelbuild/rules_python/issues/824 is considered done. +""" + +load("//python/private:py_cc_toolchain_info.bzl", _PyCcToolchainInfo = "PyCcToolchainInfo") + +PyCcToolchainInfo = _PyCcToolchainInfo diff --git a/python/private/BUILD.bazel b/python/private/BUILD.bazel index f454f42cf3..10af17e630 100644 --- a/python/private/BUILD.bazel +++ b/python/private/BUILD.bazel @@ -51,6 +51,28 @@ bzl_library( deps = ["@bazel_skylib//lib:types"], ) +bzl_library( + name = "py_cc_toolchain_bzl", + srcs = [ + "py_cc_toolchain_macro.bzl", + "py_cc_toolchain_rule.bzl", + ], + visibility = [ + "//docs:__subpackages__", + "//python/cc:__pkg__", + ], + deps = [ + ":py_cc_toolchain_info_bzl", + ":util_bzl", + ], +) + +bzl_library( + name = "py_cc_toolchain_info_bzl", + srcs = ["py_cc_toolchain_info.bzl"], + visibility = ["//python/cc:__pkg__"], +) + # @bazel_tools can't define bzl_library itself, so we just put a wrapper around it. bzl_library( name = "bazel_tools_bzl", @@ -73,6 +95,7 @@ exports_files( "reexports.bzl", "stamp.bzl", "util.bzl", + "py_cc_toolchain_rule.bzl", ], visibility = ["//docs:__pkg__"], ) diff --git a/python/private/current_py_cc_headers.bzl b/python/private/current_py_cc_headers.bzl new file mode 100644 index 0000000000..be7f8f8d46 --- /dev/null +++ b/python/private/current_py_cc_headers.bzl @@ -0,0 +1,41 @@ +# 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 current_py_cc_headers rule.""" + +def _current_py_cc_headers_impl(ctx): + py_cc_toolchain = ctx.toolchains["//python/cc:toolchain_type"].py_cc_toolchain + return py_cc_toolchain.headers.providers_map.values() + +current_py_cc_headers = rule( + implementation = _current_py_cc_headers_impl, + toolchains = ["//python/cc:toolchain_type"], + provides = [CcInfo], + doc = """\ +Provides the currently active Python toolchain's C headers. + +This is a wrapper around the underlying `cc_library()` for the +C headers for the consuming target's currently active Python toolchain. + +To use, simply depend on this target where you would have wanted the +toolchain's underlying `:python_headers` target: + +```starlark +cc_library( + name = "foo", + deps = ["@rules_python//python/cc:current_py_cc_headers"] +) +``` +""", +) diff --git a/python/private/py_cc_toolchain_info.bzl b/python/private/py_cc_toolchain_info.bzl new file mode 100644 index 0000000000..e7afc10599 --- /dev/null +++ b/python/private/py_cc_toolchain_info.bzl @@ -0,0 +1,43 @@ +# 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 PyCcToolchainInfo.""" + +PyCcToolchainInfo = provider( + doc = "C/C++ information about the Python runtime.", + fields = { + "headers": """\ +(struct) Information about the header files, with fields: + * providers_map: a dict of string to provider instances. The key should be + a fully qualified name (e.g. `@rules_foo//bar:baz.bzl#MyInfo`) of the + provider to uniquely identify its type. + + The following keys are always present: + * CcInfo: the CcInfo provider instance for the headers. + * DefaultInfo: the DefaultInfo provider instance for the headers. + + A map is used to allow additional providers from the originating headers + target (typically a `cc_library`) to be propagated to consumers (directly + exposing a Target object can cause memory issues and is an anti-pattern). + + When consuming this map, it's suggested to use `providers_map.values()` to + return all providers; or copy the map and filter out or replace keys as + appropriate. Note that any keys begining with `_` (underscore) are + considered private and should be forward along as-is (this better allows + e.g. `:current_py_cc_headers` to act as the underlying headers target it + represents). +""", + "python_version": "(str) The Python Major.Minor version.", + }, +) diff --git a/python/private/py_cc_toolchain_macro.bzl b/python/private/py_cc_toolchain_macro.bzl new file mode 100644 index 0000000000..35276f7401 --- /dev/null +++ b/python/private/py_cc_toolchain_macro.bzl @@ -0,0 +1,31 @@ +# 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. + +"""Fronting macro for the py_cc_toolchain rule.""" + +load(":py_cc_toolchain_rule.bzl", _py_cc_toolchain = "py_cc_toolchain") +load(":util.bzl", "add_tag") + +# A fronting macro is used because macros have user-observable behavior; +# using one from the onset avoids introducing those changes in the future. +def py_cc_toolchain(**kwargs): + """Creates a py_cc_toolchain target. + + Args: + **kwargs: Keyword args to pass onto underlying rule. + """ + + # This tag is added to easily identify usages through other macros. + add_tag(kwargs, "@rules_python//python:py_cc_toolchain") + _py_cc_toolchain(**kwargs) diff --git a/python/private/py_cc_toolchain_rule.bzl b/python/private/py_cc_toolchain_rule.bzl new file mode 100644 index 0000000000..c80f845065 --- /dev/null +++ b/python/private/py_cc_toolchain_rule.bzl @@ -0,0 +1,57 @@ +# 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 py_cc_toolchain rule. + +NOTE: This is a beta-quality feature. APIs subject to change until +https://github.com/bazelbuild/rules_python/issues/824 is considered done. +""" + +load(":py_cc_toolchain_info.bzl", "PyCcToolchainInfo") + +def _py_cc_toolchain_impl(ctx): + py_cc_toolchain = PyCcToolchainInfo( + headers = struct( + providers_map = { + "CcInfo": ctx.attr.headers[CcInfo], + "DefaultInfo": ctx.attr.headers[DefaultInfo], + }, + ), + python_version = ctx.attr.python_version, + ) + return [platform_common.ToolchainInfo( + py_cc_toolchain = py_cc_toolchain, + )] + +py_cc_toolchain = rule( + implementation = _py_cc_toolchain_impl, + attrs = { + "headers": attr.label( + doc = ("Target that provides the Python headers. Typically this " + + "is a cc_library target."), + providers = [CcInfo], + mandatory = True, + ), + "python_version": attr.string( + doc = "The Major.minor Python version, e.g. 3.11", + mandatory = True, + ), + }, + doc = """\ +A toolchain for a Python runtime's C/C++ information (e.g. headers) + +This rule carries information about the C/C++ side of a Python runtime, e.g. +headers, shared libraries, etc. +""", +) diff --git a/python/private/toolchains_repo.bzl b/python/private/toolchains_repo.bzl index f47ea8f064..592378739e 100644 --- a/python/private/toolchains_repo.bzl +++ b/python/private/toolchains_repo.bzl @@ -83,6 +83,15 @@ toolchain( toolchain = "@{user_repository_name}_{platform}//:python_runtimes", toolchain_type = "@bazel_tools//tools/python:toolchain_type", ) + +toolchain( + name = "{prefix}{platform}_py_cc_toolchain", + target_compatible_with = {compatible_with}, + target_settings = {target_settings}, + toolchain = "@{user_repository_name}_{platform}//:py_cc_toolchain", + toolchain_type = "@rules_python//python/cc:toolchain_type", + +) """.format( compatible_with = meta.compatible_with, platform = platform, diff --git a/python/private/util.bzl b/python/private/util.bzl index f0d43737a0..4c4b8fcf69 100644 --- a/python/private/util.bzl +++ b/python/private/util.bzl @@ -1,7 +1,25 @@ +# 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. + """Functionality shared by multiple pieces of code.""" load("@bazel_skylib//lib:types.bzl", "types") +# When bzlmod is enabled, canonical repos names have @@ in them, while under +# workspace builds, there is never a @@ in labels. +BZLMOD_ENABLED = "@@" in str(Label("//:unused")) + def copy_propagating_kwargs(from_kwargs, into_kwargs = None): """Copies args that must be compatible between two targets with a dependency relationship. @@ -46,15 +64,26 @@ def add_migration_tag(attrs): Returns: The same `attrs` object, but modified. """ + add_tag(attrs, _MIGRATION_TAG) + return attrs + +def add_tag(attrs, tag): + """Adds `tag` to `attrs["tags"]`. + + Args: + attrs: dict of keyword args. It is modified in place. + tag: str, the tag to add. + """ if "tags" in attrs and attrs["tags"] != None: tags = attrs["tags"] # Preserve the input type: this allows a test verifying the underlying # rule can accept the tuple for the tags argument. if types.is_tuple(tags): - attrs["tags"] = tags + (_MIGRATION_TAG,) + attrs["tags"] = tags + (tag,) else: - attrs["tags"] = tags + [_MIGRATION_TAG] + # List concatenation is necessary because the original value + # may be a frozen list. + attrs["tags"] = tags + [tag] else: - attrs["tags"] = [_MIGRATION_TAG] - return attrs + attrs["tags"] = [tag] diff --git a/python/repositories.bzl b/python/repositories.bzl index 04de6570a0..38a580e3a8 100644 --- a/python/repositories.bzl +++ b/python/repositories.bzl @@ -265,6 +265,7 @@ def _python_repository_impl(rctx): # Generated by python/repositories.bzl load("@bazel_tools//tools/python:toolchain.bzl", "py_runtime_pair") +load("@rules_python//python/cc:py_cc_toolchain.bzl", "py_cc_toolchain") package(default_visibility = ["//visibility:public"]) @@ -336,6 +337,12 @@ py_runtime_pair( py2_runtime = None, py3_runtime = ":py3_runtime", ) + +py_cc_toolchain( + name = "py_cc_toolchain", + headers = ":python_headers", + python_version = "{python_version}", +) """.format( glob_exclude = repr(glob_exclude), glob_include = repr(glob_include), diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel index abbe62ddff..2dd2282146 100644 --- a/tests/BUILD.bazel +++ b/tests/BUILD.bazel @@ -28,5 +28,7 @@ build_test( "//python:py_runtime_info_bzl", "//python:py_runtime_pair_bzl", "//python:py_test_bzl", + "//python/cc:py_cc_toolchain_bzl", + "//python/cc:py_cc_toolchain_info_bzl", ], ) diff --git a/tests/cc/BUILD.bazel b/tests/cc/BUILD.bazel new file mode 100644 index 0000000000..13395579fd --- /dev/null +++ b/tests/cc/BUILD.bazel @@ -0,0 +1,108 @@ +# 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. + +load("@rules_cc//cc:defs.bzl", "cc_toolchain", "cc_toolchain_suite") +load("@rules_testing//lib:util.bzl", "PREVENT_IMPLICIT_BUILDING_TAGS") +load("//python/cc:py_cc_toolchain.bzl", "py_cc_toolchain") +load(":fake_cc_toolchain_config.bzl", "fake_cc_toolchain_config") + +package(default_visibility = ["//:__subpackages__"]) + +toolchain( + name = "fake_py_cc_toolchain", + tags = PREVENT_IMPLICIT_BUILDING_TAGS, + toolchain = ":fake_py_cc_toolchain_impl", + toolchain_type = "@rules_python//python/cc:toolchain_type", +) + +py_cc_toolchain( + name = "fake_py_cc_toolchain_impl", + testonly = True, + headers = ":fake_headers", + python_version = "3.999", + tags = PREVENT_IMPLICIT_BUILDING_TAGS, +) + +# buildifier: disable=native-cc +cc_library( + name = "fake_headers", + testonly = True, + hdrs = ["fake_header.h"], + data = ["data.txt"], + includes = ["fake_include"], + tags = PREVENT_IMPLICIT_BUILDING_TAGS, +) + +cc_toolchain_suite( + name = "cc_toolchain_suite", + tags = ["manual"], + toolchains = { + "darwin_x86_64": ":mac_toolchain", + "k8": ":linux_toolchain", + }, +) + +filegroup(name = "empty") + +cc_toolchain( + name = "mac_toolchain", + all_files = ":empty", + compiler_files = ":empty", + dwp_files = ":empty", + linker_files = ":empty", + objcopy_files = ":empty", + strip_files = ":empty", + supports_param_files = 0, + toolchain_config = ":mac_toolchain_config", + toolchain_identifier = "mac-toolchain", +) + +toolchain( + name = "mac_toolchain_definition", + target_compatible_with = ["@platforms//os:macos"], + toolchain = ":mac_toolchain", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", +) + +fake_cc_toolchain_config( + name = "mac_toolchain_config", + target_cpu = "darwin_x86_64", + toolchain_identifier = "mac-toolchain", +) + +cc_toolchain( + name = "linux_toolchain", + all_files = ":empty", + compiler_files = ":empty", + dwp_files = ":empty", + linker_files = ":empty", + objcopy_files = ":empty", + strip_files = ":empty", + supports_param_files = 0, + toolchain_config = ":linux_toolchain_config", + toolchain_identifier = "linux-toolchain", +) + +toolchain( + name = "linux_toolchain_definition", + target_compatible_with = ["@platforms//os:linux"], + toolchain = ":linux_toolchain", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", +) + +fake_cc_toolchain_config( + name = "linux_toolchain_config", + target_cpu = "k8", + toolchain_identifier = "linux-toolchain", +) diff --git a/tests/cc/current_py_cc_headers/BUILD.bazel b/tests/cc/current_py_cc_headers/BUILD.bazel new file mode 100644 index 0000000000..e2d6a1b521 --- /dev/null +++ b/tests/cc/current_py_cc_headers/BUILD.bazel @@ -0,0 +1,17 @@ +# 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. + +load(":current_py_cc_headers_tests.bzl", "current_py_cc_headers_test_suite") + +current_py_cc_headers_test_suite(name = "current_py_cc_headers_tests") diff --git a/tests/cc/current_py_cc_headers/current_py_cc_headers_tests.bzl b/tests/cc/current_py_cc_headers/current_py_cc_headers_tests.bzl new file mode 100644 index 0000000000..2b8b2ee13a --- /dev/null +++ b/tests/cc/current_py_cc_headers/current_py_cc_headers_tests.bzl @@ -0,0 +1,69 @@ +# 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. + +"""Tests for current_py_cc_headers.""" + +load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") +load("@rules_testing//lib:truth.bzl", "matching") +load("//tests:cc_info_subject.bzl", "cc_info_subject") + +_tests = [] + +def _test_current_toolchain_headers(name): + analysis_test( + name = name, + impl = _test_current_toolchain_headers_impl, + target = "//python/cc:current_py_cc_headers", + config_settings = { + "//command_line_option:extra_toolchains": [str(Label("//tests/cc:all"))], + }, + attrs = { + "header": attr.label( + default = "//tests/cc:fake_header.h", + allow_single_file = True, + ), + }, + ) + +def _test_current_toolchain_headers_impl(env, target): + # Check that the forwarded CcInfo looks vaguely correct. + compilation_context = env.expect.that_target(target).provider( + CcInfo, + factory = cc_info_subject, + ).compilation_context() + compilation_context.direct_headers().contains_exactly([ + env.ctx.file.header, + ]) + compilation_context.direct_public_headers().contains_exactly([ + env.ctx.file.header, + ]) + + # NOTE: The include dir gets added twice, once for the source path, + # and once for the config-specific path. + compilation_context.system_includes().contains_at_least_predicates([ + matching.str_matches("*/fake_include"), + ]) + + # Check that the forward DefaultInfo looks correct + env.expect.that_target(target).runfiles().contains_predicate( + matching.str_matches("*/cc/data.txt"), + ) + +_tests.append(_test_current_toolchain_headers) + +def current_py_cc_headers_test_suite(name): + test_suite( + name = name, + tests = _tests, + ) diff --git a/tools/build_defs/python/tests/fake_cc_toolchain_config.bzl b/tests/cc/fake_cc_toolchain_config.bzl similarity index 100% rename from tools/build_defs/python/tests/fake_cc_toolchain_config.bzl rename to tests/cc/fake_cc_toolchain_config.bzl diff --git a/tests/cc/py_cc_toolchain/BUILD.bazel b/tests/cc/py_cc_toolchain/BUILD.bazel new file mode 100644 index 0000000000..57d030c750 --- /dev/null +++ b/tests/cc/py_cc_toolchain/BUILD.bazel @@ -0,0 +1,3 @@ +load(":py_cc_toolchain_tests.bzl", "py_cc_toolchain_test_suite") + +py_cc_toolchain_test_suite(name = "py_cc_toolchain_tests") diff --git a/tests/cc/py_cc_toolchain/py_cc_toolchain_tests.bzl b/tests/cc/py_cc_toolchain/py_cc_toolchain_tests.bzl new file mode 100644 index 0000000000..09bd64608c --- /dev/null +++ b/tests/cc/py_cc_toolchain/py_cc_toolchain_tests.bzl @@ -0,0 +1,85 @@ +# 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. + +"""Tests for py_cc_toolchain.""" + +load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") +load("@rules_testing//lib:truth.bzl", "matching") +load("//tests:cc_info_subject.bzl", "cc_info_subject") +load("//tests:default_info_subject.bzl", "default_info_subject") +load("//tests:py_cc_toolchain_info_subject.bzl", "PyCcToolchainInfoSubject") + +_tests = [] + +def _py_cc_toolchain_test(name): + analysis_test( + name = name, + impl = _py_cc_toolchain_test_impl, + target = "//tests/cc:fake_py_cc_toolchain_impl", + attrs = { + "header": attr.label( + default = "//tests/cc:fake_header.h", + allow_single_file = True, + ), + }, + ) + +def _py_cc_toolchain_test_impl(env, target): + env.expect.that_target(target).has_provider(platform_common.ToolchainInfo) + + toolchain = PyCcToolchainInfoSubject.new( + target[platform_common.ToolchainInfo].py_cc_toolchain, + meta = env.expect.meta.derive(expr = "py_cc_toolchain_info"), + ) + toolchain.python_version().equals("3.999") + + toolchain_headers = toolchain.headers() + toolchain_headers.providers_map().keys().contains_exactly(["CcInfo", "DefaultInfo"]) + + cc_info = cc_info_subject( + # TODO: Use DictSubject.get once available, + # https://github.com/bazelbuild/rules_testing/issues/51 + toolchain_headers.actual.providers_map["CcInfo"], + meta = env.expect.meta.derive(expr = "cc_info"), + ) + + compilation_context = cc_info.compilation_context() + compilation_context.direct_headers().contains_exactly([ + env.ctx.file.header, + ]) + compilation_context.direct_public_headers().contains_exactly([ + env.ctx.file.header, + ]) + + # NOTE: The include dir gets added twice, once for the source path, + # and once for the config-specific path, but we don't care about that. + compilation_context.system_includes().contains_at_least_predicates([ + matching.str_matches("*/fake_include"), + ]) + + default_info = default_info_subject( + toolchain_headers.actual.providers_map["DefaultInfo"], + meta = env.expect.meta.derive(expr = "default_info"), + ) + default_info.runfiles().contains_predicate( + matching.str_matches("*/cc/data.txt"), + ) + +_tests.append(_py_cc_toolchain_test) + +def py_cc_toolchain_test_suite(name): + test_suite( + name = name, + tests = _tests, + ) diff --git a/tests/cc_info_subject.bzl b/tests/cc_info_subject.bzl new file mode 100644 index 0000000000..31ac03a035 --- /dev/null +++ b/tests/cc_info_subject.bzl @@ -0,0 +1,128 @@ +# 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. +"""CcInfo testing subject.""" + +load("@rules_testing//lib:truth.bzl", "subjects") + +def cc_info_subject(info, *, meta): + """Creates a new `CcInfoSubject` for a CcInfo provider instance. + + Args: + info: The CcInfo object. + meta: ExpectMeta object. + + Returns: + A `CcInfoSubject` struct. + """ + + # buildifier: disable=uninitialized + public = struct( + # go/keep-sorted start + compilation_context = lambda *a, **k: _cc_info_subject_compilation_context(self, *a, **k), + # go/keep-sorted end + ) + self = struct( + actual = info, + meta = meta, + ) + return public + +def _cc_info_subject_compilation_context(self): + """Returns the CcInfo.compilation_context as a subject. + + Args: + self: implicitly added. + + Returns: + [`CompilationContext`] instance. + """ + return _compilation_context_subject_new( + self.actual.compilation_context, + meta = self.meta.derive("compilation_context()"), + ) + +def _compilation_context_subject_new(info, *, meta): + """Creates a CompilationContextSubject. + + Args: + info: ([`CompilationContext`]) object instance. + meta: rules_testing `ExpectMeta` instance. + + Returns: + [`CompilationContextSubject`] object. + """ + + # buildifier: disable=uninitialized + public = struct( + # go/keep-sorted start + direct_headers = lambda *a, **k: _compilation_context_subject_direct_headers(self, *a, **k), + direct_public_headers = lambda *a, **k: _compilation_context_subject_direct_public_headers(self, *a, **k), + system_includes = lambda *a, **k: _compilation_context_subject_system_includes(self, *a, **k), + # go/keep-sorted end + ) + self = struct( + actual = info, + meta = meta, + ) + return public + +def _compilation_context_subject_direct_headers(self): + """Returns the direct headers as a subjecct. + + Args: + self: implicitly added + + Returns: + [`CollectionSubject`] of `File` objects of the direct headers. + """ + return subjects.collection( + self.actual.direct_headers, + meta = self.meta.derive("direct_headers()"), + container_name = "direct_headers", + element_plural_name = "header files", + ) + +def _compilation_context_subject_direct_public_headers(self): + """Returns the direct public headers as a subjecct. + + Args: + self: implicitly added + + Returns: + [`CollectionSubject`] of `File` objects of the direct headers. + """ + return subjects.collection( + self.actual.direct_public_headers, + meta = self.meta.derive("direct_public_headers()"), + container_name = "direct_public_headers", + element_plural_name = "public header files", + ) + +def _compilation_context_subject_system_includes(self): + """Returns the system include directories as a subject. + + NOTE: The system includes are the `cc_library.includes` attribute. + + Args: + self: implicitly added + + Returns: + [`CollectionSubject`] of [`str`] + """ + return subjects.collection( + self.actual.system_includes.to_list(), + meta = self.meta.derive("includes()"), + container_name = "includes", + element_plural_name = "include paths", + ) diff --git a/tests/default_info_subject.bzl b/tests/default_info_subject.bzl new file mode 100644 index 0000000000..205dc1e7d9 --- /dev/null +++ b/tests/default_info_subject.bzl @@ -0,0 +1,34 @@ +# 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. +"""DefaultInfo testing subject.""" + +# TODO: Load this through truth.bzl#subjects when made available +# https://github.com/bazelbuild/rules_testing/issues/54 +load("@rules_testing//lib/private:runfiles_subject.bzl", "RunfilesSubject") # buildifier: disable=bzl-visibility + +# TODO: Use rules_testing's DefaultInfoSubject once it's available +# https://github.com/bazelbuild/rules_testing/issues/52 +def default_info_subject(info, *, meta): + # buildifier: disable=uninitialized + public = struct( + runfiles = lambda *a, **k: _default_info_subject_runfiles(self, *a, **k), + ) + self = struct(actual = info, meta = meta) + return public + +def _default_info_subject_runfiles(self): + return RunfilesSubject.new( + self.actual.default_runfiles, + meta = self.meta.derive("runfiles()"), + ) diff --git a/tests/py_cc_toolchain_info_subject.bzl b/tests/py_cc_toolchain_info_subject.bzl new file mode 100644 index 0000000000..20585e9052 --- /dev/null +++ b/tests/py_cc_toolchain_info_subject.bzl @@ -0,0 +1,52 @@ +# 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. +"""PyCcToolchainInfo testing subject.""" + +# TODO: Load this through truth.bzl#subjects when made available +# https://github.com/bazelbuild/rules_testing/issues/54 +load("@rules_testing//lib/private:dict_subject.bzl", "DictSubject") # buildifier: disable=bzl-visibility + +# TODO: Load this through truth.bzl#subjects when made available +# https://github.com/bazelbuild/rules_testing/issues/54 +load("@rules_testing//lib/private:str_subject.bzl", "StrSubject") # buildifier: disable=bzl-visibility +load(":struct_subject.bzl", "struct_subject") + +def _py_cc_toolchain_info_subject_new(info, *, meta): + # buildifier: disable=uninitialized + public = struct( + headers = lambda *a, **k: _py_cc_toolchain_info_subject_headers(self, *a, **k), + python_version = lambda *a, **k: _py_cc_toolchain_info_subject_python_version(self, *a, **k), + actual = info, + ) + self = struct(actual = info, meta = meta) + return public + +def _py_cc_toolchain_info_subject_headers(self): + return struct_subject( + self.actual.headers, + meta = self.meta.derive("headers()"), + providers_map = DictSubject.new, + ) + +def _py_cc_toolchain_info_subject_python_version(self): + return StrSubject.new( + self.actual.python_version, + meta = self.meta.derive("python_version()"), + ) + +# Disable this to aid doc generation +# buildifier: disable=name-conventions +PyCcToolchainInfoSubject = struct( + new = _py_cc_toolchain_info_subject_new, +) diff --git a/tests/struct_subject.bzl b/tests/struct_subject.bzl new file mode 100644 index 0000000000..9d18980a2f --- /dev/null +++ b/tests/struct_subject.bzl @@ -0,0 +1,50 @@ +# 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. + +# TODO: Replace this with rules_testing StructSubject +# https://github.com/bazelbuild/rules_testing/issues/53 +"""Subject for an arbitrary struct.""" + +def struct_subject(actual, *, meta, **attr_factories): + """Creates a struct subject. + + Args: + actual: struct, the struct to wrap. + meta: rules_testing ExpectMeta object. + **attr_factories: dict of attribute names to factory functions. Each + attribute must exist on the `actual` value. The factory functions + have the signature `def factory(value, *, meta)`, where `value` + is the actual attribute value of the struct, and `meta` is + a rules_testing ExpectMeta object. + + Returns: + StructSubject object. + """ + public_attrs = {} + for name, factory in attr_factories.items(): + if not hasattr(actual, name): + fail("Struct missing attribute: '{}'".format(name)) + + def attr_accessor(*, __name = name, __factory = factory): + return __factory( + getattr(actual, __name), + meta = meta.derive(__name + "()"), + ) + + public_attrs[name] = attr_accessor + public = struct( + actual = actual, + **public_attrs + ) + return public diff --git a/tools/build_defs/python/tests/BUILD.bazel b/tools/build_defs/python/tests/BUILD.bazel index b5694e2f0e..e271850834 100644 --- a/tools/build_defs/python/tests/BUILD.bazel +++ b/tools/build_defs/python/tests/BUILD.bazel @@ -12,9 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@rules_cc//cc:defs.bzl", "cc_toolchain", "cc_toolchain_suite") -load(":fake_cc_toolchain_config.bzl", "fake_cc_toolchain_config") - platform( name = "mac", constraint_values = [ @@ -28,66 +25,3 @@ platform( "@platforms//os:linux", ], ) - -cc_toolchain_suite( - name = "cc_toolchain_suite", - tags = ["manual"], - toolchains = { - "darwin_x86_64": ":mac_toolchain", - "k8": ":linux_toolchain", - }, -) - -filegroup(name = "empty") - -cc_toolchain( - name = "mac_toolchain", - all_files = ":empty", - compiler_files = ":empty", - dwp_files = ":empty", - linker_files = ":empty", - objcopy_files = ":empty", - strip_files = ":empty", - supports_param_files = 0, - toolchain_config = ":mac_toolchain_config", - toolchain_identifier = "mac-toolchain", -) - -toolchain( - name = "mac_toolchain_definition", - target_compatible_with = ["@platforms//os:macos"], - toolchain = ":mac_toolchain", - toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", -) - -fake_cc_toolchain_config( - name = "mac_toolchain_config", - target_cpu = "darwin_x86_64", - toolchain_identifier = "mac-toolchain", -) - -cc_toolchain( - name = "linux_toolchain", - all_files = ":empty", - compiler_files = ":empty", - dwp_files = ":empty", - linker_files = ":empty", - objcopy_files = ":empty", - strip_files = ":empty", - supports_param_files = 0, - toolchain_config = ":linux_toolchain_config", - toolchain_identifier = "linux-toolchain", -) - -toolchain( - name = "linux_toolchain_definition", - target_compatible_with = ["@platforms//os:linux"], - toolchain = ":linux_toolchain", - toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", -) - -fake_cc_toolchain_config( - name = "linux_toolchain_config", - target_cpu = "k8", - toolchain_identifier = "linux-toolchain", -) diff --git a/tools/build_defs/python/tests/py_test/py_test_tests.bzl b/tools/build_defs/python/tests/py_test/py_test_tests.bzl index 5983581493..1ecb2524bf 100644 --- a/tools/build_defs/python/tests/py_test/py_test_tests.bzl +++ b/tools/build_defs/python/tests/py_test/py_test_tests.bzl @@ -24,8 +24,8 @@ load("//tools/build_defs/python/tests:util.bzl", pt_util = "util") # Explicit Label() calls are required so that it resolves in @rules_python context instead of # @rules_testing context. -_FAKE_CC_TOOLCHAIN = Label("//tools/build_defs/python/tests:cc_toolchain_suite") -_FAKE_CC_TOOLCHAINS = [str(Label("//tools/build_defs/python/tests:all"))] +_FAKE_CC_TOOLCHAIN = Label("//tests/cc:cc_toolchain_suite") +_FAKE_CC_TOOLCHAINS = [str(Label("//tests/cc:all"))] _PLATFORM_MAC = Label("//tools/build_defs/python/tests:mac") _PLATFORM_LINUX = Label("//tools/build_defs/python/tests:linux")