• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (C) 2023 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
15load("@soong_injection//product_config_platforms:product_labels.bzl", _product_labels = "product_labels")
16load("//build/bazel/platforms/arch/variants:constants.bzl", _arch_constants = "constants")
17load(
18    "//build/bazel/toolchains/clang/host/linux-x86:cc_toolchain_constants.bzl",
19    "arch_to_variants",
20    "variant_constraints",
21    "variant_name",
22)
23load("@env//:env.bzl", "env")
24
25# This dict denotes the suffixes for host platforms (keys) and the constraints
26# associated with them (values). Used in transitions and tests, in addition to
27# here.
28host_platforms = {
29    "linux_x86": [
30        "@//build/bazel_common_rules/platforms/arch:x86",
31        "@//build/bazel_common_rules/platforms/os:linux",
32    ],
33    "linux_x86_64": [
34        "@//build/bazel_common_rules/platforms/arch:x86_64",
35        "@//build/bazel_common_rules/platforms/os:linux",
36    ],
37    "linux_musl_x86": [
38        "@//build/bazel_common_rules/platforms/arch:x86",
39        "@//build/bazel_common_rules/platforms/os:linux_musl",
40    ],
41    "linux_musl_x86_64": [
42        "@//build/bazel_common_rules/platforms/arch:x86_64",
43        "@//build/bazel_common_rules/platforms/os:linux_musl",
44    ],
45    # linux_bionic is the OS for the Linux kernel plus the Bionic libc runtime,
46    # but without the rest of Android.
47    "linux_bionic_arm64": [
48        "@//build/bazel_common_rules/platforms/arch:arm64",
49        "@//build/bazel_common_rules/platforms/os:linux_bionic",
50    ],
51    "linux_bionic_x86_64": [
52        "@//build/bazel_common_rules/platforms/arch:x86_64",
53        "@//build/bazel_common_rules/platforms/os:linux_bionic",
54    ],
55    "darwin_arm64": [
56        "@//build/bazel_common_rules/platforms/arch:arm64",
57        "@//build/bazel_common_rules/platforms/os:darwin",
58    ],
59    "darwin_x86_64": [
60        "@//build/bazel_common_rules/platforms/arch:x86_64",
61        "@//build/bazel_common_rules/platforms/os:darwin",
62    ],
63    "windows_x86": [
64        "@//build/bazel_common_rules/platforms/arch:x86",
65        "@//build/bazel_common_rules/platforms/os:windows",
66    ],
67    "windows_x86_64": [
68        "@//build/bazel_common_rules/platforms/arch:x86_64",
69        "@//build/bazel_common_rules/platforms/os:windows",
70    ],
71}
72
73def _is_variant_default(arch, variant):
74    return variant == None or variant in (arch, "generic")
75
76def _soong_arch_config_to_struct(soong_arch_config):
77    return struct(
78        arch = soong_arch_config["arch"],
79        arch_variant = soong_arch_config["arch_variant"],
80        cpu_variant = soong_arch_config["cpu_variant"],
81    )
82
83def _determine_target_arches_from_config(config):
84    arches = []
85
86    # ndk_abis and aml_abis explicitly get handled first as they override any setting
87    # for DeviceArch, DeviceSecondaryArch in Soong:
88    # https://cs.android.com/android/platform/superproject/+/master:build/soong/android/config.go;l=455-468;drc=b45a2ea782074944f79fc388df20b06e01f265f7
89    if config.get("Ndk_abis"):
90        for arch_config in _arch_constants.ndk_arches:
91            arches.append(_soong_arch_config_to_struct(arch_config))
92        return arches
93    elif config.get("Aml_abis"):
94        for arch_config in _arch_constants.aml_arches:
95            arches.append(_soong_arch_config_to_struct(arch_config))
96        return arches
97
98    arch = config.get("DeviceArch")
99    arch_variant = config.get("DeviceArchVariant")
100    cpu_variant = config.get("DeviceCpuVariant")
101
102    if _is_variant_default(arch, arch_variant):
103        arch_variant = ""
104    if _is_variant_default(arch, cpu_variant):
105        cpu_variant = ""
106
107    if not arch:
108        # TODO(b/258839711): determine how to better id whether a config is actually host only or we're just missing the target config
109        if "DeviceArch" in config:
110            fail("No architecture was specified in the product config, expected one of Ndk_abis, Aml_abis, or DeviceArch to be set:\n%s" % config)
111        else:
112            return arches
113
114    arches.append(struct(
115        arch = arch,
116        arch_variant = arch_variant,
117        cpu_variant = cpu_variant,
118    ))
119
120    arch = config.get("DeviceSecondaryArch")
121    arch_variant = config.get("DeviceSecondaryArchVariant")
122    cpu_variant = config.get("DeviceSecondaryCpuVariant")
123
124    if _is_variant_default(arch, arch_variant):
125        arch_variant = ""
126    if _is_variant_default(arch, cpu_variant):
127        cpu_variant = ""
128
129    if arch:
130        arches.append(struct(
131            arch = arch,
132            arch_variant = arch_variant,
133            cpu_variant = cpu_variant,
134        ))
135    return arches
136
137def _define_platform_for_arch(name, common_constraints, arch, secondary_arch = None):
138    if secondary_arch == None:
139        # When there is no secondary arch, we'll pretend it exists but is the same as the primary arch
140        secondary_arch = arch
141    native.platform(
142        name = name,
143        constraint_values = common_constraints + [
144            "@//build/bazel_common_rules/platforms/arch:" + arch.arch,
145            "@//build/bazel_common_rules/platforms/arch:secondary_" + secondary_arch.arch,
146            "@//build/bazel_common_rules/platforms/os:android",
147        ] + ["@" + v for v in variant_constraints(
148            arch,
149            _arch_constants.AndroidArchToVariantToFeatures[arch.arch],
150        )],
151    )
152
153def _define_platform_for_arch_with_secondary(name, common_constraints, arch, secondary_arch = None):
154    if secondary_arch != None:
155        _define_platform_for_arch(name, common_constraints, arch, secondary_arch)
156        _define_platform_for_arch(name + "_secondary", common_constraints, secondary_arch)
157    else:
158        _define_platform_for_arch(name, common_constraints, arch)
159        native.alias(
160            name = name + "_secondary",
161            actual = ":" + name,
162        )
163
164def _verify_product_is_registered(name):
165    """
166    Verifies that this android_product() is listed in _product_labels.
167
168    _product_labels is used to build a platform_mappings file entry from each product to its
169    build settings. This is because we store most product configuration in build settings, and
170    currently the only way to set build settings based on a certain platform is with a
171    platform_mappings file.
172    """
173    my_label = native.repository_name() + "//" + native.package_name() + ":" + name
174    for label in _product_labels:
175        if my_label == label:
176            return
177    fail("All android_product() instances must have an entry in the platform_mappings file " +
178         "generated by bp2build. By default the products generated from legacy android product " +
179         "configurations and products listed in //build/bazel/tests/products:product_labels.bzl " +
180         "are included.")
181
182def android_product(*, name, soong_variables, extra_constraints = []):
183    """
184    android_product integrates product variables into Bazel platforms.
185
186    This uses soong.variables to create constraints and platforms used by the
187    bazel build. The soong.variables file itself contains a post-processed list of
188    variables derived from Make variables, through soong_config.mk, generated
189    during the product config step.
190
191    Some constraints used here are handcrafted in
192    //build/bazel_common_rules/platforms/{arch,os}. The rest are dynamically generated.
193
194    If you're looking for what --config=android, --config=linux_x86_64 or most
195    select statements in the BUILD files (ultimately) refer to, they're all
196    created here.
197    """
198    _verify_product_is_registered(name)
199
200    arch_configs = _determine_target_arches_from_config(soong_variables)
201
202    common_constraints = extra_constraints
203
204    # TODO(b/258802089): figure out how to deal with multiple arches for target
205    if len(arch_configs) > 0:
206        arch = arch_configs[0]
207        secondary_arch = None
208        if len(arch_configs) > 1:
209            secondary_arch = arch_configs[1]
210
211        _define_platform_for_arch_with_secondary(name, common_constraints, arch, secondary_arch)
212
213        # These variants are mostly for mixed builds, which may request a
214        # module with a certain arch
215        for arch, variants in arch_to_variants.items():
216            for variant in variants:
217                native.platform(
218                    name = name + "_android_" + arch + variant_name(variant),
219                    constraint_values = common_constraints + [
220                        "@//build/bazel_common_rules/platforms/arch:" + arch,
221                        "@//build/bazel_common_rules/platforms/arch:secondary_" + arch,
222                        "@//build/bazel_common_rules/platforms/os:android",
223                    ] + ["@" + v for v in variant_constraints(
224                        variant,
225                        _arch_constants.AndroidArchToVariantToFeatures[arch],
226                    )],
227                )
228
229        arch_transitions = [
230            struct(
231                name = "arm",
232                arch = struct(
233                    arch = "arm",
234                    arch_variant = "armv7-a-neon",
235                    cpu_variant = "",
236                ),
237                secondary_arch = None,
238            ),
239            struct(
240                name = "arm64",
241                arch = struct(
242                    arch = "arm64",
243                    arch_variant = "armv8-a",
244                    cpu_variant = "",
245                ),
246                secondary_arch = struct(
247                    arch = "arm",
248                    arch_variant = "armv7-a-neon",
249                    cpu_variant = "",
250                ),
251            ),
252            struct(
253                name = "arm64only",
254                arch = struct(
255                    arch = "arm64",
256                    arch_variant = "armv8-a",
257                    cpu_variant = "",
258                ),
259                secondary_arch = None,
260            ),
261            struct(
262                name = "x86",
263                arch = struct(
264                    arch = "x86",
265                    arch_variant = "",
266                    cpu_variant = "",
267                ),
268                secondary_arch = None,
269            ),
270            struct(
271                name = "x86_64",
272                arch = struct(
273                    arch = "x86_64",
274                    arch_variant = "",
275                    cpu_variant = "",
276                ),
277                secondary_arch = struct(
278                    arch = "x86",
279                    arch_variant = "",
280                    cpu_variant = "",
281                ),
282            ),
283            struct(
284                name = "x86_64only",
285                arch = struct(
286                    arch = "x86_64",
287                    arch_variant = "",
288                    cpu_variant = "",
289                ),
290                secondary_arch = None,
291            ),
292        ]
293
294        # TODO(b/249685973): Remove this, this is currently just for aabs
295        # to build each architecture
296        for arch in arch_transitions:
297            _define_platform_for_arch_with_secondary(name + "__internal_" + arch.name, common_constraints, arch.arch, arch.secondary_arch)
298
299    # Now define the host platforms. We need a host platform per product because
300    # the host platforms still use the product variables.
301    # TODO(b/262753134): Investigate making the host platforms product-independant
302    for suffix, constraints in host_platforms.items():
303        # Add RBE properties if the host platform support it.
304        exec_properties = {}
305        if "linux" in suffix and env.get("DEVICE_TEST_RBE_DOCKER_IMAGE_LINK"):
306            exec_properties = {
307                "container-image": env.get("DEVICE_TEST_RBE_DOCKER_IMAGE_LINK").replace("_atChar_", "@").replace("_colonChar_", ":"),
308                "dockerNetwork": "standard",
309                "dockerPrivileged": "true",
310                "dockerRunAsRoot": "true",
311                "OSFamily": "Linux",
312            }
313        native.platform(
314            name = name + "_" + suffix,
315            constraint_values = common_constraints + constraints,
316            exec_properties = exec_properties,
317        )
318