xref: /aosp_15_r20/build/bazel/platforms/platform_utils.bzl (revision 7594170e27e0732bc44b93d1440d87a54b6ffe7c)
1# Copyright (C) 2022 The Android Open Source Project
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"""
16platform_utils.bzl defines a platform_utils rule, and several
17utility functions that accept an instance of that rule and return
18information about the target platform. One instance of the platform_utils
19rule is defined in //build/bazel/platforms:platform_utils. All rules
20that need it can depend on that target, and then call the util
21functions by doing something like `is_target_linux(ctx.attr._platform_utils)`.
22This works because child targets inherit their parent's configuration.
23"""
24
25_name_to_constraint = {
26    "_x86_constraint": "//build/bazel_common_rules/platforms/arch:x86",
27    "_x86_64_constraint": "//build/bazel_common_rules/platforms/arch:x86_64",
28    "_arm_constraint": "//build/bazel_common_rules/platforms/arch:arm",
29    "_arm64_constraint": "//build/bazel_common_rules/platforms/arch:arm64",
30    "_secondary_x86_constraint": "//build/bazel_common_rules/platforms/arch:secondary_x86",
31    "_secondary_x86_64_constraint": "//build/bazel_common_rules/platforms/arch:secondary_x86_64",
32    "_secondary_arm_constraint": "//build/bazel_common_rules/platforms/arch:secondary_arm",
33    "_secondary_arm64_constraint": "//build/bazel_common_rules/platforms/arch:secondary_arm64",
34    "_android_constraint": "//build/bazel_common_rules/platforms/os:android",
35    "_linux_constraint": "//build/bazel_common_rules/platforms/os:linux",
36    "_linux_musl_constraint": "//build/bazel_common_rules/platforms/os:linux_musl",
37    "_linux_bionic_constraint": "//build/bazel_common_rules/platforms/os:linux_bionic",
38    "_darwin_constraint": "//build/bazel_common_rules/platforms/os:darwin",
39}
40
41_AndroidPlatformUtilsInfo = provider(
42    "_AndroidPlatformUtilsInfo exports metadata about what platform the code is being run on.",
43    fields = {
44        "target" + name: "Whether the target platform has the constraint %s" % constraint
45        for name, constraint in _name_to_constraint.items()
46    },
47)
48
49def _platform_utils_impl(ctx):
50    return [
51        _AndroidPlatformUtilsInfo(**{
52            "target" + name: ctx.target_platform_has_constraint(getattr(ctx.attr, name)[platform_common.ConstraintValueInfo])
53            for name in _name_to_constraint
54        }),
55    ]
56
57platform_utils = rule(
58    implementation = _platform_utils_impl,
59    attrs = {
60        name: attr.label(
61            default = Label(constraint),
62            doc = "An internal reference to the constraint so it can be used in the rule implementation.",
63        )
64        for name, constraint in _name_to_constraint.items()
65    },
66)
67
68def _get_platform_info(utils):
69    if _AndroidPlatformUtilsInfo not in utils:
70        fail("Provided object was not an instance of platform_utils. " +
71             "You should depend on //build/bazel/platforms:platform_utils and then pass " +
72             "ctx.attr._platform_utils to this function.")
73    return utils[_AndroidPlatformUtilsInfo]
74
75def _is_target_linux(utils):
76    """Returns if the target platform is linux with any variation of libc."""
77    platforminfo = _get_platform_info(utils)
78    return (platforminfo.target_linux_constraint or
79            platforminfo.target_linux_musl_constraint or
80            platforminfo.target_linux_bionic_constraint)
81
82def _is_target_android(utils):
83    """Returns if the target platform is android."""
84    return _get_platform_info(utils).target_android_constraint
85
86def _is_target_darwin(utils):
87    """Returns if the target platform is darwin."""
88    return _get_platform_info(utils).target_darwin_constraint
89
90def _is_target_linux_or_android(utils):
91    """Returns if the target platform is linux with any variation of libc, or android."""
92    return _is_target_linux(utils) or _is_target_android(utils)
93
94def _is_target_bionic(utils):
95    """Returns if the target platform uses the Bionic libc"""
96    return _is_target_linux_bionic(utils) or _is_target_android(utils)
97
98def _is_target_linux_bionic(utils):
99    """Returns if the target platform runs (non-Android) Linux and uses the Bionic libc"""
100    return _get_platform_info(utils).target_linux_bionic_constraint
101
102def _get_target_bitness(utils):
103    """Returns 32 or 64 depending on the bitness of the target platform."""
104    platforminfo = _get_platform_info(utils)
105
106    if platforminfo.target_x86_constraint or platforminfo.target_arm_constraint:
107        return 32
108    elif platforminfo.target_x86_64_constraint or platforminfo.target_arm64_constraint:
109        return 64
110    fail("Unable to determine target bitness")
111
112def _get_target_arch(utils):
113    """Returns 'x86', 'x86_64', 'arm', or 'arm64' depending on the target platform."""
114    platforminfo = _get_platform_info(utils)
115
116    if platforminfo.target_x86_constraint:
117        return "x86"
118    elif platforminfo.target_x86_64_constraint:
119        return "x86_64"
120    elif platforminfo.target_arm_constraint:
121        return "arm"
122    elif platforminfo.target_arm64_constraint:
123        return "arm64"
124
125    fail("Unable to determine target arch")
126
127def _get_target_secondary_arch(utils):
128    """
129    Returns 'x86', 'x86_64', 'arm', 'arm64', or '' depending on the target platform.
130
131    If the secondary arch is the same as the primary arch, an empty string will be returned.
132    This is supposed to indicate that no secondary arch exists. The main motivation for this
133    behavior is in soong.variables, DeviceSecondaryArch and related variables are empty
134    strings when they don't exist, so a lot of code revolves around that. However in bazel
135    a constraint setting must always have a value, and a "none" value would probably
136    introduce more problems, so instead the secondary arch copies the primary arch if it
137    doesn't exist.
138    """
139    platforminfo = _get_platform_info(utils)
140
141    result = ""
142    if platforminfo.target_secondary_x86_constraint:
143        result = "x86"
144    elif platforminfo.target_secondary_x86_64_constraint:
145        result = "x86_64"
146    elif platforminfo.target_secondary_arm_constraint:
147        result = "arm"
148    elif platforminfo.target_secondary_arm64_constraint:
149        result = "arm64"
150    else:
151        fail("Unable to determine target secondary arch")
152
153    if _get_target_arch(utils) == result:
154        return ""
155    return result
156
157platforms = struct(
158    is_target_linux = _is_target_linux,
159    is_target_android = _is_target_android,
160    is_target_bionic = _is_target_bionic,
161    is_target_darwin = _is_target_darwin,
162    is_target_linux_or_android = _is_target_linux_or_android,
163    get_target_bitness = _get_target_bitness,
164    get_target_arch = _get_target_arch,
165    get_target_secondary_arch = _get_target_secondary_arch,
166)
167