Ignas Anikevicius | 8f114a5 | 2024-01-31 14:41:20 +0900 | [diff] [blame] | 1 | # Copyright 2022 The Bazel Authors. All rights reserved. |
| 2 | # |
| 3 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | # you may not use this file except in compliance with the License. |
| 5 | # You may obtain a copy of the License at |
| 6 | # |
| 7 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | # |
| 9 | # Unless required by applicable law or agreed to in writing, software |
| 10 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | # See the License for the specific language governing permissions and |
| 13 | # limitations under the License. |
| 14 | |
| 15 | """Create the toolchain defs in a BUILD.bazel file.""" |
| 16 | |
| 17 | load("@bazel_skylib//lib:selects.bzl", "selects") |
Richard Levasseur | dd5db65 | 2024-10-15 16:33:37 -0700 | [diff] [blame] | 18 | load(":text_util.bzl", "render") |
Richard Levasseur | 3730803 | 2024-05-18 09:44:18 -0700 | [diff] [blame] | 19 | load( |
| 20 | ":toolchain_types.bzl", |
| 21 | "EXEC_TOOLS_TOOLCHAIN_TYPE", |
| 22 | "PY_CC_TOOLCHAIN_TYPE", |
| 23 | "TARGET_TOOLCHAIN_TYPE", |
| 24 | ) |
Ignas Anikevicius | 8f114a5 | 2024-01-31 14:41:20 +0900 | [diff] [blame] | 25 | |
Ignas Anikevicius | cf1f36d | 2024-06-19 13:08:58 +0900 | [diff] [blame] | 26 | _IS_EXEC_TOOLCHAIN_ENABLED = Label("//python/config_settings:is_exec_tools_toolchain_enabled") |
| 27 | |
Richard Levasseur | 68c3048 | 2024-07-16 16:22:22 -0700 | [diff] [blame] | 28 | # buildifier: disable=unnamed-macro |
| 29 | def py_toolchain_suite( |
| 30 | *, |
| 31 | prefix, |
| 32 | user_repository_name, |
| 33 | python_version, |
| 34 | set_python_version_constraint, |
| 35 | flag_values, |
| 36 | target_compatible_with = []): |
Ignas Anikevicius | 8f114a5 | 2024-01-31 14:41:20 +0900 | [diff] [blame] | 37 | """For internal use only. |
| 38 | |
| 39 | Args: |
| 40 | prefix: Prefix for toolchain target names. |
| 41 | user_repository_name: The name of the user repository. |
| 42 | python_version: The full (X.Y.Z) version of the interpreter. |
| 43 | set_python_version_constraint: True or False as a string. |
Ignas Anikevicius | 7de43d1 | 2024-06-06 17:20:01 +0900 | [diff] [blame] | 44 | flag_values: Extra flag values to match for this toolchain. |
Richard Levasseur | 68c3048 | 2024-07-16 16:22:22 -0700 | [diff] [blame] | 45 | target_compatible_with: list constraints the toolchains are compatible with. |
Ignas Anikevicius | 8f114a5 | 2024-01-31 14:41:20 +0900 | [diff] [blame] | 46 | """ |
| 47 | |
| 48 | # We have to use a String value here because bzlmod is passing in a |
Richard Levasseur | ac3abf6 | 2024-06-17 16:28:33 -0700 | [diff] [blame] | 49 | # string as we cannot have list of bools in build rule attributes. |
Ignas Anikevicius | 8f114a5 | 2024-01-31 14:41:20 +0900 | [diff] [blame] | 50 | # This if statement does not appear to work unless it is in the |
| 51 | # toolchain file. |
Ignas Anikevicius | 7de43d1 | 2024-06-06 17:20:01 +0900 | [diff] [blame] | 52 | if set_python_version_constraint in ["True", "False"]: |
Ignas Anikevicius | 8f114a5 | 2024-01-31 14:41:20 +0900 | [diff] [blame] | 53 | major_minor, _, _ = python_version.rpartition(".") |
Ignas Anikevicius | 7de43d1 | 2024-06-06 17:20:01 +0900 | [diff] [blame] | 54 | python_versions = [major_minor, python_version] |
| 55 | if set_python_version_constraint == "False": |
| 56 | python_versions.append("") |
Ignas Anikevicius | 8f114a5 | 2024-01-31 14:41:20 +0900 | [diff] [blame] | 57 | |
Ignas Anikevicius | 7de43d1 | 2024-06-06 17:20:01 +0900 | [diff] [blame] | 58 | match_any = [] |
| 59 | for i, v in enumerate(python_versions): |
| 60 | name = "{prefix}_{python_version}_{i}".format( |
| 61 | prefix = prefix, |
| 62 | python_version = python_version, |
| 63 | i = i, |
| 64 | ) |
| 65 | match_any.append(name) |
| 66 | native.config_setting( |
| 67 | name = name, |
| 68 | flag_values = flag_values | { |
| 69 | Label("@rules_python//python/config_settings:python_version"): v, |
| 70 | }, |
| 71 | visibility = ["//visibility:private"], |
| 72 | ) |
| 73 | |
| 74 | name = "{prefix}_version_setting_{python_version}".format( |
| 75 | prefix = prefix, |
| 76 | python_version = python_version, |
Ignas Anikevicius | 8f114a5 | 2024-01-31 14:41:20 +0900 | [diff] [blame] | 77 | visibility = ["//visibility:private"], |
| 78 | ) |
Ignas Anikevicius | 7de43d1 | 2024-06-06 17:20:01 +0900 | [diff] [blame] | 79 | selects.config_setting_group( |
| 80 | name = name, |
| 81 | match_any = match_any, |
| 82 | visibility = ["//visibility:private"], |
| 83 | ) |
| 84 | target_settings = [name] |
Ignas Anikevicius | 8f114a5 | 2024-01-31 14:41:20 +0900 | [diff] [blame] | 85 | else: |
| 86 | fail(("Invalid set_python_version_constraint value: got {} {}, wanted " + |
| 87 | "either the string 'True' or the string 'False'; " + |
| 88 | "(did you convert bool to string?)").format( |
| 89 | type(set_python_version_constraint), |
| 90 | repr(set_python_version_constraint), |
| 91 | )) |
| 92 | |
Richard Levasseur | 68c3048 | 2024-07-16 16:22:22 -0700 | [diff] [blame] | 93 | _internal_toolchain_suite( |
| 94 | prefix = prefix, |
| 95 | runtime_repo_name = user_repository_name, |
| 96 | target_settings = target_settings, |
| 97 | target_compatible_with = target_compatible_with, |
| 98 | ) |
| 99 | |
| 100 | def _internal_toolchain_suite(prefix, runtime_repo_name, target_compatible_with, target_settings): |
Ignas Anikevicius | 8f114a5 | 2024-01-31 14:41:20 +0900 | [diff] [blame] | 101 | native.toolchain( |
| 102 | name = "{prefix}_toolchain".format(prefix = prefix), |
Richard Levasseur | 68c3048 | 2024-07-16 16:22:22 -0700 | [diff] [blame] | 103 | toolchain = "@{runtime_repo_name}//:python_runtimes".format( |
| 104 | runtime_repo_name = runtime_repo_name, |
Ignas Anikevicius | 8f114a5 | 2024-01-31 14:41:20 +0900 | [diff] [blame] | 105 | ), |
Richard Levasseur | 3730803 | 2024-05-18 09:44:18 -0700 | [diff] [blame] | 106 | toolchain_type = TARGET_TOOLCHAIN_TYPE, |
Ignas Anikevicius | 8f114a5 | 2024-01-31 14:41:20 +0900 | [diff] [blame] | 107 | target_settings = target_settings, |
Richard Levasseur | 68c3048 | 2024-07-16 16:22:22 -0700 | [diff] [blame] | 108 | target_compatible_with = target_compatible_with, |
Ignas Anikevicius | 8f114a5 | 2024-01-31 14:41:20 +0900 | [diff] [blame] | 109 | ) |
| 110 | |
| 111 | native.toolchain( |
| 112 | name = "{prefix}_py_cc_toolchain".format(prefix = prefix), |
Richard Levasseur | 68c3048 | 2024-07-16 16:22:22 -0700 | [diff] [blame] | 113 | toolchain = "@{runtime_repo_name}//:py_cc_toolchain".format( |
| 114 | runtime_repo_name = runtime_repo_name, |
Ignas Anikevicius | 8f114a5 | 2024-01-31 14:41:20 +0900 | [diff] [blame] | 115 | ), |
Richard Levasseur | 3730803 | 2024-05-18 09:44:18 -0700 | [diff] [blame] | 116 | toolchain_type = PY_CC_TOOLCHAIN_TYPE, |
Ignas Anikevicius | 8f114a5 | 2024-01-31 14:41:20 +0900 | [diff] [blame] | 117 | target_settings = target_settings, |
Richard Levasseur | 68c3048 | 2024-07-16 16:22:22 -0700 | [diff] [blame] | 118 | target_compatible_with = target_compatible_with, |
Ignas Anikevicius | 8f114a5 | 2024-01-31 14:41:20 +0900 | [diff] [blame] | 119 | ) |
Richard Levasseur | 3730803 | 2024-05-18 09:44:18 -0700 | [diff] [blame] | 120 | |
| 121 | native.toolchain( |
| 122 | name = "{prefix}_py_exec_tools_toolchain".format(prefix = prefix), |
Richard Levasseur | 68c3048 | 2024-07-16 16:22:22 -0700 | [diff] [blame] | 123 | toolchain = "@{runtime_repo_name}//:py_exec_tools_toolchain".format( |
| 124 | runtime_repo_name = runtime_repo_name, |
Richard Levasseur | 3730803 | 2024-05-18 09:44:18 -0700 | [diff] [blame] | 125 | ), |
| 126 | toolchain_type = EXEC_TOOLS_TOOLCHAIN_TYPE, |
Ignas Anikevicius | cf1f36d | 2024-06-19 13:08:58 +0900 | [diff] [blame] | 127 | target_settings = select({ |
| 128 | _IS_EXEC_TOOLCHAIN_ENABLED: target_settings, |
| 129 | # Whatever the default is, it has to map to a `config_setting` |
| 130 | # that will never match. Since the default branch is only taken if |
| 131 | # _IS_EXEC_TOOLCHAIN_ENABLED is false, then it will never match |
| 132 | # when later evaluated during toolchain resolution. |
| 133 | # Note that @platforms//:incompatible can't be used here because |
| 134 | # the RHS must be a `config_setting`. |
| 135 | "//conditions:default": [_IS_EXEC_TOOLCHAIN_ENABLED], |
| 136 | }), |
Richard Levasseur | 68c3048 | 2024-07-16 16:22:22 -0700 | [diff] [blame] | 137 | exec_compatible_with = target_compatible_with, |
Richard Levasseur | 3730803 | 2024-05-18 09:44:18 -0700 | [diff] [blame] | 138 | ) |
| 139 | |
| 140 | # NOTE: When adding a new toolchain, for WORKSPACE builds to see the |
| 141 | # toolchain, the name must be added to the native.register_toolchains() |
| 142 | # call in python/repositories.bzl. Bzlmod doesn't need anything; it will |
| 143 | # register `:all`. |
Richard Levasseur | 68c3048 | 2024-07-16 16:22:22 -0700 | [diff] [blame] | 144 | |
| 145 | def define_local_toolchain_suites(name, version_aware_repo_names, version_unaware_repo_names): |
| 146 | """Define toolchains for `local_runtime_repo` backed toolchains. |
| 147 | |
| 148 | This generates `toolchain` targets that can be registered using `:all`. The |
| 149 | specific names of the toolchain targets are not defined. The priority order |
| 150 | of the toolchains is the order that is passed in, with version-aware having |
| 151 | higher priority than version-unaware. |
| 152 | |
| 153 | Args: |
| 154 | name: `str` Unused; only present to satisfy tooling. |
| 155 | version_aware_repo_names: `list[str]` of the repo names that will have |
| 156 | version-aware toolchains defined. |
| 157 | version_unaware_repo_names: `list[str]` of the repo names that will have |
| 158 | version-unaware toolchains defined. |
| 159 | """ |
| 160 | i = 0 |
| 161 | for i, repo in enumerate(version_aware_repo_names, start = i): |
| 162 | prefix = render.left_pad_zero(i, 4) |
| 163 | _internal_toolchain_suite( |
| 164 | prefix = prefix, |
| 165 | runtime_repo_name = repo, |
| 166 | target_compatible_with = ["@{}//:os".format(repo)], |
| 167 | target_settings = ["@{}//:is_matching_python_version".format(repo)], |
| 168 | ) |
| 169 | |
| 170 | # The version unaware entries must go last because they will match any Python |
| 171 | # version. |
| 172 | for i, repo in enumerate(version_unaware_repo_names, start = i + 1): |
| 173 | prefix = render.left_pad_zero(i, 4) |
| 174 | _internal_toolchain_suite( |
| 175 | prefix = prefix, |
| 176 | runtime_repo_name = repo, |
| 177 | target_settings = [], |
| 178 | target_compatible_with = ["@{}//:os".format(repo)], |
| 179 | ) |