|  | 
|  | 1 | +# Copyright 2024 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 | +"""This file contains repository rules and macros to support toolchain registration. | 
|  | 16 | +""" | 
|  | 17 | + | 
|  | 18 | +load( | 
|  | 19 | +    "//python:versions.bzl", | 
|  | 20 | +    "DEFAULT_RELEASE_BASE_URL", | 
|  | 21 | +    "MINOR_MAPPING", | 
|  | 22 | +    "PLATFORMS", | 
|  | 23 | +    "TOOL_VERSIONS", | 
|  | 24 | +    "get_release_info", | 
|  | 25 | +) | 
|  | 26 | +load(":bzlmod_enabled.bzl", "BZLMOD_ENABLED") | 
|  | 27 | +load(":coverage_deps.bzl", "coverage_dep") | 
|  | 28 | +load(":full_version.bzl", "full_version") | 
|  | 29 | +load(":python_repository.bzl", "python_repository") | 
|  | 30 | +load( | 
|  | 31 | +    ":toolchains_repo.bzl", | 
|  | 32 | +    "host_toolchain", | 
|  | 33 | +    "toolchain_aliases", | 
|  | 34 | +    "toolchains_repo", | 
|  | 35 | +) | 
|  | 36 | + | 
|  | 37 | +# Wrapper macro around everything above, this is the primary API. | 
|  | 38 | +def python_register_toolchains( | 
|  | 39 | +        name, | 
|  | 40 | +        python_version, | 
|  | 41 | +        register_toolchains = True, | 
|  | 42 | +        register_coverage_tool = False, | 
|  | 43 | +        set_python_version_constraint = False, | 
|  | 44 | +        tool_versions = None, | 
|  | 45 | +        minor_mapping = None, | 
|  | 46 | +        **kwargs): | 
|  | 47 | +    """Convenience macro for users which does typical setup. | 
|  | 48 | +
 | 
|  | 49 | +    - Create a repository for each built-in platform like "python_3_8_linux_amd64" - | 
|  | 50 | +      this repository is lazily fetched when Python is needed for that platform. | 
|  | 51 | +    - Create a repository exposing toolchains for each platform like | 
|  | 52 | +      "python_platforms". | 
|  | 53 | +    - Register a toolchain pointing at each platform. | 
|  | 54 | +
 | 
|  | 55 | +    Users can avoid this macro and do these steps themselves, if they want more | 
|  | 56 | +    control. | 
|  | 57 | +
 | 
