blob: d20e0496102322fa1db6a39a895126a2b8f4745e [file] [log] [blame]
# 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.
"""This file contains repository rules and macros to support toolchain registration.
"""
load(
"//python:versions.bzl",
"DEFAULT_RELEASE_BASE_URL",
"MINOR_MAPPING",
"PLATFORMS",
"TOOL_VERSIONS",
"get_release_info",
)
load(":bzlmod_enabled.bzl", "BZLMOD_ENABLED")
load(":coverage_deps.bzl", "coverage_dep")
load(":full_version.bzl", "full_version")
load(":python_repository.bzl", "python_repository")
load(
":toolchains_repo.bzl",
"host_toolchain",
"toolchain_aliases",
"toolchains_repo",
)
# Wrapper macro around everything above, this is the primary API.
def python_register_toolchains(
name,
python_version,
register_toolchains = True,
register_coverage_tool = False,
set_python_version_constraint = False,
tool_versions = None,
minor_mapping = None,
**kwargs):
"""Convenience macro for users which does typical setup.
With `bzlmod` enabled, this function is not needed since `rules_python` is
handling everything. In order to override the default behaviour from the
root module one can see the docs for the {rule}`python` extension.
- Create a repository for each built-in platform like "python_3_8_linux_amd64" -
this repository is lazily fetched when Python is needed for that platform.
- Create a repository exposing toolchains for each platform like
"python_platforms".
- Register a toolchain pointing at each platform.
Users can avoid this macro and do these steps themselves, if they want more
control.
Args:
name: {type}`str` base name for all created repos, e.g. "python_3_8".
python_version: {type}`str` the Python version.
register_toolchains: {type}`bool` Whether or not to register the downloaded toolchains.
register_coverage_tool: {type}`bool` Whether or not to register the
downloaded coverage tool to the toolchains.
set_python_version_constraint: {type}`bool` When set to `True`,
`target_compatible_with` for the toolchains will include a version
constraint.
tool_versions: {type}`dict` contains a mapping of version with SHASUM
and platform info. If not supplied, the defaults in
python/versions.bzl will be used.
minor_mapping: {type}`dict[str, str]` contains a mapping from `X.Y` to `X.Y.Z`
version.
**kwargs: passed to each {obj}`python_repository` call.
"""
if BZLMOD_ENABLED:
# you cannot used native.register_toolchains when using bzlmod.
register_toolchains = False
base_url = kwargs.pop("base_url", DEFAULT_RELEASE_BASE_URL)
tool_versions = tool_versions or TOOL_VERSIONS
minor_mapping = minor_mapping or MINOR_MAPPING
python_version = full_version(version = python_version, minor_mapping = minor_mapping)
toolchain_repo_name = "{name}_toolchains".format(name = name)
# When using unreleased Bazel versions, the version is an empty string
if native.bazel_version:
bazel_major = int(native.bazel_version.split(".")[0])
if bazel_major < 6:
if register_coverage_tool:
# buildifier: disable=print
print((
"WARNING: ignoring register_coverage_tool=True when " +
"registering @{name}: Bazel 6+ required, got {version}"
).format(
name = name,
version = native.bazel_version,
))
register_coverage_tool = False
loaded_platforms = []
for platform in PLATFORMS.keys():
sha256 = tool_versions[python_version]["sha256"].get(platform, None)
if not sha256:
continue
loaded_platforms.append(platform)
(release_filename, urls, strip_prefix, patches, patch_strip) = get_release_info(platform, python_version, base_url, tool_versions)
# allow passing in a tool version
coverage_tool = None
coverage_tool = tool_versions[python_version].get("coverage_tool", {}).get(platform, None)
if register_coverage_tool and coverage_tool == None:
coverage_tool = coverage_dep(
name = "{name}_{platform}_coverage".format(
name = name,
platform = platform,
),
python_version = python_version,
platform = platform,
visibility = ["@{name}_{platform}//:__subpackages__".format(
name = name,
platform = platform,
)],
)
python_repository(
name = "{name}_{platform}".format(
name = name,
platform = platform,
),
sha256 = sha256,
patches = patches,
patch_strip = patch_strip,
platform = platform,
python_version = python_version,
release_filename = release_filename,
urls = urls,
strip_prefix = strip_prefix,
coverage_tool = coverage_tool,
**kwargs
)
if register_toolchains:
native.register_toolchains("@{toolchain_repo_name}//:{platform}_toolchain".format(
toolchain_repo_name = toolchain_repo_name,
platform = platform,
))
native.register_toolchains("@{toolchain_repo_name}//:{platform}_py_cc_toolchain".format(
toolchain_repo_name = toolchain_repo_name,
platform = platform,
))
native.register_toolchains("@{toolchain_repo_name}//:{platform}_py_exec_tools_toolchain".format(
toolchain_repo_name = toolchain_repo_name,
platform = platform,
))
host_toolchain(name = name + "_host")
toolchain_aliases(
name = name,
python_version = python_version,
user_repository_name = name,
platforms = loaded_platforms,
)
# in bzlmod we write out our own toolchain repos
if BZLMOD_ENABLED:
return
toolchains_repo(
name = toolchain_repo_name,
python_version = python_version,
set_python_version_constraint = set_python_version_constraint,
user_repository_name = name,
)