xref: /aosp_15_r20/external/bazelbuild-rules_python/python/private/config_settings.bzl (revision 60517a1edbc8ecf509223e9af94a7adec7d736b8)
1*60517a1eSAndroid Build Coastguard Worker# Copyright 2024 The Bazel Authors. All rights reserved.
2*60517a1eSAndroid Build Coastguard Worker#
3*60517a1eSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
4*60517a1eSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
5*60517a1eSAndroid Build Coastguard Worker# You may obtain a copy of the License at
6*60517a1eSAndroid Build Coastguard Worker#
7*60517a1eSAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
8*60517a1eSAndroid Build Coastguard Worker#
9*60517a1eSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
10*60517a1eSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
11*60517a1eSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*60517a1eSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
13*60517a1eSAndroid Build Coastguard Worker# limitations under the License.
14*60517a1eSAndroid Build Coastguard Worker
15*60517a1eSAndroid Build Coastguard Worker"""This module is used to construct the config settings in the BUILD file in this same package.
16*60517a1eSAndroid Build Coastguard Worker"""
17*60517a1eSAndroid Build Coastguard Worker
18*60517a1eSAndroid Build Coastguard Workerload("@bazel_skylib//lib:selects.bzl", "selects")
19*60517a1eSAndroid Build Coastguard Workerload("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
20*60517a1eSAndroid Build Coastguard Workerload(":semver.bzl", "semver")
21*60517a1eSAndroid Build Coastguard Worker
22*60517a1eSAndroid Build Coastguard Worker_PYTHON_VERSION_FLAG = Label("//python/config_settings:python_version")
23*60517a1eSAndroid Build Coastguard Worker_PYTHON_VERSION_MAJOR_MINOR_FLAG = Label("//python/config_settings:_python_version_major_minor")
24*60517a1eSAndroid Build Coastguard Worker
25*60517a1eSAndroid Build Coastguard Workerdef construct_config_settings(*, name, versions, minor_mapping):  # buildifier: disable=function-docstring
26*60517a1eSAndroid Build Coastguard Worker    """Create a 'python_version' config flag and construct all config settings used in rules_python.
27*60517a1eSAndroid Build Coastguard Worker
28*60517a1eSAndroid Build Coastguard Worker    This mainly includes the targets that are used in the toolchain and pip hub
29*60517a1eSAndroid Build Coastguard Worker    repositories that only match on the 'python_version' flag values.
30*60517a1eSAndroid Build Coastguard Worker
31*60517a1eSAndroid Build Coastguard Worker    Args:
32*60517a1eSAndroid Build Coastguard Worker        name: {type}`str` A dummy name value that is no-op for now.
33*60517a1eSAndroid Build Coastguard Worker        versions: {type}`list[str]` A list of versions to build constraint settings for.
34*60517a1eSAndroid Build Coastguard Worker        minor_mapping: {type}`dict[str, str]` A mapping from `X.Y` to `X.Y.Z` python versions.
35*60517a1eSAndroid Build Coastguard Worker    """
36*60517a1eSAndroid Build Coastguard Worker    _ = name  # @unused
37*60517a1eSAndroid Build Coastguard Worker    _python_version_flag(
38*60517a1eSAndroid Build Coastguard Worker        name = _PYTHON_VERSION_FLAG.name,
39*60517a1eSAndroid Build Coastguard Worker        # TODO: The default here should somehow match the MODULE config. Until
40*60517a1eSAndroid Build Coastguard Worker        # then, use the empty string to indicate an unknown version. This
41*60517a1eSAndroid Build Coastguard Worker        # also prevents version-unaware targets from inadvertently matching
42*60517a1eSAndroid Build Coastguard Worker        # a select condition when they shouldn't.
43*60517a1eSAndroid Build Coastguard Worker        build_setting_default = "",
44*60517a1eSAndroid Build Coastguard Worker        visibility = ["//visibility:public"],
45*60517a1eSAndroid Build Coastguard Worker    )
46*60517a1eSAndroid Build Coastguard Worker
47*60517a1eSAndroid Build Coastguard Worker    _python_version_major_minor_flag(
48*60517a1eSAndroid Build Coastguard Worker        name = _PYTHON_VERSION_MAJOR_MINOR_FLAG.name,
49*60517a1eSAndroid Build Coastguard Worker        build_setting_default = "",
50*60517a1eSAndroid Build Coastguard Worker        visibility = ["//visibility:public"],
51*60517a1eSAndroid Build Coastguard Worker    )
52*60517a1eSAndroid Build Coastguard Worker
53*60517a1eSAndroid Build Coastguard Worker    native.config_setting(
54*60517a1eSAndroid Build Coastguard Worker        name = "is_python_version_unset",
55*60517a1eSAndroid Build Coastguard Worker        flag_values = {_PYTHON_VERSION_FLAG: ""},
56*60517a1eSAndroid Build Coastguard Worker        visibility = ["//visibility:public"],
57*60517a1eSAndroid Build Coastguard Worker    )
58*60517a1eSAndroid Build Coastguard Worker
59*60517a1eSAndroid Build Coastguard Worker    _reverse_minor_mapping = {full: minor for minor, full in minor_mapping.items()}
60*60517a1eSAndroid Build Coastguard Worker    for version in versions:
61*60517a1eSAndroid Build Coastguard Worker        minor_version = _reverse_minor_mapping.get(version)
62*60517a1eSAndroid Build Coastguard Worker        if not minor_version:
63*60517a1eSAndroid Build Coastguard Worker            native.config_setting(
64*60517a1eSAndroid Build Coastguard Worker                name = "is_python_{}".format(version),
65*60517a1eSAndroid Build Coastguard Worker                flag_values = {":python_version": version},
66*60517a1eSAndroid Build Coastguard Worker                visibility = ["//visibility:public"],
67*60517a1eSAndroid Build Coastguard Worker            )
68*60517a1eSAndroid Build Coastguard Worker            continue
69*60517a1eSAndroid Build Coastguard Worker
70*60517a1eSAndroid Build Coastguard Worker        # Also need to match the minor version when using
71*60517a1eSAndroid Build Coastguard Worker        name = "is_python_{}".format(version)
72*60517a1eSAndroid Build Coastguard Worker        native.config_setting(
73*60517a1eSAndroid Build Coastguard Worker            name = "_" + name,
74*60517a1eSAndroid Build Coastguard Worker            flag_values = {":python_version": version},
75*60517a1eSAndroid Build Coastguard Worker            visibility = ["//visibility:public"],
76*60517a1eSAndroid Build Coastguard Worker        )
77*60517a1eSAndroid Build Coastguard Worker
78*60517a1eSAndroid Build Coastguard Worker        # An alias pointing to an underscore-prefixed config_setting_group
79*60517a1eSAndroid Build Coastguard Worker        # is used because config_setting_group creates
80*60517a1eSAndroid Build Coastguard Worker        # `is_{version}_N` targets, which are easily confused with the
81*60517a1eSAndroid Build Coastguard Worker        # `is_{minor}.{micro}` (dot) targets.
82*60517a1eSAndroid Build Coastguard Worker        selects.config_setting_group(
83*60517a1eSAndroid Build Coastguard Worker            name = "_{}_group".format(name),
84*60517a1eSAndroid Build Coastguard Worker            match_any = [
85*60517a1eSAndroid Build Coastguard Worker                ":_is_python_{}".format(version),
86*60517a1eSAndroid Build Coastguard Worker                ":is_python_{}".format(minor_version),
87*60517a1eSAndroid Build Coastguard Worker            ],
88*60517a1eSAndroid Build Coastguard Worker            visibility = ["//visibility:private"],
89*60517a1eSAndroid Build Coastguard Worker        )
90*60517a1eSAndroid Build Coastguard Worker        native.alias(
91*60517a1eSAndroid Build Coastguard Worker            name = name,
92*60517a1eSAndroid Build Coastguard Worker            actual = "_{}_group".format(name),
93*60517a1eSAndroid Build Coastguard Worker            visibility = ["//visibility:public"],
94*60517a1eSAndroid Build Coastguard Worker        )
95*60517a1eSAndroid Build Coastguard Worker
96*60517a1eSAndroid Build Coastguard Worker    # This matches the raw flag value, e.g. --//python/config_settings:python_version=3.8
97*60517a1eSAndroid Build Coastguard Worker    # It's private because matching the concept of e.g. "3.8" value is done
98*60517a1eSAndroid Build Coastguard Worker    # using the `is_python_X.Y` config setting group, which is aware of the
99*60517a1eSAndroid Build Coastguard Worker    # minor versions that could match instead.
100*60517a1eSAndroid Build Coastguard Worker    for minor in minor_mapping.keys():
101*60517a1eSAndroid Build Coastguard Worker        native.config_setting(
102*60517a1eSAndroid Build Coastguard Worker            name = "is_python_{}".format(minor),
103*60517a1eSAndroid Build Coastguard Worker            flag_values = {_PYTHON_VERSION_MAJOR_MINOR_FLAG: minor},
104*60517a1eSAndroid Build Coastguard Worker            visibility = ["//visibility:public"],
105*60517a1eSAndroid Build Coastguard Worker        )
106*60517a1eSAndroid Build Coastguard Worker
107*60517a1eSAndroid Build Coastguard Workerdef _python_version_flag_impl(ctx):
108*60517a1eSAndroid Build Coastguard Worker    value = ctx.build_setting_value
109*60517a1eSAndroid Build Coastguard Worker    return [
110*60517a1eSAndroid Build Coastguard Worker        # BuildSettingInfo is the original provider returned, so continue to
111*60517a1eSAndroid Build Coastguard Worker        # return it for compatibility
112*60517a1eSAndroid Build Coastguard Worker        BuildSettingInfo(value = value),
113*60517a1eSAndroid Build Coastguard Worker        # FeatureFlagInfo is returned so that config_setting respects the value
114*60517a1eSAndroid Build Coastguard Worker        # as returned by this rule instead of as originally seen on the command
115*60517a1eSAndroid Build Coastguard Worker        # line.
116*60517a1eSAndroid Build Coastguard Worker        # It is also for Google compatibility, which expects the FeatureFlagInfo
117*60517a1eSAndroid Build Coastguard Worker        # provider.
118*60517a1eSAndroid Build Coastguard Worker        config_common.FeatureFlagInfo(value = value),
119*60517a1eSAndroid Build Coastguard Worker    ]
120*60517a1eSAndroid Build Coastguard Worker
121*60517a1eSAndroid Build Coastguard Worker_python_version_flag = rule(
122*60517a1eSAndroid Build Coastguard Worker    implementation = _python_version_flag_impl,
123*60517a1eSAndroid Build Coastguard Worker    build_setting = config.string(flag = True),
124*60517a1eSAndroid Build Coastguard Worker    attrs = {},
125*60517a1eSAndroid Build Coastguard Worker)
126*60517a1eSAndroid Build Coastguard Worker
127*60517a1eSAndroid Build Coastguard Workerdef _python_version_major_minor_flag_impl(ctx):
128*60517a1eSAndroid Build Coastguard Worker    input = ctx.attr._python_version_flag[config_common.FeatureFlagInfo].value
129*60517a1eSAndroid Build Coastguard Worker    if input:
130*60517a1eSAndroid Build Coastguard Worker        version = semver(input)
131*60517a1eSAndroid Build Coastguard Worker        value = "{}.{}".format(version.major, version.minor)
132*60517a1eSAndroid Build Coastguard Worker    else:
133*60517a1eSAndroid Build Coastguard Worker        value = ""
134*60517a1eSAndroid Build Coastguard Worker
135*60517a1eSAndroid Build Coastguard Worker    return [config_common.FeatureFlagInfo(value = value)]
136*60517a1eSAndroid Build Coastguard Worker
137*60517a1eSAndroid Build Coastguard Worker_python_version_major_minor_flag = rule(
138*60517a1eSAndroid Build Coastguard Worker    implementation = _python_version_major_minor_flag_impl,
139*60517a1eSAndroid Build Coastguard Worker    build_setting = config.string(flag = False),
140*60517a1eSAndroid Build Coastguard Worker    attrs = {
141*60517a1eSAndroid Build Coastguard Worker        "_python_version_flag": attr.label(
142*60517a1eSAndroid Build Coastguard Worker            default = _PYTHON_VERSION_FLAG,
143*60517a1eSAndroid Build Coastguard Worker        ),
144*60517a1eSAndroid Build Coastguard Worker    },
145*60517a1eSAndroid Build Coastguard Worker)
146