|  | 58 | +    Args: | 
|  | 59 | +        name: {type}`str` base name for all created repos, e.g. "python_3_8". | 
|  | 60 | +        python_version: {type}`str` the Python version. | 
|  | 61 | +        register_toolchains: {type}`bool` Whether or not to register the downloaded toolchains. | 
|  | 62 | +        register_coverage_tool: {type}`bool` Whether or not to register the | 
|  | 63 | +            downloaded coverage tool to the toolchains. | 
|  | 64 | +        set_python_version_constraint: {type}`bool` When set to `True`, | 
|  | 65 | +            `target_compatible_with` for the toolchains will include a version | 
|  | 66 | +            constraint. | 
|  | 67 | +        tool_versions: {type}`dict` contains a mapping of version with SHASUM | 
|  | 68 | +            and platform info. If not supplied, the defaults in | 
|  | 69 | +            python/versions.bzl will be used. | 
|  | 70 | +        minor_mapping: {type}`dict[str, str]` contains a mapping from `X.Y` to `X.Y.Z` | 
|  | 71 | +            version. | 
|  | 72 | +        **kwargs: passed to each {obj}`python_repository` call. | 
|  | 73 | +    """ | 
|  | 74 | + | 
|  | 75 | +    if BZLMOD_ENABLED: | 
|  | 76 | +        # you cannot used native.register_toolchains when using bzlmod. | 
|  | 77 | +        register_toolchains = False | 
|  | 78 | + | 
|  | 79 | +    base_url = kwargs.pop("base_url", DEFAULT_RELEASE_BASE_URL) | 
|  | 80 | +    tool_versions = tool_versions or TOOL_VERSIONS | 
|  | 81 | +    minor_mapping = minor_mapping or MINOR_MAPPING | 
|  | 82 | + | 
|  | 83 | +    python_version = full_version(version = python_version, minor_mapping = minor_mapping) | 
|  | 84 | + | 
|  | 85 | +    toolchain_repo_name = "{name}_toolchains".format(name = name) | 
|  | 86 | + | 
|  | 87 | +    # When using unreleased Bazel versions, the version is an empty string | 
|  | 88 | +    if native.bazel_version: | 
|  | 89 | +        bazel_major = int(native.bazel_version.split(".")[0]) | 
|  | 90 | +        if bazel_major < 6: | 
|  | 91 | +            if register_coverage_tool: | 
|  | 92 | +                # buildifier: disable=print | 
|  | 93 | +                print(( | 
|  | 94 | +                    "WARNING: ignoring register_coverage_tool=True when " + | 
|  | 95 | +                    "registering @{name}: Bazel 6+ required, got {version}" | 
|  | 96 | +                ).format( | 
|  | 97 | +                    name = name, | 
|  | 98 | +                    version = native.bazel_version, | 
|  | 99 | +                )) | 
|  | 100 | +            register_coverage_tool = False | 
|  | 101 | + | 
|  | 102 | +    loaded_platforms = [] | 
|  | 103 | +    for platform in PLATFORMS.keys(): | 
|  | 104 | +        sha256 = tool_versions[python_version]["sha256"].get(platform, None) | 
|  | 105 | +        if not sha256: | 
|  | 106 | +            continue | 
|  | 107 | + | 
|  | 108 | +        loaded_platforms.append(platform) | 
|  | 109 | +        (release_filename, urls, strip_prefix, patches, patch_strip) = get_release_info(platform, python_version, base_url, tool_versions) | 
|  | 110 | + | 
|  | 111 | +        # allow passing in a tool version | 
|  | 112 | +        coverage_tool = None | 
|  | 113 | +        coverage_tool = tool_versions[python_version].get("coverage_tool", {}).get(platform, None) | 
|  | 114 | +        if register_coverage_tool and coverage_tool == None: | 
|  | 115 | +            coverage_tool = coverage_dep( | 
|  | 116 | +                name = "{name}_{platform}_coverage".format( | 
|  | 117 | +                    name = name, | 
|  | 118 | +                    platform = platform, | 
|  | 119 | +                ), | 
|  | 120 | +                python_version = python_version, | 
|  | 121 | +                platform = platform, | 
|  | 122 | +                visibility = ["@{name}_{platform}//:__subpackages__".format( | 
|  | 123 | +                    name = name, | 
|  | 124 | +                    platform = platform, | 
|  | 125 | +                )], | 
|  | 126 | +            ) | 
|  | 127 | + | 
|  | 128 | +        python_repository( | 
|  | 129 | +            name = "{name}_{platform}".format( | 
|  | 130 | +                name = name, | 
|  | 131 | +                platform = platform, | 
|  | 132 | +            ), | 
|  | 133 | +            sha256 = sha256, | 
|  | 134 | +            patches = patches, | 
|  | 135 | +            patch_strip = patch_strip, | 
|  | 136 | +            platform = platform, | 
|  | 137 | +            python_version = python_version, | 
|  | 138 | +            release_filename = release_filename, | 
|  | 139 | +            urls = urls, | 
|  | 140 | +            strip_prefix = strip_prefix, | 
|  | 141 | +            coverage_tool = coverage_tool, | 
|  | 142 | +            **kwargs | 
|  | 143 | +        ) | 
|  | 144 | +        if register_toolchains: | 
|  | 145 | +            native.register_toolchains("@{toolchain_repo_name}//:{platform}_toolchain".format( | 
|  | 146 | +                toolchain_repo_name = toolchain_repo_name, | 
|  | 147 | +                platform = platform, | 
|  | 148 | +            )) | 
|  | 149 | +            native.register_toolchains("@{toolchain_repo_name}//:{platform}_py_cc_toolchain".format( | 
|  | 150 | +                toolchain_repo_name = toolchain_repo_name, | 
|  | 151 | +                platform = platform, | 
|  | 152 | +            )) | 
|  | 153 | +            native.register_toolchains("@{toolchain_repo_name}//:{platform}_py_exec_tools_toolchain".format( | 
|  | 154 | +                toolchain_repo_name = toolchain_repo_name, | 
|  | 155 | +                platform = platform, | 
|  | 156 | +            )) | 
|  | 157 | + | 
|  | 158 | +    host_toolchain(name = name + "_host") | 
|  | 159 | + | 
|  | 160 | +    toolchain_aliases( | 
|  | 161 | +        name = name, | 
|  | 162 | +        python_version = python_version, | 
|  | 163 | +        user_repository_name = name, | 
|  | 164 | +        platforms = loaded_platforms, | 
|  | 165 | +    ) | 
|  | 166 | + | 
|  | 167 | +    # in bzlmod we write out our own toolchain repos | 
|  | 168 | +    if BZLMOD_ENABLED: | 
|  | 169 | +        return | 
|  | 170 | + | 
|  | 171 | +    toolchains_repo( | 
|  | 172 | +        name = toolchain_repo_name, | 
|  | 173 | +        python_version = python_version, | 
|  | 174 | +        set_python_version_constraint = set_python_version_constraint, | 
|  | 175 | +        user_repository_name = name, | 
|  | 176 | +    ) | 
0 commit comments