xref: /aosp_15_r20/build/bazel/toolchains/clang/host/linux-x86/cc_toolchain_features.bzl (revision 7594170e27e0732bc44b93d1440d87a54b6ffe7c)
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
15"""Feature definitions for Android's C/C++ toolchain.
16
17This top level list of features are available through the get_features function.
18"""
19
20load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
21load(
22    "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl",
23    "feature",
24    "feature_set",
25    "flag_group",
26    "flag_set",
27    "variable_with_value",
28    "with_feature_set",
29)
30load("@soong_injection//api_levels:platform_versions.bzl", "platform_versions")
31load("//build/bazel/rules/common:api.bzl", "api")
32load(
33    ":cc_toolchain_constants.bzl",
34    _actions = "actions",
35    _arches = "arches",
36    _c_std_versions = "c_std_versions",
37    _cpp_std_versions = "cpp_std_versions",
38    _default_c_std_version = "default_c_std_version",
39    _default_cpp_std_version = "default_cpp_std_version",
40    _default_cpp_std_version_no_gnu = "default_cpp_std_version_no_gnu",
41    _experimental_cpp_std_version = "experimental_cpp_std_version",
42    _experimental_cpp_std_version_no_gnu = "experimental_cpp_std_version_no_gnu",
43    _flags = "flags",
44    _generated_config_constants = "generated_config_constants",
45    _generated_sanitizer_constants = "generated_sanitizer_constants",
46    _oses = "oses",
47)
48
49def is_os_device(os):
50    return os == _oses.Android
51
52def is_os_bionic(os):
53    return os == _oses.Android or os == _oses.LinuxBionic
54
55def _sdk_version_features_between(start, end):
56    return ["sdk_version_" + str(i) for i in range(start, end + 1)]
57
58def _sdk_version_features_before(version):
59    return _sdk_version_features_between(1, version - 1)
60
61def _get_sdk_version_features(os_is_device, target_arch):
62    if not os_is_device:
63        return []
64
65    default_sdk_version = "10000"
66    sdk_feature_prefix = "sdk_version_"
67    all_sdk_versions = [default_sdk_version]
68    for level in api.api_levels.values():
69        all_sdk_versions.append(str(level))
70
71    # Explicitly support internal branch state where the platform sdk version has
72    # finalized, but the sdk is still active, so it's represented by a 9000-ish
73    # value in api_levels.
74    platform_sdk_version = str(platform_versions.platform_sdk_version)
75    if platform_sdk_version not in all_sdk_versions:
76        all_sdk_versions.append(platform_sdk_version)
77
78    flag_prefix = "--target="
79    if target_arch == _arches.X86:
80        flag_prefix += "i686-linux-android"
81    elif target_arch == _arches.X86_64:
82        flag_prefix += "x86_64-linux-android"
83    elif target_arch == _arches.Arm:
84        flag_prefix += _generated_config_constants.ArmClangTriple
85    elif target_arch == _arches.Arm64:
86        flag_prefix += "aarch64-linux-android"
87    else:
88        fail("Unknown target arch %s" % (target_arch))
89
90    features = [feature(
91        name = "sdk_version_default",
92        enabled = True,
93        implies = [sdk_feature_prefix + default_sdk_version],
94    )]
95    features.extend([
96        feature(name = sdk_feature_prefix + sdk_version, provides = ["sdk_version"])
97        for sdk_version in all_sdk_versions
98    ])
99    features.append(feature(
100        name = "sdk_version_flag",
101        enabled = True,
102        flag_sets = [
103            flag_set(
104                actions = _actions.compile + _actions.link,
105                flag_groups = [
106                    flag_group(
107                        flags = [flag_prefix + sdk_version],
108                    ),
109                ],
110                with_features = [
111                    with_feature_set(
112                        features = [sdk_feature_prefix + sdk_version],
113                    ),
114                ],
115            )
116            for sdk_version in all_sdk_versions
117        ],
118    ))
119    return features
120
121def _get_c_std_features():
122    features = []
123    features.append(feature(
124        # The default cpp_std feature. Remember to disable
125        # this feature if enabling another cpp_std feature.
126        name = "cpp_std_default",
127        enabled = True,
128        implies = [_default_cpp_std_version],
129    ))
130    features.append(feature(
131        # The default c_std feature. Remember to disable
132        # this feature if enabling another cpp_std feature.
133        name = "c_std_default",
134        enabled = True,
135        implies = [_default_c_std_version],
136    ))
137
138    features.append(feature(
139        name = "cpp_std_default_no_gnu",
140        implies = [_default_cpp_std_version_no_gnu],
141    ))
142    features.append(feature(
143        name = "c_std_default_no_gnu",
144        implies = [_default_cpp_std_version_no_gnu],
145    ))
146    features.append(feature(
147        name = "cpp_std_experimental",
148        implies = [_experimental_cpp_std_version],
149    ))
150    features.append(feature(
151        name = "c_std_experimental",
152        implies = [_experimental_cpp_std_version],
153    ))
154    features.append(feature(
155        name = "cpp_std_experimental_no_gnu",
156        implies = [_experimental_cpp_std_version_no_gnu],
157    ))
158    features.append(feature(
159        name = "c_std_experimental_no_gnu",
160        implies = [_experimental_cpp_std_version_no_gnu],
161    ))
162    features.extend([
163        feature(name = std_version, provides = ["cpp_std"])
164        for std_version in _cpp_std_versions
165    ])
166    features.extend([
167        feature(name = std_version, provides = ["c_std"])
168        for std_version in _c_std_versions
169    ])
170    features.append(feature(
171        name = "cpp_std_flag",
172        enabled = True,
173        # Create the -std flag group for each of the std versions,
174        # enabled with with_feature_set.
175        flag_sets = [
176            flag_set(
177                actions = [_actions.cpp_compile],
178                flag_groups = [
179                    flag_group(
180                        flags = ["-std=" + std_version],
181                    ),
182                ],
183                with_features = [
184                    with_feature_set(
185                        features = [std_version],
186                    ),
187                ],
188            )
189            for std_version in _cpp_std_versions
190        ],
191    ))
192    features.append(feature(
193        name = "c_std_flag",
194        enabled = True,
195        # Create the -std flag group for each of the std versions,
196        # enabled with with_feature_set.
197        flag_sets = [
198            flag_set(
199                actions = [_actions.c_compile],
200                flag_groups = [
201                    flag_group(
202                        flags = ["-std=" + std_version],
203                    ),
204                ],
205                with_features = [
206                    with_feature_set(
207                        features = [std_version],
208                    ),
209                ],
210            )
211            for std_version in _c_std_versions
212        ],
213    ))
214    return features
215
216def _env_based_common_global_cflags(ctx):
217    flags = []
218
219    # The logic comes from https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/config/global.go;l=332;drc=af32e1ba3ffca6b552ac1ff6d14e5c3a5148cb80
220    auto_pattern_initialize = ctx.attr._auto_pattern_initialize[BuildSettingInfo].value
221    auto_uninitialize = ctx.attr._auto_uninitialize[BuildSettingInfo].value
222    if ctx.attr._auto_zero_initialize[BuildSettingInfo].value:
223        flags.extend(["-ftrivial-auto-var-init=zero"])
224    elif auto_pattern_initialize:
225        flags.extend(["-ftrivial-auto-var-init=pattern"])
226    elif auto_uninitialize:
227        flags.extend(["-ftrivial-auto-var-init=uninitialized"])
228    else:
229        # Default to zero initialization.
230        flags.extend(["-ftrivial-auto-var-init=zero"])
231
232    if ctx.attr._use_ccache[BuildSettingInfo].value or (not auto_pattern_initialize and not auto_uninitialize):
233        flags.extend(["-Wno-unused-command-line-argument"])
234
235    if ctx.attr._llvm_next[BuildSettingInfo].value:
236        flags.extend(["-Wno-error=single-bit-bitfield-constant-conversion"])
237
238    if ctx.attr._allow_unknown_warning_option[BuildSettingInfo].value:
239        flags.extend(["-Wno-error=unknown-warning-option"])
240
241    if ctx.attr._device_no_bionic_page_size_macro[BuildSettingInfo].value:
242        flags.extend(["-D__BIONIC_NO_PAGE_SIZE_MACRO"])
243
244    clang_debug_env_value = ctx.attr._clang_default_debug_level[BuildSettingInfo].value
245    if clang_debug_env_value == "":
246        flags.extend(["-g"])
247    elif clang_debug_env_value == "debug_level_g":
248        flags.extend(["-g"])
249    elif clang_debug_env_value == "debug_level_0":
250        flags.extend(["-g0"])
251    elif clang_debug_env_value == "debug_level_1":
252        flags.extend(["-g1"])
253    elif clang_debug_env_value == "debug_level_2":
254        flags.extend(["-g2"])
255    elif clang_debug_env_value == "debug_level_3":
256        flags.extend(["-g3"])
257
258    return flags
259
260def _compiler_flag_features(ctx, target_arch, target_os, flags = []):
261    os_is_device = is_os_device(target_os)
262    compiler_flags = []
263
264    # Combine the toolchain's provided flags with the default ones.
265    compiler_flags.extend(flags)
266    compiler_flags.extend(_flags.compiler_flags)
267    compiler_flags.extend(_generated_config_constants.CommonGlobalCflags)
268    compiler_flags.extend(_env_based_common_global_cflags(ctx))
269
270    if os_is_device:
271        compiler_flags.extend(_generated_config_constants.DeviceGlobalCflags)
272    else:
273        compiler_flags.extend(_generated_config_constants.HostGlobalCflags)
274
275    # Default compiler flags for assembly sources.
276    asm_only_flags = _generated_config_constants.CommonGlobalAsflags
277
278    # Default C++ compile action only flags (No C)
279    cpp_only_flags = []
280    cpp_only_flags.extend(_generated_config_constants.CommonGlobalCppflags)
281    if os_is_device:
282        cpp_only_flags.extend(_generated_config_constants.DeviceGlobalCppflags)
283    else:
284        cpp_only_flags.extend(_generated_config_constants.HostGlobalCppflags)
285
286    # Default C compile action only flags (No C++)
287    c_only_flags = []
288    c_only_flags.extend(_generated_config_constants.CommonGlobalConlyflags)
289
290    # Flags that only apply in the external/ directory.
291    non_external_flags = _flags.non_external_defines
292
293    features = []
294
295    # TODO: disabled on windows
296    features.append(feature(
297        name = "pic",
298        enabled = False,
299        flag_sets = [
300            flag_set(
301                actions = _actions.compile,
302                flag_groups = [
303                    flag_group(
304                        flags = ["-fPIC"],
305                    ),
306                ],
307                with_features = [
308                    with_feature_set(
309                        features = ["linker_flags"],
310                        not_features = ["pie"],
311                    ),
312                ],
313            ),
314        ],
315    ))
316
317    features.append(feature(
318        name = "pie",
319        enabled = False,
320        flag_sets = [
321            flag_set(
322                actions = _actions.compile,
323                flag_groups = [
324                    flag_group(
325                        flags = ["-fPIE"],
326                    ),
327                ],
328                with_features = [
329                    with_feature_set(
330                        features = ["linker_flags"],
331                        not_features = ["pic"],
332                    ),
333                ],
334            ),
335        ],
336    ))
337
338    features.append(feature(
339        name = "non_external_compiler_flags",
340        enabled = True,
341        flag_sets = [
342            flag_set(
343                actions = _actions.compile,
344                flag_groups = [
345                    flag_group(
346                        flags = non_external_flags,
347                    ),
348                ],
349                with_features = [
350                    with_feature_set(
351                        not_features = ["external_compiler_flags"],
352                    ),
353                ],
354            ),
355        ],
356    ))
357
358    # bpf only needs the flag below instead of all the flags in
359    # common_compiler_flags
360    features.append(feature(
361        name = "bpf_compiler_flags",
362        enabled = False,
363        flag_sets = [
364            flag_set(
365                actions = _actions.compile,
366                flag_groups = [
367                    flag_group(
368                        flags = ["-fdebug-prefix-map=/proc/self/cwd="],
369                    ),
370                ],
371            ),
372        ],
373    ))
374
375    if target_arch == _arches.Arm:
376        features.append(feature(
377            name = "arm_isa_arm",
378            enabled = False,
379            flag_sets = [
380                flag_set(
381                    actions = _actions.compile,
382                    flag_groups = [
383                        flag_group(
384                            flags = ["-fstrict-aliasing"],
385                        ),
386                    ],
387                ),
388            ],
389        ))
390
391        features.append(feature(
392            name = "arm_isa_thumb",
393            enabled = True,
394            flag_sets = [
395                flag_set(
396                    actions = _actions.compile,
397                    flag_groups = [
398                        flag_group(
399                            flags = _generated_config_constants.ArmThumbCflags,
400                        ),
401                    ],
402                    with_features = [
403                        with_feature_set(
404                            not_features = ["arm_isa_arm"],
405                        ),
406                    ],
407                ),
408            ],
409        ))
410
411    # Must follow arm_isa_thumb for flag ordering
412    features.append(feature(
413        name = "common_compiler_flags",
414        enabled = True,
415        flag_sets = [
416            flag_set(
417                actions = _actions.compile,
418                flag_groups = [
419                    flag_group(
420                        flags = compiler_flags,
421                    ),
422                ],
423            ),
424        ],
425    ))
426
427    features.append(feature(
428        name = "asm_compiler_flags",
429        enabled = True,
430        flag_sets = [
431            flag_set(
432                actions = _actions.assemble,
433                flag_groups = [
434                    flag_group(
435                        flags = asm_only_flags,
436                    ),
437                ],
438            ),
439        ],
440    ))
441
442    features.append(feature(
443        name = "cpp_compiler_flags",
444        enabled = True,
445        flag_sets = [
446            flag_set(
447                actions = [_actions.cpp_compile],
448                flag_groups = [
449                    flag_group(
450                        flags = cpp_only_flags,
451                    ),
452                ],
453            ),
454        ],
455    ))
456
457    if c_only_flags:
458        features.append(feature(
459            name = "c_compiler_flags",
460            enabled = True,
461            flag_sets = [
462                flag_set(
463                    actions = [_actions.c_compile],
464                    flag_groups = [
465                        flag_group(
466                            flags = c_only_flags,
467                        ),
468                    ],
469                ),
470            ],
471        ))
472
473    features.append(feature(
474        name = "external_compiler_flags",
475        enabled = True,
476        flag_sets = [
477            flag_set(
478                actions = _actions.compile,
479                flag_groups = [
480                    flag_group(
481                        flags = _generated_config_constants.ExternalCflags,
482                    ),
483                ],
484                with_features = [
485                    with_feature_set(
486                        not_features = ["non_external_compiler_flags"],
487                    ),
488                ],
489            ),
490        ],
491    ))
492
493    features.append(feature(
494        name = "warnings_as_errors",
495        enabled = True,
496        flag_sets = [
497            flag_set(
498                actions = _actions.compile,
499                flag_groups = [
500                    flag_group(
501                        flags = ["-Werror"],
502                    ),
503                ],
504            ),
505        ],
506    ))
507
508    # The user_compile_flags feature is used by Bazel to add --copt, --conlyopt,
509    # and --cxxopt values. Any features added above this call will thus appear
510    # earlier in the commandline than the user opts (so users could override
511    # flags set by earlier features). Anything after the user options are
512    # effectively non-overridable by users.
513    features.append(feature(
514        name = "user_compile_flags",
515        enabled = True,
516        flag_sets = [
517            flag_set(
518                actions = _actions.compile,
519                flag_groups = [
520                    flag_group(
521                        expand_if_available = "user_compile_flags",
522                        flags = ["%{user_compile_flags}"],
523                        iterate_over = "user_compile_flags",
524                    ),
525                ],
526            ),
527        ],
528    ))
529
530    return features
531
532def _get_no_override_compile_flags(target_os):
533    features = []
534
535    # These cannot be overriden by the user.
536    features.append(feature(
537        name = "no_override_clang_global_copts",
538        enabled = True,
539        flag_sets = [
540            flag_set(
541                # We want this to apply to all actions except assembly
542                # primarily to match Soong's semantics
543                actions = [a for a in _actions.compile if a not in _actions.assemble],
544                flag_groups = [
545                    flag_group(
546                        flags = _generated_config_constants.NoOverrideGlobalCflags,
547                    ),
548                ],
549            ),
550        ],
551    ))
552
553    if target_os != _oses.Darwin:
554        # These cannot be overriden by the user.
555        features.append(feature(
556            name = "no_override_clang_external_global_copts",
557            enabled = True,
558            flag_sets = [
559                flag_set(
560                    # We want this to apply to all actions except assembly
561                    # primarily to match Soong's semantics
562                    actions = [a for a in _actions.compile if a not in _actions.assemble],
563                    flag_groups = [
564                        flag_group(
565                            flags = _generated_config_constants.NoOverrideExternalGlobalCflags,
566                        ),
567                    ],
568                ),
569            ],
570            requires = [
571                feature_set(features = [
572                    "external_compiler_flags",
573                ]),
574            ],
575        ))
576
577    return features
578
579def _rtti_features(rtti_toggle):
580    if not rtti_toggle:
581        return []
582
583    rtti_flag_feature = feature(
584        name = "rtti_flag",
585        flag_sets = [
586            flag_set(
587                actions = [_actions.cpp_compile],
588                flag_groups = [
589                    flag_group(
590                        flags = ["-frtti"],
591                    ),
592                ],
593                with_features = [
594                    with_feature_set(features = ["rtti"]),
595                ],
596            ),
597            flag_set(
598                actions = [_actions.cpp_compile],
599                flag_groups = [
600                    flag_group(
601                        flags = ["-fno-rtti"],
602                    ),
603                ],
604                with_features = [
605                    with_feature_set(not_features = ["rtti"]),
606                ],
607            ),
608        ],
609        enabled = True,
610    )
611    rtti_feature = feature(
612        name = "rtti",
613        enabled = False,
614    )
615    return [rtti_flag_feature, rtti_feature]
616
617# TODO(b/202167934): Darwin does not support pack dynamic relocations
618def _pack_dynamic_relocations_features(target_os):
619    sht_relr_flags = flag_set(
620        actions = _actions.link,
621        flag_groups = [
622            flag_group(
623                flags = ["-Wl,--pack-dyn-relocs=android+relr"],
624            ),
625        ],
626        with_features = [
627            with_feature_set(
628                features = ["linker_flags"],
629                not_features = ["disable_pack_relocations"] + _sdk_version_features_before(30),
630            ),
631        ],
632    )
633    android_relr_flags = flag_set(
634        actions = _actions.link,
635        flag_groups = [
636            flag_group(
637                flags = ["-Wl,--pack-dyn-relocs=android+relr", "-Wl,--use-android-relr-tags"],
638            ),
639        ],
640        with_features = [
641            with_feature_set(
642                features = ["linker_flags", version],
643                not_features = ["disable_pack_relocations"],
644            )
645            for version in _sdk_version_features_between(28, 29)
646        ],
647    )
648    relocation_packer_flags = flag_set(
649        actions = _actions.link,
650        flag_groups = [
651            flag_group(
652                flags = ["-Wl,--pack-dyn-relocs=android"],
653            ),
654        ],
655        with_features = [
656            with_feature_set(
657                features = ["linker_flags", version],
658                not_features = ["disable_pack_relocations"],
659            )
660            for version in _sdk_version_features_between(23, 27)
661        ],
662    )
663
664    if is_os_bionic(target_os):
665        pack_dyn_relr_flag_sets = [
666            sht_relr_flags,
667            android_relr_flags,
668            relocation_packer_flags,
669        ]
670    else:
671        pack_dyn_relr_flag_sets = []
672
673    pack_dynamic_relocations_feature = feature(
674        name = "pack_dynamic_relocations",
675        enabled = True,
676        flag_sets = pack_dyn_relr_flag_sets,
677    )
678    disable_pack_relocations_feature = feature(
679        # this will take precedence over the pack_dynamic_relocations feature
680        # because each flag_set in that feature explicitly disallows the
681        # disable_dynamic_relocations feature
682        name = "disable_pack_relocations",
683        flag_sets = [
684            flag_set(
685                actions = _actions.link,
686                flag_groups = [
687                    flag_group(
688                        flags = ["-Wl,--pack-dyn-relocs=none"],
689                    ),
690                ],
691                with_features = [
692                    with_feature_set(
693                        features = ["linker_flags"],
694                    ),
695                ],
696            ),
697        ],
698        enabled = False,
699    )
700    return [
701        pack_dynamic_relocations_feature,
702        disable_pack_relocations_feature,
703    ]
704
705# TODO(b/202167934): Darwin by default disallows undefined symbols, to allow, -Wl,undefined,dynamic_lookup
706def _undefined_symbols_feature(target_os):
707    return _linker_flag_feature(
708        "no_undefined_symbols",
709        flags = ["-Wl,--no-undefined"],
710        enabled = is_os_bionic(target_os) or target_os == _oses.LinuxMusl,
711    )
712
713def _dynamic_linker_flag_feature(target_os, arch_is_64_bit):
714    flags = []
715    if is_os_device(target_os):
716        # TODO: handle bootstrap partition, asan
717        dynamic_linker_path = "/system/bin/linker"
718        if arch_is_64_bit:
719            dynamic_linker_path += "64"
720        flags.append("-Wl,-dynamic-linker," + dynamic_linker_path)
721    elif is_os_bionic(target_os) or target_os == _oses.LinuxMusl:
722        flags.append("-Wl,--no-dynamic-linker")
723    return _binary_linker_flag_feature(name = "dynamic_linker", flags = flags) if len(flags) else []
724
725# TODO(b/202167934): Darwin uses @loader_path in place of $ORIGIN
726def _rpath_features(target_os, arch_is_64_bit):
727    runtime_library_search_directories_flag_sets = [
728        flag_set(
729            actions = _actions.link,
730            flag_groups = [
731                flag_group(
732                    iterate_over = "runtime_library_search_directories",
733                    flag_groups = [
734                        flag_group(
735                            flags = [
736                                "-Wl,-rpath,$EXEC_ORIGIN/%{runtime_library_search_directories}",
737                            ],
738                            expand_if_true = "is_cc_test",
739                        ),
740                        flag_group(
741                            flags = [
742                                "-Wl,-rpath,$ORIGIN/%{runtime_library_search_directories}",
743                            ],
744                            expand_if_false = "is_cc_test",
745                        ),
746                    ],
747                    expand_if_available =
748                        "runtime_library_search_directories",
749                ),
750            ],
751            with_features = [
752                with_feature_set(features = ["static_link_cpp_runtimes"]),
753            ],
754        ),
755        flag_set(
756            actions = _actions.link,
757            flag_groups = [
758                flag_group(
759                    iterate_over = "runtime_library_search_directories",
760                    flag_groups = [
761                        flag_group(
762                            flags = [
763                                "-Wl,-rpath,$ORIGIN/%{runtime_library_search_directories}",
764                            ],
765                        ),
766                    ],
767                    expand_if_available =
768                        "runtime_library_search_directories",
769                ),
770            ],
771            with_features = [
772                with_feature_set(
773                    not_features = ["static_link_cpp_runtimes", "disable_rpath"],
774                ),
775            ],
776        ),
777    ]
778
779    if (not is_os_device(target_os)) and arch_is_64_bit:
780        runtime_library_search_directories_flag_sets.append(flag_set(
781            actions = _actions.link,
782            flag_groups = [
783                flag_group(
784                    flag_groups = [
785                        flag_group(
786                            flags = [
787                                "-Wl,-rpath,$ORIGIN/../lib64",
788                                "-Wl,-rpath,$ORIGIN/lib64",
789                            ],
790                        ),
791                    ],
792                ),
793            ],
794            with_features = [
795                with_feature_set(not_features = ["static_link_cpp_runtimes"]),
796            ],
797        ))
798
799    runtime_library_search_directories_feature = feature(
800        name = "runtime_library_search_directories",
801        flag_sets = runtime_library_search_directories_flag_sets,
802    )
803
804    disable_rpath_feature = feature(
805        name = "disable_rpath",
806        enabled = False,
807    )
808    return [runtime_library_search_directories_feature, disable_rpath_feature]
809
810def _use_libcrt_feature(path):
811    if not path:
812        return None
813    return _flag_feature("use_libcrt", actions = _actions.link, flags = [
814        path.path,
815        "-Wl,--exclude-libs=" + path.basename,
816    ])
817
818def _flag_feature(name, actions = None, flags = None, enabled = True):
819    if not flags or not actions:
820        return None
821    return feature(
822        name = name,
823        enabled = enabled,
824        flag_sets = [
825            flag_set(
826                actions = actions,
827                flag_groups = [
828                    flag_group(flags = flags),
829                ],
830            ),
831        ],
832    )
833
834def _linker_flag_feature(name, flags = [], enabled = True):
835    return _flag_feature(name, actions = _actions.link, flags = flags, enabled = enabled)
836
837def _archiver_flag_feature(name, flags = [], enabled = True):
838    return _flag_feature(name, actions = _actions.archive, flags = flags, enabled = enabled)
839
840def _binary_linker_flag_feature(name, flags = [], enabled = True):
841    return _flag_feature(name, actions = [_actions.cpp_link_executable], flags = flags, enabled = enabled)
842
843def _toolchain_include_feature(system_includes = []):
844    flags = []
845    for include in system_includes:
846        flags.append("-isystem")
847        flags.append(include)
848    if not flags:
849        return None
850    return feature(
851        name = "toolchain_include_directories",
852        enabled = True,
853        flag_sets = [
854            flag_set(
855                actions = _actions.compile,
856                flag_groups = [
857                    flag_group(
858                        flags = flags,
859                    ),
860                ],
861            ),
862        ],
863    )
864
865def _stub_library_feature():
866    return feature(
867        name = "stub_library",
868        enabled = False,
869        flag_sets = [
870            flag_set(
871                actions = [_actions.c_compile],
872                flag_groups = [
873                    flag_group(
874                        # Ensures that the stub libraries are always compiled with default visibility
875                        flags = _generated_config_constants.StubLibraryCompilerFlags + ["-fvisibility=default"],
876                    ),
877                ],
878            ),
879        ],
880    )
881
882def _flatten(xs):
883    ret = []
884    for x in xs:
885        if type(x) == "list":
886            ret.extend(x)
887        else:
888            ret.append(x)
889    return ret
890
891def _additional_archiver_flags(target_os):
892    archiver_flags = []
893    if target_os != _oses.Darwin:
894        archiver_flags.extend(_flags.non_darwin_archiver_flags)
895    return archiver_flags
896
897# Additional linker flags that are dependent on a host or device target.
898def _additional_linker_flags(os_is_device):
899    linker_flags = []
900    if os_is_device:
901        linker_flags.extend(_generated_config_constants.DeviceGlobalLldflags)
902        linker_flags.extend(_flags.bionic_linker_flags)
903    else:
904        linker_flags.extend(_generated_config_constants.HostGlobalLldflags)
905    return linker_flags
906
907def _static_binary_linker_flags(os_is_device):
908    linker_flags = []
909    if os_is_device:
910        linker_flags.extend(_flags.bionic_static_executable_linker_flags)
911    return linker_flags
912
913def _shared_binary_linker_flags(target_os):
914    linker_flags = []
915    if is_os_device(target_os):
916        linker_flags.extend(_flags.bionic_dynamic_executable_linker_flags)
917    elif target_os != _oses.Windows:
918        linker_flags.extend(_flags.host_non_windows_dynamic_executable_linker_flags)
919    return linker_flags
920
921# Legacy features moved from their hardcoded Bazel's Java implementation
922# to Starlark.
923#
924# These legacy features must come before all other features.
925def _get_legacy_features_begin():
926    features = [
927        # Legacy features omitted from this list, since they're not used in
928        # Android builds currently, or is alternatively supported through rules
929        # directly (e.g. stripped_shared_library for debug symbol stripping).
930        #
931        # thin_lto: Do not add, as it may break some features. replaced by _get_thinlto_features()
932        #
933        # runtime_library_search_directories: replaced by custom _rpath_feature().
934        #
935        # Compile related features:
936        #
937        # random_seed
938        # legacy_compile_flags
939        # per_object_debug_info
940        # pic
941        # force_pic_flags
942        #
943        # Optimization related features:
944        #
945        # fdo_instrument
946        # fdo_optimize
947        # cs_fdo_instrument
948        # cs_fdo_optimize
949        # fdo_prefetch_hints
950        # propeller_optimize
951        #
952        # Interface libraries related features:
953        #
954        # supports_interface_shared_libraries
955        # build_interface_libraries
956        # dynamic_library_linker_tool
957        #
958        # Coverage:
959        #
960        # coverage
961        # llvm_coverage_map_format
962        # gcc_coverage_map_format
963        #
964        # Others:
965        #
966        # symbol_counts
967        # static_libgcc
968        # fission_support
969        # static_link_cpp_runtimes
970        #
971        # ------------------------
972        #
973        feature(
974            name = "autofdo",
975            flag_sets = [
976                flag_set(
977                    actions = _actions.compile,
978                    flag_groups = [
979                        flag_group(
980                            # https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/afdo.go;l=35;drc=7a8362c252b152f806fc303c414ff1418672b067
981                            flags = [
982                                "-funique-internal-linkage-names",
983                                "-fprofile-sample-accurate",
984                                "-fprofile-sample-use=%{fdo_profile_path}",
985                            ],
986                            expand_if_available = "fdo_profile_path",
987                        ),
988                    ],
989                ),
990            ],
991            provides = ["profile"],
992        ),
993        # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=98;drc=6d03a2ecf25ad596446c296ef1e881b60c379812
994        feature(
995            name = "dependency_file",
996            enabled = True,
997            flag_sets = [
998                flag_set(
999                    actions = _actions.compile,
1000                    flag_groups = [
1001                        flag_group(
1002                            expand_if_available = "dependency_file",
1003                            flags = [
1004                                "-MD",
1005                                "-MF",
1006                                "%{dependency_file}",
1007                            ],
1008                        ),
1009                    ],
1010                ),
1011            ],
1012        ),
1013        # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=186;drc=6d03a2ecf25ad596446c296ef1e881b60c379812
1014        feature(
1015            name = "preprocessor_defines",
1016            enabled = True,
1017            flag_sets = [
1018                flag_set(
1019                    actions = _actions.compile,
1020                    flag_groups = [
1021                        flag_group(
1022                            iterate_over = "preprocessor_defines",
1023                            flags = ["-D%{preprocessor_defines}"],
1024                        ),
1025                    ],
1026                ),
1027            ],
1028        ),
1029        # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=207;drc=6d03a2ecf25ad596446c296ef1e881b60c379812
1030        feature(
1031            name = "includes",
1032            enabled = True,
1033            flag_sets = [
1034                flag_set(
1035                    actions = _actions.compile,
1036                    flag_groups = [
1037                        flag_group(
1038                            expand_if_available = "includes",
1039                            iterate_over = "includes",
1040                            flags = ["-include", "%{includes}"],
1041                        ),
1042                    ],
1043                ),
1044            ],
1045        ),
1046        # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=232;drc=6d03a2ecf25ad596446c296ef1e881b60c379812
1047        feature(
1048            name = "include_paths",
1049            enabled = True,
1050            flag_sets = [
1051                flag_set(
1052                    actions = _actions.compile,
1053                    flag_groups = [
1054                        flag_group(
1055                            iterate_over = "quote_include_paths",
1056                            flags = ["-iquote", "%{quote_include_paths}"],
1057                        ),
1058                        flag_group(
1059                            iterate_over = "include_paths",
1060                            flags = ["-I", "%{include_paths}"],
1061                        ),
1062                        flag_group(
1063                            iterate_over = "system_include_paths",
1064                            flags = ["-isystem", "%{system_include_paths}"],
1065                        ),
1066                        flag_group(
1067                            flags = ["-F%{framework_include_paths}"],
1068                            iterate_over = "framework_include_paths",
1069                        ),
1070                    ],
1071                ),
1072            ],
1073        ),
1074        # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=476;drc=6d03a2ecf25ad596446c296ef1e881b60c379812
1075        feature(
1076            name = "shared_flag",
1077            flag_sets = [
1078                flag_set(
1079                    actions = [
1080                        _actions.cpp_link_dynamic_library,
1081                        _actions.cpp_link_nodeps_dynamic_library,
1082                    ],
1083                    flag_groups = [
1084                        flag_group(
1085                            flags = [
1086                                "-shared",
1087                            ],
1088                        ),
1089                    ],
1090                ),
1091            ],
1092        ),
1093
1094        # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=492;drc=6d03a2ecf25ad596446c296ef1e881b60c379812
1095        feature(
1096            name = "linkstamps",
1097            flag_sets = [
1098                flag_set(
1099                    actions = _actions.link,
1100                    flag_groups = [
1101                        flag_group(
1102                            expand_if_available = "linkstamp_paths",
1103                            iterate_over = "linkstamp_paths",
1104                            flags = ["%{linkstamp_paths}"],
1105                        ),
1106                    ],
1107                ),
1108            ],
1109        ),
1110        # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=512;drc=6d03a2ecf25ad596446c296ef1e881b60c379812
1111        feature(
1112            name = "output_execpath_flags",
1113            flag_sets = [
1114                flag_set(
1115                    actions = _actions.link,
1116                    flag_groups = [
1117                        flag_group(
1118                            expand_if_available = "output_execpath",
1119                            flags = [
1120                                "-o",
1121                                "%{output_execpath}",
1122                            ],
1123                        ),
1124                    ],
1125                ),
1126            ],
1127        ),
1128        # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=592;drc=6d03a2ecf25ad596446c296ef1e881b60c379812
1129        feature(
1130            name = "library_search_directories",
1131            flag_sets = [
1132                flag_set(
1133                    actions = _actions.link,
1134                    flag_groups = [
1135                        flag_group(
1136                            expand_if_available = "library_search_directories",
1137                            iterate_over = "library_search_directories",
1138                            flags = ["-L%{library_search_directories}"],
1139                        ),
1140                    ],
1141                ),
1142            ],
1143        ),
1144        # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=612;drc=6d03a2ecf25ad596446c296ef1e881b60c379812
1145        feature(
1146            name = "archiver_flags",
1147            flag_sets = [
1148                flag_set(
1149                    actions = ["c++-link-static-library"],
1150                    flag_groups = [
1151                        flag_group(
1152                            flags = ["crsPD"],
1153                        ),
1154                        flag_group(
1155                            expand_if_available = "output_execpath",
1156                            flags = ["%{output_execpath}"],
1157                        ),
1158                    ],
1159                ),
1160                flag_set(
1161                    actions = ["c++-link-static-library"],
1162                    flag_groups = [
1163                        flag_group(
1164                            expand_if_available = "libraries_to_link",
1165                            iterate_over = "libraries_to_link",
1166                            flag_groups = [
1167                                flag_group(
1168                                    expand_if_equal = variable_with_value(
1169                                        name = "libraries_to_link.type",
1170                                        value = "object_file",
1171                                    ),
1172                                    flags = ["%{libraries_to_link.name}"],
1173                                ),
1174                            ],
1175                        ),
1176                        flag_group(
1177                            expand_if_equal = variable_with_value(
1178                                name = "libraries_to_link.type",
1179                                value = "object_file_group",
1180                            ),
1181                            iterate_over = "libraries_to_link.object_files",
1182                            flags = ["%{libraries_to_link.object_files}"],
1183                        ),
1184                    ],
1185                ),
1186            ],
1187        ),
1188        feature(
1189            name = "archive_with_prebuilt_flags",
1190            flag_sets = [
1191                flag_set(
1192                    actions = ["c++-link-static-library"],
1193                    flag_groups = [
1194                        flag_group(
1195                            flags = ["cqsL"],
1196                        ),
1197                        flag_group(
1198                            expand_if_available = "output_execpath",
1199                            flags = ["%{output_execpath}"],
1200                        ),
1201                    ],
1202                ),
1203            ],
1204        ),
1205        # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=653;drc=6d03a2ecf25ad596446c296ef1e881b60c379812
1206        feature(
1207            name = "libraries_to_link",
1208            flag_sets = [
1209                flag_set(
1210                    actions = _actions.link,
1211                    flag_groups = ([
1212                        flag_group(
1213                            expand_if_true = "thinlto_param_file",
1214                            flags = ["-Wl,@%{thinlto_param_file}"],
1215                        ),
1216                        flag_group(
1217                            expand_if_available = "libraries_to_link",
1218                            iterate_over = "libraries_to_link",
1219                            flag_groups = (
1220                                [
1221                                    flag_group(
1222                                        expand_if_equal = variable_with_value(
1223                                            name = "libraries_to_link.type",
1224                                            value = "object_file_group",
1225                                        ),
1226                                        expand_if_false = "libraries_to_link.is_whole_archive",
1227                                        flags = ["-Wl,--start-lib"],
1228                                    ),
1229                                    flag_group(
1230                                        expand_if_equal = variable_with_value(
1231                                            name = "libraries_to_link.type",
1232                                            value = "static_library",
1233                                        ),
1234                                        expand_if_true = "libraries_to_link.is_whole_archive",
1235                                        flags = ["-Wl,--whole-archive"],
1236                                    ),
1237                                    flag_group(
1238                                        expand_if_equal = variable_with_value(
1239                                            name = "libraries_to_link.type",
1240                                            value = "object_file_group",
1241                                        ),
1242                                        iterate_over = "libraries_to_link.object_files",
1243                                        flags = ["%{libraries_to_link.object_files}"],
1244                                    ),
1245                                    flag_group(
1246                                        expand_if_equal = variable_with_value(
1247                                            name = "libraries_to_link.type",
1248                                            value = "object_file",
1249                                        ),
1250                                        flags = ["%{libraries_to_link.name}"],
1251                                    ),
1252                                    flag_group(
1253                                        expand_if_equal = variable_with_value(
1254                                            name = "libraries_to_link.type",
1255                                            value = "interface_library",
1256                                        ),
1257                                        flags = ["%{libraries_to_link.name}"],
1258                                    ),
1259                                    flag_group(
1260                                        expand_if_equal = variable_with_value(
1261                                            name = "libraries_to_link.type",
1262                                            value = "static_library",
1263                                        ),
1264                                        flags = ["%{libraries_to_link.name}"],
1265                                    ),
1266                                    flag_group(
1267                                        expand_if_equal = variable_with_value(
1268                                            name = "libraries_to_link.type",
1269                                            value = "dynamic_library",
1270                                        ),
1271                                        flags = ["-l%{libraries_to_link.name}"],
1272                                    ),
1273                                    flag_group(
1274                                        expand_if_equal = variable_with_value(
1275                                            name = "libraries_to_link.type",
1276                                            value = "versioned_dynamic_library",
1277                                        ),
1278                                        flags = ["-l:%{libraries_to_link.name}"],
1279                                    ),
1280                                    flag_group(
1281                                        expand_if_equal = variable_with_value(
1282                                            name = "libraries_to_link.type",
1283                                            value = "static_library",
1284                                        ),
1285                                        expand_if_true = "libraries_to_link.is_whole_archive",
1286                                        flags = ["-Wl,--no-whole-archive"],
1287                                    ),
1288                                    flag_group(
1289                                        expand_if_equal = variable_with_value(
1290                                            name = "libraries_to_link.type",
1291                                            value = "object_file_group",
1292                                        ),
1293                                        expand_if_false = "libraries_to_link.is_whole_archive",
1294                                        flags = ["-Wl,--end-lib"],
1295                                    ),
1296                                ]
1297                            ),
1298                        ),
1299                    ]),
1300                ),
1301            ],
1302        ),
1303        # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=842;drc=6d03a2ecf25ad596446c296ef1e881b60c379812
1304        feature(
1305            name = "user_link_flags",
1306            flag_sets = [
1307                flag_set(
1308                    actions = _actions.link,
1309                    flag_groups = [
1310                        flag_group(
1311                            expand_if_available = "user_link_flags",
1312                            iterate_over = "user_link_flags",
1313                            flags = ["%{user_link_flags}"],
1314                        ),
1315                    ],
1316                ),
1317            ],
1318        ),
1319        feature(
1320            name = "strip_debug_symbols",
1321            flag_sets = [
1322                flag_set(
1323                    actions = _actions.link,
1324                    flag_groups = [
1325                        flag_group(
1326                            expand_if_available = "strip_debug_symbols",
1327                            flags = ["-Wl,-S"],
1328                        ),
1329                    ],
1330                ),
1331            ],
1332            enabled = False,
1333        ),
1334        feature(
1335            name = "llvm_coverage_map_format",
1336            flag_sets = [
1337                flag_set(
1338                    actions = _actions.compile,
1339                    flag_groups = [
1340                        flag_group(
1341                            flags = [
1342                                "-fprofile-instr-generate=/data/misc/trace/clang-%%p-%%m.profraw",
1343                                "-fcoverage-mapping",
1344                                "-Wno-pass-failed",
1345                                "-D__ANDROID_CLANG_COVERAGE__",
1346                            ],
1347                        ),
1348                    ],
1349                ),
1350                flag_set(
1351                    actions = [_actions.c_compile, _actions.cpp_compile],
1352                    flag_groups = [flag_group(flags = ["-Wno-frame-larger-than="])],
1353                ),
1354                # TODO(b/233660582): support "-Wl,--wrap,open" and libprofile-clang-extras
1355                flag_set(
1356                    actions = _actions.link,
1357                    flag_groups = [flag_group(flags = ["-fprofile-instr-generate"])],
1358                ),
1359                flag_set(
1360                    actions = _actions.link,
1361                    flag_groups = [flag_group(flags = ["-Wl,--wrap,open"])],
1362                    with_features = [
1363                        with_feature_set(
1364                            features = ["android_coverage_lib"],
1365                        ),
1366                    ],
1367                ),
1368            ],
1369            requires = [feature_set(features = ["coverage"])],
1370        ),
1371        feature(name = "coverage"),
1372        feature(name = "android_coverage_lib"),
1373    ]
1374
1375    return features
1376
1377# Legacy features moved from their hardcoded Bazel's Java implementation
1378# to Starlark.
1379#
1380# These legacy features must come after all other features.
1381def _get_legacy_features_end():
1382    # Omitted legacy (unused or re-implemented) features:
1383    #
1384    # fully_static_link
1385    # user_compile_flags
1386    # sysroot
1387    features = [
1388        feature(
1389            name = "linker_param_file",
1390            enabled = True,
1391            flag_sets = [
1392                flag_set(
1393                    actions = _actions.link + _actions.archive,
1394                    flag_groups = [
1395                        flag_group(
1396                            expand_if_available = "linker_param_file",
1397                            flags = ["@%{linker_param_file}"],
1398                        ),
1399                    ],
1400                ),
1401            ],
1402        ),
1403        # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=1511;drc=6d03a2ecf25ad596446c296ef1e881b60c379812
1404        feature(
1405            name = "compiler_input_flags",
1406            enabled = True,
1407            flag_sets = [
1408                flag_set(
1409                    actions = _actions.compile,
1410                    flag_groups = [
1411                        flag_group(
1412                            expand_if_available = "source_file",
1413                            flags = ["-c", "%{source_file}"],
1414                        ),
1415                    ],
1416                ),
1417            ],
1418        ),
1419        # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=1538;drc=6d03a2ecf25ad596446c296ef1e881b60c379812
1420        feature(
1421            name = "compiler_output_flags",
1422            enabled = True,
1423            flag_sets = [
1424                flag_set(
1425                    actions = _actions.compile,
1426                    flag_groups = [
1427                        flag_group(
1428                            expand_if_available = "output_assembly_file",
1429                            flags = ["-S"],
1430                        ),
1431                        flag_group(
1432                            expand_if_available = "output_preprocess_file",
1433                            flags = ["-E"],
1434                        ),
1435                        flag_group(
1436                            expand_if_available = "output_file",
1437                            flags = ["-o", "%{output_file}"],
1438                        ),
1439                    ],
1440                ),
1441            ],
1442        ),
1443    ]
1444
1445    return features
1446
1447def _link_crtbegin(crt_files):
1448    # in practice, either all of these are supported for a toolchain or none of them do
1449    if crt_files.shared_library_crtbegin == None or crt_files.shared_binary_crtbegin == None or crt_files.static_binary_crtbegin == None:
1450        return []
1451
1452    features = [
1453        feature(
1454            # User facing feature
1455            name = "link_crt",
1456            enabled = True,
1457            implies = ["link_crtbegin", "link_crtend"],
1458        ),
1459        feature(
1460            name = "link_crtbegin",
1461            enabled = True,
1462        ),
1463        feature(
1464            name = "link_crtbegin_so",
1465            enabled = True,
1466            flag_sets = [
1467                flag_set(
1468                    actions = [_actions.cpp_link_dynamic_library],
1469                    flag_groups = [
1470                        flag_group(
1471                            flags = [crt_files.shared_library_crtbegin.path],
1472                        ),
1473                    ],
1474                    with_features = [
1475                        with_feature_set(
1476                            features = ["link_crt", "link_crtbegin"],
1477                        ),
1478                    ],
1479                ),
1480            ],
1481        ),
1482        feature(
1483            name = "link_crtbegin_dynamic",
1484            enabled = True,
1485            flag_sets = [
1486                flag_set(
1487                    actions = [_actions.cpp_link_executable],
1488                    flag_groups = [
1489                        flag_group(
1490                            flags = [crt_files.shared_binary_crtbegin.path],
1491                        ),
1492                    ],
1493                    with_features = [
1494                        with_feature_set(
1495                            features = [
1496                                "dynamic_executable",
1497                                "link_crt",
1498                                "link_crtbegin",
1499                            ],
1500                        ),
1501                    ],
1502                ),
1503            ],
1504        ),
1505        feature(
1506            name = "link_crtbegin_static",
1507            enabled = True,
1508            flag_sets = [
1509                flag_set(
1510                    actions = [_actions.cpp_link_executable],
1511                    flag_groups = [
1512                        flag_group(
1513                            flags = [crt_files.static_binary_crtbegin.path],
1514                        ),
1515                    ],
1516                    with_features = [
1517                        with_feature_set(
1518                            features = [
1519                                "link_crt",
1520                                "link_crtbegin",
1521                                "static_executable",
1522                            ],
1523                        ),
1524                    ],
1525                ),
1526            ],
1527        ),
1528    ]
1529
1530    return features
1531
1532def _link_crtend(crt_files):
1533    # in practice, either all of these are supported for a toolchain or none of them do
1534    if crt_files.shared_library_crtend == None or crt_files.binary_crtend == None:
1535        return None
1536
1537    return [
1538        feature(
1539            name = "link_crtend",
1540            enabled = True,
1541        ),
1542        feature(
1543            name = "link_crtend_so",
1544            enabled = True,
1545            flag_sets = [
1546                flag_set(
1547                    actions = [_actions.cpp_link_dynamic_library],
1548                    flag_groups = [
1549                        flag_group(
1550                            flags = [crt_files.shared_library_crtend.path],
1551                        ),
1552                    ],
1553                    with_features = [
1554                        with_feature_set(
1555                            features = ["link_crt", "link_crtend"],
1556                        ),
1557                    ],
1558                ),
1559            ],
1560        ),
1561        feature(
1562            name = "link_crtend_binary",
1563            enabled = True,
1564            flag_sets = [
1565                flag_set(
1566                    actions = [_actions.cpp_link_executable],
1567                    flag_groups = [
1568                        flag_group(
1569                            flags = [crt_files.binary_crtend.path],
1570                        ),
1571                    ],
1572                    with_features = [
1573                        with_feature_set(
1574                            features = ["link_crt", "link_crtend"],
1575                        ),
1576                    ],
1577                ),
1578            ],
1579        ),
1580    ]
1581
1582# TODO(b/276932249): Restrict for Fuzzer when we have Fuzzer in Bazel
1583def _get_thinlto_features():
1584    features = [
1585        feature(
1586            name = "android_thin_lto",
1587            enabled = False,
1588            flag_sets = [
1589                flag_set(
1590                    actions = _actions.compile + _actions.link + _actions.assemble,
1591                    flag_groups = [
1592                        flag_group(
1593                            flags = [
1594                                "-flto=thin",
1595                                "-fsplit-lto-unit",
1596                            ],
1597                        ),
1598                    ],
1599                ),
1600            ],
1601        ),
1602        feature(
1603            name = "android_thin_lto_whole_program_vtables",
1604            enabled = False,
1605            requires = [feature_set(features = ["android_thin_lto"])],
1606            flag_sets = [
1607                flag_set(
1608                    actions = _actions.link,
1609                    flag_groups = [
1610                        flag_group(
1611                            flags = ["-fwhole-program-vtables"],
1612                        ),
1613                    ],
1614                ),
1615            ],
1616        ),
1617        # See Soong code:
1618        # https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/lto.go;l=133;drc=2c435a00ff73dc485855824ee49d2dec1a01e592
1619        feature(
1620            name = "android_thin_lto_limit_cross_tu_inline",
1621            enabled = True,
1622            requires = [feature_set(features = ["android_thin_lto"])],
1623            flag_sets = [
1624                flag_set(
1625                    actions = _actions.link,
1626                    flag_groups = [
1627                        flag_group(
1628                            flags = ["-Wl,-plugin-opt,-import-instr-limit=5"],
1629                        ),
1630                    ],
1631                    with_features = [
1632                        with_feature_set(
1633                            not_features = [
1634                                # TODO(b/267220812): Update for PGO
1635                                "autofdo",
1636                            ],
1637                        ),
1638                    ],
1639                ),
1640            ],
1641        ),
1642        # Used for CFI
1643        # TODO(b/283951987): Remove after full LTO support is removed in Soong
1644        feature(
1645            name = "android_full_lto",
1646            enabled = False,
1647            flag_sets = [
1648                flag_set(
1649                    actions = _actions.compile + _actions.link + _actions.assemble,
1650                    flag_groups = [
1651                        flag_group(
1652                            flags = ["-flto"],
1653                        ),
1654                    ],
1655                ),
1656            ],
1657        ),
1658    ]
1659    return features
1660
1661def _make_flag_set(actions, flags, with_features = [], with_not_features = []):
1662    return flag_set(
1663        actions = actions,
1664        flag_groups = [
1665            flag_group(
1666                flags = flags,
1667            ),
1668        ],
1669        with_features = [
1670            with_feature_set(
1671                features = with_features,
1672                not_features = with_not_features,
1673            ),
1674        ],
1675    )
1676
1677def _get_misc_sanitizer_features():
1678    return [
1679        # New sanitizers must imply this feature
1680        feature(
1681            name = "sanitizers_enabled",
1682            enabled = False,
1683        ),
1684    ]
1685
1686# TODO(b/276756817): Restrict for VNDK when we have VNDK in Bazel
1687# TODO(b/276756319): Restrict for riscv64 when we have riscv64 in Bazel
1688# TODO(b/276932249): Restrict for Fuzzer when we have Fuzzer in Bazel
1689# TODO(b/276931992): Restrict for Asan when we have Asan in Bazel
1690# TODO(b/283951987): Switch to thin LTO when possible
1691def _get_cfi_features(target_arch, target_os):
1692    if target_os in [_oses.Windows, _oses.Darwin, _oses.LinuxMusl]:
1693        return []
1694    features = [
1695        feature(
1696            name = "android_cfi_cross_dso",
1697            enabled = True,
1698            requires = [feature_set(features = ["android_cfi"])],
1699            flag_sets = [
1700                _make_flag_set(
1701                    actions = _actions.c_and_cpp_compile + _actions.link,
1702                    flags = [_generated_sanitizer_constants.CfiCrossDsoFlag],
1703                    with_features = ["dynamic_executable"],
1704                    with_not_features = ["static_executable"],
1705                ),
1706            ],
1707        ),
1708    ]
1709
1710    features.append(
1711        feature(
1712            name = "android_cfi",
1713            enabled = False,
1714            flag_sets = [
1715                _make_flag_set(
1716                    _actions.c_and_cpp_compile,
1717                    _generated_sanitizer_constants.CfiCFlags,
1718                ),
1719                _make_flag_set(
1720                    _actions.link,
1721                    _generated_sanitizer_constants.CfiLdFlags,
1722                ),
1723                _make_flag_set(
1724                    _actions.assemble,
1725                    _generated_sanitizer_constants.CfiAsFlags,
1726                ),
1727            ],
1728            implies = ["android_full_lto", "sanitizers_enabled"] + (
1729                ["arm_isa_thumb"] if target_arch == _arches.Arm else []
1730            ),
1731        ),
1732    )
1733
1734    features.append(
1735        feature(
1736            name = "android_cfi_assembly_support",
1737            enabled = False,
1738            requires = [feature_set(features = ["android_cfi"])],
1739            flag_sets = [
1740                _make_flag_set(
1741                    _actions.c_and_cpp_compile,
1742                    [_generated_sanitizer_constants.CfiAssemblySupportFlag],
1743                ),
1744            ],
1745        ),
1746    )
1747
1748    features.append(
1749        feature(
1750            name = "android_cfi_exports_map",
1751            enabled = False,
1752            requires = [feature_set(features = ["android_cfi"])],
1753            flag_sets = [
1754                _make_flag_set(
1755                    _actions.link,
1756                    [
1757                        _generated_config_constants.VersionScriptFlagPrefix +
1758                        _generated_sanitizer_constants.CfiExportsMapPath +
1759                        "/" +
1760                        _generated_sanitizer_constants.CfiExportsMapFilename,
1761                    ],
1762                ),
1763            ],
1764        ),
1765    )
1766
1767    features.append(
1768        feature(
1769            name = "android_cfi_visibility_default",
1770            enabled = True,
1771            requires = [feature_set(features = ["android_cfi"])],
1772            flag_sets = [
1773                flag_set(
1774                    actions = _actions.c_and_cpp_compile,
1775                    flag_groups = [
1776                        flag_group(
1777                            flags = [
1778                                _generated_config_constants.VisibilityDefaultFlag,
1779                            ],
1780                        ),
1781                    ],
1782                    with_features = [
1783                        with_feature_set(
1784                            not_features = ["visibility_hidden"],
1785                        ),
1786                    ],
1787                ),
1788            ],
1789        ),
1790    )
1791
1792    return features
1793
1794def _get_memtag_features(target_arch, target_os):
1795    features = []
1796    if target_os != _oses.Android or target_arch != _arches.Arm64:
1797        return features
1798
1799    features.append(
1800        feature(
1801            name = "memtag_heap",
1802            enabled = False,
1803            requires = [feature_set(features = ["cc_binary"])],
1804            flag_sets = [
1805                _make_flag_set(
1806                    actions = _actions.compile + _actions.link,
1807                    flags = ["-fsanitize=memtag-heap"],
1808                ),
1809                _make_flag_set(
1810                    actions = _actions.link,
1811                    flags = ["-fsanitize-memtag-mode=sync"],
1812                    with_features = ["diag_memtag_heap"],
1813                ),
1814                _make_flag_set(
1815                    actions = _actions.link,
1816                    flags = ["-fsanitize-memtag-mode=async"],
1817                    with_not_features = ["diag_memtag_heap"],
1818                ),
1819            ],
1820            implies = ["sanitizers_enabled"],
1821        ),
1822    )
1823
1824    features.append(feature(name = "cc_binary"))
1825    features.append(feature(name = "diag_memtag_heap"))
1826
1827    return features
1828
1829def _get_visibiility_hidden_feature():
1830    return [
1831        feature(
1832            name = "visibility_hidden",
1833            enabled = False,
1834            flag_sets = [
1835                _make_flag_set(
1836                    _actions.c_and_cpp_compile,
1837                    [_generated_config_constants.VisibilityHiddenFlag],
1838                ),
1839            ],
1840        ),
1841    ]
1842
1843def _sanitizer_flag_feature(name, actions, flags):
1844    return feature(
1845        name = name,
1846        enabled = True,
1847        flag_sets = [
1848            flag_set(
1849                actions = actions,
1850                flag_groups = [
1851                    flag_group(
1852                        flags = flags,
1853                    ),
1854                ],
1855                # Any new sanitizers that are enabled need to have a
1856                # with_feature_set added here.
1857                with_features = [
1858                    with_feature_set(
1859                        features = ["sanitizers_enabled"],
1860                    ),
1861                ],
1862            ),
1863        ],
1864    )
1865
1866def _host_or_device_specific_sanitizer_feature(target_os):
1867    if is_os_device(target_os):
1868        return _sanitizer_flag_feature(
1869            "sanitizer_device_only_flags",
1870            _actions.compile,
1871            _generated_sanitizer_constants.DeviceOnlySanitizeFlags,
1872        )
1873    return _sanitizer_flag_feature(
1874        "sanitizer_host_only_flags",
1875        _actions.compile,
1876        _generated_sanitizer_constants.HostOnlySanitizeFlags,
1877    )
1878
1879def _exclude_ubsan_rt_feature(path):
1880    if not path:
1881        return None
1882    return feature(
1883        name = "ubsan_exclude_rt",
1884        enabled = True,
1885        flag_sets = [
1886            flag_set(
1887                actions = _actions.link,
1888                flag_groups = [
1889                    flag_group(
1890                        flags = ["-Wl,--exclude-libs=" + path.basename],
1891                    ),
1892                ],
1893            ),
1894        ],
1895    )
1896
1897int_overflow_ignorelist_path = "build/soong/cc/config"
1898int_overflow_ignorelist_filename = "integer_overflow_blocklist.txt"
1899
1900def _get_unsupported_integer_check_with_feature_sets(feature_check):
1901    integer_sanitizers = [
1902        "implicit-unsigned-integer-truncation",
1903        "implicit-signed-integer-truncation",
1904        "implicit-integer-sign-change",
1905        "integer-divide-by-zero",
1906        "signed-integer-overflow",
1907        "unsigned-integer-overflow",
1908        "implicit-integer-truncation",
1909        "implicit-integer-arithmetic-value-change",
1910        "integer",
1911        "integer_overflow",
1912    ]
1913    if feature_check in integer_sanitizers:
1914        integer_sanitizers.remove(feature_check)
1915
1916    return [
1917        with_feature_set(
1918            features = ["ubsan_" + integer_sanitizer],
1919            not_features = ["ubsan_" + feature_check],
1920        )
1921        for integer_sanitizer in integer_sanitizers
1922    ]
1923
1924def _get_ubsan_features(target_os, libclang_rt_ubsan_minimal):
1925    if target_os in [_oses.Windows, _oses.Darwin]:
1926        return []
1927
1928    ALL_UBSAN_ACTIONS = _actions.compile + _actions.link + _actions.assemble
1929
1930    ubsan_features = [
1931        feature(
1932            name = "ubsan_enabled",
1933            enabled = False,
1934            implies = ["sanitizers_enabled"],
1935        ),
1936    ]
1937
1938    ubsan_features.append(
1939        feature(
1940            name = "ubsan_integer_overflow",
1941            enabled = False,
1942            flag_sets = [
1943                flag_set(
1944                    actions = ALL_UBSAN_ACTIONS,
1945                    flag_groups = [
1946                        flag_group(
1947                            flags = [
1948                                "-fsanitize=unsigned-integer-overflow",
1949                                "-fsanitize=signed-integer-overflow",
1950                            ],
1951                        ),
1952                    ],
1953                ),
1954                flag_set(
1955                    actions = _actions.c_and_cpp_compile,
1956                    flag_groups = [
1957                        flag_group(
1958                            flags = [
1959                                "-fsanitize-ignorelist=%s/%s" % (
1960                                    int_overflow_ignorelist_path,
1961                                    int_overflow_ignorelist_filename,
1962                                ),
1963                            ],
1964                        ),
1965                    ],
1966                ),
1967            ],
1968            implies = ["ubsan_minimal_runtime", "ubsan_enabled"],
1969        ),
1970    )
1971
1972    ubsan_checks = [
1973        "alignment",
1974        "bool",
1975        "builtin",
1976        "bounds",
1977        "array-bounds",
1978        "local-bounds",
1979        "enum",
1980        "float-cast-overflow",
1981        "float-divide-by-zero",
1982        "function",
1983        "implicit-unsigned-integer-truncation",
1984        "implicit-signed-integer-truncation",
1985        "implicit-integer-sign-change",
1986        "integer-divide-by-zero",
1987        "nonnull-attribute",
1988        "null",
1989        "nullability-arg",
1990        "nullability-assign",
1991        "nullability-return",
1992        "objc-cast",
1993        "object-size",
1994        "pointer-overflow",
1995        "return",
1996        "returns-nonnull-attribute",
1997        "shift",
1998        "shift-base",
1999        "shift-exponent",
2000        "unsigned-shift-base",
2001        "signed-integer-overflow",
2002        "unreachable",
2003        "unsigned-integer-overflow",
2004        "vla-bound",
2005        "vptr",
2006
2007        # check groups
2008        "undefined",
2009        "implicit-integer-truncation",
2010        "implicit-integer-arithmetic-value-change",
2011        "implicit-conversion",
2012        "integer",
2013        "nullability",
2014    ]
2015    ubsan_features += [
2016        feature(
2017            name = "ubsan_" + check_name,
2018            enabled = False,
2019            flag_sets = [
2020                flag_set(
2021                    actions = ALL_UBSAN_ACTIONS,
2022                    flag_groups = [
2023                        flag_group(
2024                            flags = ["-fsanitize=%s" % check_name],
2025                        ),
2026                    ],
2027                ),
2028            ],
2029            implies = ["ubsan_minimal_runtime", "ubsan_enabled"],
2030        )
2031        for check_name in ubsan_checks
2032    ]
2033
2034    ubsan_features.append(
2035        feature(
2036            name = "ubsan_no_sanitize_link_runtime",
2037            enabled = target_os in [
2038                _oses.Android,
2039                _oses.LinuxBionic,
2040                _oses.LinuxMusl,
2041            ],
2042            flag_sets = [
2043                flag_set(
2044                    actions = _actions.link,
2045                    flag_groups = [
2046                        flag_group(
2047                            flags = [
2048                                _generated_sanitizer_constants.NoSanitizeLinkRuntimeFlag,
2049                            ],
2050                        ),
2051                    ],
2052                    with_features = [
2053                        with_feature_set(
2054                            features = ["sanitizers_enabled"],
2055                        ),
2056                    ],
2057                ),
2058            ],
2059        ),
2060    )
2061
2062    # non-Bionic toolchain prebuilts are missing UBSan's vptr and function san.
2063    # Musl toolchain prebuilts have vptr and function sanitizers, but enabling
2064    # them implicitly enables RTTI which causes RTTI mismatch issues with
2065    # dependencies.
2066    ubsan_features.append(
2067        feature(
2068            name = "ubsan_disable_unsupported_non_bionic_checks",
2069            enabled = target_os not in [_oses.LinuxBionic, _oses.Android],
2070            flag_sets = [
2071                flag_set(
2072                    actions = _actions.c_and_cpp_compile,
2073                    flag_groups = [
2074                        flag_group(
2075                            flags = [
2076                                "-fno-sanitize=function,vptr",
2077                            ],
2078                        ),
2079                    ],
2080                    with_features = [
2081                        with_feature_set(
2082                            features = ["ubsan_integer_overflow"],
2083                        ),
2084                    ] + [
2085                        with_feature_set(features = ["ubsan_" + check_name])
2086                        for check_name in ubsan_checks
2087                    ],
2088                ),
2089            ],
2090        ),
2091    )
2092
2093    ubsan_features += [
2094        _host_or_device_specific_sanitizer_feature(target_os),
2095        _exclude_ubsan_rt_feature(libclang_rt_ubsan_minimal),
2096    ]
2097
2098    ubsan_features.append(
2099        feature(
2100            name = "ubsan_minimal_runtime",
2101            enabled = False,
2102            flag_sets = [
2103                flag_set(
2104                    actions = _actions.c_and_cpp_compile,
2105                    flag_groups = [
2106                        flag_group(
2107                            flags = _generated_sanitizer_constants.MinimalRuntimeFlags,
2108                        ),
2109                    ],
2110                ),
2111            ],
2112        ),
2113    )
2114
2115    ubsan_features.append(
2116        feature(
2117            name = "ubsan_disable_unsupported_integer_checks",
2118            enabled = True,
2119            flag_sets = [
2120                # TODO(b/119329758): If this bug is fixed, this shouldn't be
2121                #                    needed anymore
2122                flag_set(
2123                    actions = _actions.c_and_cpp_compile,
2124                    flag_groups = [
2125                        flag_group(
2126                            flags = [
2127                                "-fno-sanitize=implicit-integer-sign-change",
2128                            ],
2129                        ),
2130                    ],
2131                    with_features = _get_unsupported_integer_check_with_feature_sets(
2132                        "implicit-integer-sign-change",
2133                    ),
2134                ),
2135                # TODO(b/171275751): If this bug is fixed, this shouldn't be
2136                #                    needed anymore
2137                flag_set(
2138                    actions = _actions.c_and_cpp_compile,
2139                    flag_groups = [
2140                        flag_group(
2141                            flags = [
2142                                "-fno-sanitize=unsigned-shift-base",
2143                            ],
2144                        ),
2145                    ],
2146                    with_features = _get_unsupported_integer_check_with_feature_sets(
2147                        "unsigned-shift-base",
2148                    ),
2149                ),
2150            ],
2151        ),
2152    )
2153
2154    return ubsan_features
2155
2156def _manual_binder_interface_feature():
2157    return feature(
2158        name = "do_not_check_manual_binder_interfaces",
2159        enabled = False,
2160        flag_sets = [
2161            flag_set(
2162                actions = _actions.compile,
2163                flag_groups = [
2164                    flag_group(
2165                        flags = [
2166                            "-DDO_NOT_CHECK_MANUAL_BINDER_INTERFACES",
2167                        ],
2168                    ),
2169                ],
2170            ),
2171        ],
2172    )
2173
2174# Create the full list of features.
2175# buildifier: disable=function-docstring
2176def get_features(
2177        ctx,
2178        builtin_include_dirs,
2179        crt_files):
2180    target_os = ctx.attr.target_os
2181    target_arch = ctx.attr.target_arch
2182    target_flags = ctx.attr.target_flags
2183    compile_only_flags = ctx.attr.compiler_flags
2184    linker_only_flags = ctx.attr.linker_flags
2185    device_max_page_size = ctx.attr._device_max_page_size_supported[BuildSettingInfo].value
2186    if device_max_page_size and (target_arch == "arm64" or target_arch == "x86_64"):
2187        linker_only_flags = ctx.attr.linker_flags + \
2188                            ["-Wl,-z,max-page-size=" + device_max_page_size]
2189
2190    libclang_rt_builtin = ctx.file.libclang_rt_builtin
2191    libclang_rt_ubsan_minimal = ctx.file.libclang_rt_ubsan_minimal
2192    rtti_toggle = ctx.attr.rtti_toggle
2193
2194    os_is_device = is_os_device(target_os)
2195    arch_is_64_bit = target_arch.endswith("64")
2196
2197    # Aggregate all features in order.
2198    # Note that the feature-list helper methods called below may return empty
2199    # lists, depending on whether these features should be enabled. These are still
2200    # listed in the below stanza as-is to preserve ordering.
2201    features = [
2202        # Do not depend on Bazel's built-in legacy features and action configs:
2203        feature(name = "no_legacy_features"),
2204
2205        # This must always come first, after no_legacy_features.
2206        _link_crtbegin(crt_files),
2207
2208        # Explicitly depend on a subset of legacy configs:
2209        _get_legacy_features_begin(),
2210
2211        # get_c_std_features must come before _compiler_flag_features and user
2212        # compile flags, as build targets may use copts/cflags to explicitly
2213        # change the -std version to overwrite the defaults or c{,pp}_std attribute
2214        # value.
2215        _get_c_std_features(),
2216        # Features tied to sdk version
2217        _get_sdk_version_features(os_is_device, target_arch),
2218        _compiler_flag_features(ctx, target_arch, target_os, target_flags + compile_only_flags),
2219        _rpath_features(target_os, arch_is_64_bit),
2220        # Optimization
2221        _get_thinlto_features(),
2222        # Sanitizers
2223        _get_cfi_features(target_arch, target_os),
2224        _get_memtag_features(target_arch, target_os),
2225        _get_ubsan_features(target_os, libclang_rt_ubsan_minimal),
2226        _get_misc_sanitizer_features(),
2227        # Misc features
2228        _get_visibiility_hidden_feature(),
2229        # RTTI
2230        _rtti_features(rtti_toggle),
2231        _use_libcrt_feature(libclang_rt_builtin),
2232        # Shared compile/link flags that should also be part of the link actions.
2233        _linker_flag_feature("linker_target_flags", flags = target_flags),
2234        # Link-only flags.
2235        _linker_flag_feature("linker_flags", flags = linker_only_flags + _additional_linker_flags(os_is_device)),
2236        _archiver_flag_feature("additional_archiver_flags", flags = _additional_archiver_flags(target_os)),
2237        _undefined_symbols_feature(target_os),
2238        _dynamic_linker_flag_feature(target_os, arch_is_64_bit),
2239        _binary_linker_flag_feature("dynamic_executable", flags = _shared_binary_linker_flags(target_os)),
2240        # distinct from other static flags as it can be disabled separately
2241        _binary_linker_flag_feature("static_flag", flags = ["-static"], enabled = False),
2242        # default for executables is dynamic linking
2243        _binary_linker_flag_feature("static_executable", flags = _static_binary_linker_flags(os_is_device), enabled = False),
2244        _manual_binder_interface_feature(),
2245        _pack_dynamic_relocations_features(target_os),
2246        # System include directories features
2247        _toolchain_include_feature(system_includes = builtin_include_dirs),
2248        # Compiling stub.c sources to stub libraries
2249        _stub_library_feature(),
2250        _get_legacy_features_end(),
2251        # Flags that cannot be overridden must be at the end
2252        _get_no_override_compile_flags(target_os),
2253        # This must always come last.
2254        _link_crtend(crt_files),
2255    ]
2256
2257    return _flatten([f for f in features if f != None])
2258