"""Feature definitions for Android's C/C++ toolchain. This top level list of features are available through the get_features function. """ load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") load( "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", "feature", "feature_set", "flag_group", "flag_set", "variable_with_value", "with_feature_set", ) load("//build/bazel/product_config:product_variables_providing_rule.bzl", "ProductVariablesInfo") load( ":cc_toolchain_constants.bzl", _actions = "actions", _arches = "arches", _c_std_versions = "c_std_versions", _cpp_std_versions = "cpp_std_versions", _default_c_std_version = "default_c_std_version", _default_c_std_version_no_gnu = "default_c_std_version_no_gnu", _default_cpp_std_version = "default_cpp_std_version", _default_cpp_std_version_no_gnu = "default_cpp_std_version_no_gnu", _experimental_c_std_version = "experimental_c_std_version", _experimental_c_std_version_no_gnu = "experimental_c_std_version_no_gnu", _experimental_cpp_std_version = "experimental_cpp_std_version", _experimental_cpp_std_version_no_gnu = "experimental_cpp_std_version_no_gnu", _flags = "flags", _generated_config_constants = "generated_config_constants", _generated_sanitizer_constants = "generated_sanitizer_constants", _oses = "oses", ) load("//build/bazel/rules/common:api.bzl", "api") load("@soong_injection//api_levels:platform_versions.bzl", "platform_versions") def is_os_device(os): return os == _oses.Android def is_os_bionic(os): return os == _oses.Android or os == _oses.LinuxBionic def _sdk_version_features_between(start, end): return ["sdk_version_" + str(i) for i in range(start, end + 1)] def _sdk_version_features_before(version): return _sdk_version_features_between(1, version - 1) def _get_sdk_version_features(os_is_device, target_arch): if not os_is_device: return [] default_sdk_version = "10000" sdk_feature_prefix = "sdk_version_" all_sdk_versions = [default_sdk_version] for level in api.api_levels.values(): all_sdk_versions.append(str(level)) # Explicitly support internal branch state where the platform sdk version has # finalized, but the sdk is still active, so it's represented by a 9000-ish # value in api_levels. platform_sdk_version = str(platform_versions.platform_sdk_version) if platform_sdk_version not in all_sdk_versions: all_sdk_versions.append(platform_sdk_version) flag_prefix = "--target=" if target_arch == _arches.X86: flag_prefix += "i686-linux-android" elif target_arch == _arches.X86_64: flag_prefix += "x86_64-linux-android" elif target_arch == _arches.Arm: flag_prefix += _generated_config_constants.ArmClangTriple elif target_arch == _arches.Arm64: flag_prefix += "aarch64-linux-android" else: fail("Unknown target arch %s" % (target_arch)) features = [feature( name = "sdk_version_default", enabled = True, implies = [sdk_feature_prefix + default_sdk_version], )] features.extend([ feature(name = sdk_feature_prefix + sdk_version, provides = ["sdk_version"]) for sdk_version in all_sdk_versions ]) features.append(feature( name = "sdk_version_flag", enabled = True, flag_sets = [ flag_set( actions = _actions.compile + _actions.link, flag_groups = [ flag_group( flags = [flag_prefix + sdk_version], ), ], with_features = [ with_feature_set( features = [sdk_feature_prefix + sdk_version], ), ], ) for sdk_version in all_sdk_versions ], )) return features def _get_c_std_features(): features = [] features.append(feature( # The default cpp_std feature. Remember to disable # this feature if enabling another cpp_std feature. name = "cpp_std_default", enabled = True, implies = [_default_cpp_std_version], )) features.append(feature( # The default c_std feature. Remember to disable # this feature if enabling another cpp_std feature. name = "c_std_default", enabled = True, implies = [_default_c_std_version], )) features.append(feature( name = "cpp_std_default_no_gnu", implies = [_default_cpp_std_version_no_gnu], )) features.append(feature( name = "c_std_default_no_gnu", implies = [_default_cpp_std_version_no_gnu], )) features.append(feature( name = "cpp_std_experimental", implies = [_experimental_cpp_std_version], )) features.append(feature( name = "c_std_experimental", implies = [_experimental_cpp_std_version], )) features.append(feature( name = "cpp_std_experimental_no_gnu", implies = [_experimental_cpp_std_version_no_gnu], )) features.append(feature( name = "c_std_experimental_no_gnu", implies = [_experimental_cpp_std_version_no_gnu], )) features.extend([ feature(name = std_version, provides = ["cpp_std"]) for std_version in _cpp_std_versions ]) features.extend([ feature(name = std_version, provides = ["c_std"]) for std_version in _c_std_versions ]) features.append(feature( name = "cpp_std_flag", enabled = True, # Create the -std flag group for each of the std versions, # enabled with with_feature_set. flag_sets = [ flag_set( actions = [_actions.cpp_compile], flag_groups = [ flag_group( flags = ["-std=" + std_version], ), ], with_features = [ with_feature_set( features = [std_version], ), ], ) for std_version in _cpp_std_versions ], )) features.append(feature( name = "c_std_flag", enabled = True, # Create the -std flag group for each of the std versions, # enabled with with_feature_set. flag_sets = [ flag_set( actions = [_actions.c_compile], flag_groups = [ flag_group( flags = ["-std=" + std_version], ), ], with_features = [ with_feature_set( features = [std_version], ), ], ) for std_version in _c_std_versions ], )) return features def _env_based_common_global_cflags(ctx): flags = [] # The logic comes from https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/config/global.go;l=332;drc=af32e1ba3ffca6b552ac1ff6d14e5c3a5148cb80 auto_pattern_initialize = ctx.attr._auto_pattern_initialize[BuildSettingInfo].value auto_uninitialize = ctx.attr._auto_uninitialize[BuildSettingInfo].value if ctx.attr._auto_zero_initialize[BuildSettingInfo].value: flags.extend(["-ftrivial-auto-var-init=zero", "-enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang"]) elif auto_pattern_initialize: flags.extend(["-ftrivial-auto-var-init=pattern"]) elif auto_uninitialize: flags.extend(["-ftrivial-auto-var-init=uninitialized"]) else: # Default to zero initialization. flags.extend(["-ftrivial-auto-var-init=zero", "-enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang"]) if ctx.attr._use_ccache[BuildSettingInfo].value or (not auto_pattern_initialize and not auto_uninitialize): flags.extend(["-Wno-unused-command-line-argument"]) if ctx.attr._llvm_next[BuildSettingInfo].value: flags.extend(["-Wno-error=single-bit-bitfield-constant-conversion"]) if ctx.attr._allow_unknown_warning_option[BuildSettingInfo].value: flags.extend(["-Wno-error=unknown-warning-option"]) return flags def _compiler_flag_features(ctx, target_arch, target_os, flags = []): os_is_device = is_os_device(target_os) compiler_flags = [] # Combine the toolchain's provided flags with the default ones. compiler_flags.extend(flags) compiler_flags.extend(_flags.compiler_flags) compiler_flags.extend(_generated_config_constants.CommonGlobalCflags) compiler_flags.extend(_env_based_common_global_cflags(ctx)) if os_is_device: compiler_flags.extend(_generated_config_constants.DeviceGlobalCflags) else: compiler_flags.extend(_generated_config_constants.HostGlobalCflags) # Default compiler flags for assembly sources. asm_only_flags = _generated_config_constants.CommonGlobalAsflags # Default C++ compile action only flags (No C) cpp_only_flags = [] cpp_only_flags.extend(_generated_config_constants.CommonGlobalCppflags) if os_is_device: cpp_only_flags.extend(_generated_config_constants.DeviceGlobalCppflags) else: cpp_only_flags.extend(_generated_config_constants.HostGlobalCppflags) # Default C compile action only flags (No C++) c_only_flags = [] c_only_flags.extend(_generated_config_constants.CommonGlobalConlyflags) # Flags that only apply in the external/ directory. non_external_flags = _flags.non_external_defines features = [] # TODO: disabled on windows features.append(feature( name = "pic", enabled = False, flag_sets = [ flag_set( actions = _actions.compile, flag_groups = [ flag_group( flags = ["-fPIC"], ), ], with_features = [ with_feature_set( features = ["linker_flags"], not_features = ["pie"], ), ], ), ], )) features.append(feature( name = "pie", enabled = False, flag_sets = [ flag_set( actions = _actions.compile, flag_groups = [ flag_group( flags = ["-fPIE"], ), ], with_features = [ with_feature_set( features = ["linker_flags"], not_features = ["pic"], ), ], ), ], )) features.append(feature( name = "non_external_compiler_flags", enabled = True, flag_sets = [ flag_set( actions = _actions.compile, flag_groups = [ flag_group( flags = non_external_flags, ), ], with_features = [ with_feature_set( not_features = ["external_compiler_flags"], ), ], ), ], )) # bpf only needs the flag below instead of all the flags in # common_compiler_flags features.append(feature( name = "bpf_compiler_flags", enabled = False, flag_sets = [ flag_set( actions = _actions.compile, flag_groups = [ flag_group( flags = ["-fdebug-prefix-map=/proc/self/cwd="], ), ], ), ], )) features.append(feature( name = "asm_compiler_flags", enabled = True, flag_sets = [ flag_set( actions = _actions.assemble, flag_groups = [ flag_group( flags = asm_only_flags, ), ], ), ], )) features.append(feature( name = "cpp_compiler_flags", enabled = True, flag_sets = [ flag_set( actions = [_actions.cpp_compile], flag_groups = [ flag_group( flags = cpp_only_flags, ), ], ), ], )) if c_only_flags: features.append(feature( name = "c_compiler_flags", enabled = True, flag_sets = [ flag_set( actions = [_actions.c_compile], flag_groups = [ flag_group( flags = c_only_flags, ), ], ), ], )) features.append(feature( name = "arm_isa_arm", enabled = False, provides = ["arm_isa"], flag_sets = [ flag_set( actions = _actions.compile, flag_groups = [ flag_group( flags = ["-fstrict-aliasing"], ), ], ), ], )) features.append(feature( name = "arm_isa_thumb", enabled = target_arch == _arches.Arm, provides = ["arm_isa"], flag_sets = [ flag_set( actions = _actions.compile, flag_groups = [ flag_group( flags = _generated_config_constants.ArmThumbCflags, ), ], ), ], )) # Must follow arm_isa_thumb for flag ordering features.append(feature( name = "common_compiler_flags", enabled = True, flag_sets = [ flag_set( actions = _actions.compile, flag_groups = [ flag_group( flags = compiler_flags, ), ], ), ], )) features.append(feature( name = "external_compiler_flags", enabled = True, flag_sets = [ flag_set( actions = _actions.compile, flag_groups = [ flag_group( flags = _generated_config_constants.ExternalCflags, ), ], with_features = [ with_feature_set( not_features = ["non_external_compiler_flags"], ), ], ), ], )) # The user_compile_flags feature is used by Bazel to add --copt, --conlyopt, # and --cxxopt values. Any features added above this call will thus appear # earlier in the commandline than the user opts (so users could override # flags set by earlier features). Anything after the user options are # effectively non-overridable by users. features.append(feature( name = "user_compile_flags", enabled = True, flag_sets = [ flag_set( actions = _actions.compile, flag_groups = [ flag_group( expand_if_available = "user_compile_flags", flags = ["%{user_compile_flags}"], iterate_over = "user_compile_flags", ), ], ), ], )) # These cannot be overriden by the user. features.append(feature( name = "no_override_clang_global_copts", enabled = True, flag_sets = [ flag_set( # We want this to apply to all actions except assembly # primarily to match Soong's semantics actions = [a for a in _actions.compile if a not in _actions.assemble], flag_groups = [ flag_group( flags = _generated_config_constants.NoOverrideGlobalCflags, ), ], ), ], )) if target_os != _oses.Darwin: # These cannot be overriden by the user. features.append(feature( name = "no_override_clang_external_global_copts", enabled = True, flag_sets = [ flag_set( # We want this to apply to all actions except assembly # primarily to match Soong's semantics actions = [a for a in _actions.compile if a not in _actions.assemble], flag_groups = [ flag_group( flags = _generated_config_constants.NoOverrideExternalGlobalCflags, ), ], ), ], requires = [ feature_set(features = [ "external_compiler_flags", ]), ], )) return features def _rtti_features(rtti_toggle): if not rtti_toggle: return [] rtti_flag_feature = feature( name = "rtti_flag", flag_sets = [ flag_set( actions = [_actions.cpp_compile], flag_groups = [ flag_group( flags = ["-frtti"], ), ], with_features = [ with_feature_set(features = ["rtti"]), ], ), flag_set( actions = [_actions.cpp_compile], flag_groups = [ flag_group( flags = ["-fno-rtti"], ), ], with_features = [ with_feature_set(not_features = ["rtti"]), ], ), ], enabled = True, ) rtti_feature = feature( name = "rtti", enabled = False, ) return [rtti_flag_feature, rtti_feature] # TODO(b/202167934): Darwin does not support pack dynamic relocations def _pack_dynamic_relocations_features(target_os): sht_relr_flags = flag_set( actions = _actions.link, flag_groups = [ flag_group( flags = ["-Wl,--pack-dyn-relocs=android+relr"], ), ], with_features = [ with_feature_set( features = ["linker_flags"], not_features = ["disable_pack_relocations"] + _sdk_version_features_before(30), ), ], ) android_relr_flags = flag_set( actions = _actions.link, flag_groups = [ flag_group( flags = ["-Wl,--pack-dyn-relocs=android+relr", "-Wl,--use-android-relr-tags"], ), ], with_features = [ with_feature_set( features = ["linker_flags", version], not_features = ["disable_pack_relocations"], ) for version in _sdk_version_features_between(28, 29) ], ) relocation_packer_flags = flag_set( actions = _actions.link, flag_groups = [ flag_group( flags = ["-Wl,--pack-dyn-relocs=android"], ), ], with_features = [ with_feature_set( features = ["linker_flags", version], not_features = ["disable_pack_relocations"], ) for version in _sdk_version_features_between(23, 27) ], ) if is_os_bionic(target_os): pack_dyn_relr_flag_sets = [ sht_relr_flags, android_relr_flags, relocation_packer_flags, ] else: pack_dyn_relr_flag_sets = [] pack_dynamic_relocations_feature = feature( name = "pack_dynamic_relocations", enabled = True, flag_sets = pack_dyn_relr_flag_sets, ) disable_pack_relocations_feature = feature( # this will take precedence over the pack_dynamic_relocations feature # because each flag_set in that feature explicitly disallows the # disable_dynamic_relocations feature name = "disable_pack_relocations", flag_sets = [ flag_set( actions = _actions.link, flag_groups = [ flag_group( flags = ["-Wl,--pack-dyn-relocs=none"], ), ], with_features = [ with_feature_set( features = ["linker_flags"], ), ], ), ], enabled = False, ) return [ pack_dynamic_relocations_feature, disable_pack_relocations_feature, ] # TODO(b/202167934): Darwin by default disallows undefined symbols, to allow, -Wl,undefined,dynamic_lookup def _undefined_symbols_feature(target_os): return _linker_flag_feature( "no_undefined_symbols", flags = ["-Wl,--no-undefined"], enabled = is_os_bionic(target_os) or target_os == _oses.LinuxMusl, ) def _dynamic_linker_flag_feature(target_os, arch_is_64_bit): flags = [] if is_os_device(target_os): # TODO: handle bootstrap partition, asan dynamic_linker_path = "/system/bin/linker" if arch_is_64_bit: dynamic_linker_path += "64" flags += ["-Wl,-dynamic-linker," + dynamic_linker_path] elif is_os_bionic(target_os) or target_os == _oses.LinuxMusl: flags += ["-Wl,--no-dynamic-linker"] return _binary_linker_flag_feature(name = "dynamic_linker", flags = flags) if len(flags) else [] # TODO(b/202167934): Darwin uses @loader_path in place of $ORIGIN def _rpath_features(target_os, arch_is_64_bit): runtime_library_search_directories_flag_sets = [ flag_set( actions = _actions.link, flag_groups = [ flag_group( iterate_over = "runtime_library_search_directories", flag_groups = [ flag_group( flags = [ "-Wl,-rpath,$EXEC_ORIGIN/%{runtime_library_search_directories}", ], expand_if_true = "is_cc_test", ), flag_group( flags = [ "-Wl,-rpath,$ORIGIN/%{runtime_library_search_directories}", ], expand_if_false = "is_cc_test", ), ], expand_if_available = "runtime_library_search_directories", ), ], with_features = [ with_feature_set(features = ["static_link_cpp_runtimes"]), ], ), flag_set( actions = _actions.link, flag_groups = [ flag_group( iterate_over = "runtime_library_search_directories", flag_groups = [ flag_group( flags = [ "-Wl,-rpath,$ORIGIN/%{runtime_library_search_directories}", ], ), ], expand_if_available = "runtime_library_search_directories", ), ], with_features = [ with_feature_set( not_features = ["static_link_cpp_runtimes", "disable_rpath"], ), ], ), ] if (not is_os_device(target_os)) and arch_is_64_bit: runtime_library_search_directories_flag_sets += [flag_set( actions = _actions.link, flag_groups = [ flag_group( flag_groups = [ flag_group( flags = [ "-Wl,-rpath,$ORIGIN/../lib64", "-Wl,-rpath,$ORIGIN/lib64", ], ), ], ), ], with_features = [ with_feature_set(not_features = ["static_link_cpp_runtimes"]), ], )] runtime_library_search_directories_feature = feature( name = "runtime_library_search_directories", flag_sets = runtime_library_search_directories_flag_sets, ) disable_rpath_feature = feature( name = "disable_rpath", enabled = False, ) return [runtime_library_search_directories_feature, disable_rpath_feature] def _use_libcrt_feature(path): if not path: return None return _flag_feature("use_libcrt", actions = _actions.link, flags = [ path.path, "-Wl,--exclude-libs=" + path.path, ]) def _flag_feature(name, actions = None, flags = None, enabled = True): if not flags or not actions: return None return feature( name = name, enabled = enabled, flag_sets = [ flag_set( actions = actions, flag_groups = [ flag_group(flags = flags), ], ), ], ) def _linker_flag_feature(name, flags = [], enabled = True): return _flag_feature(name, actions = _actions.link, flags = flags, enabled = enabled) def _archiver_flag_feature(name, flags = [], enabled = True): return _flag_feature(name, actions = _actions.archive, flags = flags, enabled = enabled) def _binary_linker_flag_feature(name, flags = [], enabled = True): return _flag_feature(name, actions = [_actions.cpp_link_executable], flags = flags, enabled = enabled) def _toolchain_include_feature(system_includes = []): flags = [] for include in system_includes: flags.append("-isystem") flags.append(include) if not flags: return None return feature( name = "toolchain_include_directories", enabled = True, flag_sets = [ flag_set( actions = _actions.compile, flag_groups = [ flag_group( flags = flags, ), ], ), ], ) def _stub_library_feature(): return feature( name = "stub_library", enabled = False, flag_sets = [ flag_set( actions = [_actions.c_compile], flag_groups = [ flag_group( # Ensures that the stub libraries are always compiled with default visibility flags = _generated_config_constants.StubLibraryCompilerFlags + ["-fvisibility=default"], ), ], ), ], ) def _flatten(xs): ret = [] for x in xs: if type(x) == "list": ret.extend(x) else: ret.append(x) return ret def _additional_archiver_flags(target_os): archiver_flags = [] if target_os != _oses.Darwin: archiver_flags.extend(_flags.non_darwin_archiver_flags) return archiver_flags # Additional linker flags that are dependent on a host or device target. def _additional_linker_flags(os_is_device): linker_flags = [] if os_is_device: linker_flags.extend(_generated_config_constants.DeviceGlobalLldflags) linker_flags.extend(_flags.bionic_linker_flags) else: linker_flags.extend(_generated_config_constants.HostGlobalLldflags) return linker_flags def _static_binary_linker_flags(os_is_device): linker_flags = [] if os_is_device: linker_flags.extend(_flags.bionic_static_executable_linker_flags) return linker_flags def _shared_binary_linker_flags(target_os): linker_flags = [] if is_os_device(target_os): linker_flags.extend(_flags.bionic_dynamic_executable_linker_flags) elif target_os != _oses.Windows: linker_flags.extend(_flags.host_non_windows_dynamic_executable_linker_flags) return linker_flags # Legacy features moved from their hardcoded Bazel's Java implementation # to Starlark. # # These legacy features must come before all other features. def _get_legacy_features_begin(): features = [ # Legacy features omitted from this list, since they're not used in # Android builds currently, or is alternatively supported through rules # directly (e.g. stripped_shared_library for debug symbol stripping). # # thin_lto: Do not add, as it may break some features. replaced by _get_thinlto_features() # # runtime_library_search_directories: replaced by custom _rpath_feature(). # # Compile related features: # # random_seed # legacy_compile_flags # per_object_debug_info # pic # force_pic_flags # # Optimization related features: # # fdo_instrument # fdo_optimize # cs_fdo_instrument # cs_fdo_optimize # fdo_prefetch_hints # propeller_optimize # # Interface libraries related features: # # supports_interface_shared_libraries # build_interface_libraries # dynamic_library_linker_tool # # Coverage: # # coverage # llvm_coverage_map_format # gcc_coverage_map_format # # Others: # # symbol_counts # static_libgcc # fission_support # static_link_cpp_runtimes # # ------------------------ # feature( name = "autofdo", flag_sets = [ flag_set( actions = _actions.compile, flag_groups = [ flag_group( # https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/afdo.go;l=35;drc=7a8362c252b152f806fc303c414ff1418672b067 flags = [ "-funique-internal-linkage-names", "-fprofile-sample-accurate", "-fprofile-sample-use=%{fdo_profile_path}", ], expand_if_available = "fdo_profile_path", ), ], ), ], provides = ["profile"], ), # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=98;drc=6d03a2ecf25ad596446c296ef1e881b60c379812 feature( name = "dependency_file", enabled = True, flag_sets = [ flag_set( actions = _actions.compile, flag_groups = [ flag_group( expand_if_available = "dependency_file", flags = [ "-MD", "-MF", "%{dependency_file}", ], ), ], ), ], ), # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=186;drc=6d03a2ecf25ad596446c296ef1e881b60c379812 feature( name = "preprocessor_defines", enabled = True, flag_sets = [ flag_set( actions = _actions.compile, flag_groups = [ flag_group( iterate_over = "preprocessor_defines", flags = ["-D%{preprocessor_defines}"], ), ], ), ], ), # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=207;drc=6d03a2ecf25ad596446c296ef1e881b60c379812 feature( name = "includes", enabled = True, flag_sets = [ flag_set( actions = _actions.compile, flag_groups = [ flag_group( expand_if_available = "includes", iterate_over = "includes", flags = ["-include", "%{includes}"], ), ], ), ], ), # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=232;drc=6d03a2ecf25ad596446c296ef1e881b60c379812 feature( name = "include_paths", enabled = True, flag_sets = [ flag_set( actions = _actions.compile, flag_groups = [ flag_group( iterate_over = "quote_include_paths", flags = ["-iquote", "%{quote_include_paths}"], ), flag_group( iterate_over = "include_paths", flags = ["-I", "%{include_paths}"], ), flag_group( iterate_over = "system_include_paths", flags = ["-isystem", "%{system_include_paths}"], ), flag_group( flags = ["-F%{framework_include_paths}"], iterate_over = "framework_include_paths", ), ], ), ], ), # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=476;drc=6d03a2ecf25ad596446c296ef1e881b60c379812 feature( name = "shared_flag", flag_sets = [ flag_set( actions = [ _actions.cpp_link_dynamic_library, _actions.cpp_link_nodeps_dynamic_library, ], flag_groups = [ flag_group( flags = [ "-shared", ], ), ], ), ], ), # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=492;drc=6d03a2ecf25ad596446c296ef1e881b60c379812 feature( name = "linkstamps", flag_sets = [ flag_set( actions = _actions.link, flag_groups = [ flag_group( expand_if_available = "linkstamp_paths", iterate_over = "linkstamp_paths", flags = ["%{linkstamp_paths}"], ), ], ), ], ), # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=512;drc=6d03a2ecf25ad596446c296ef1e881b60c379812 feature( name = "output_execpath_flags", flag_sets = [ flag_set( actions = _actions.link, flag_groups = [ flag_group( expand_if_available = "output_execpath", flags = [ "-o", "%{output_execpath}", ], ), ], ), ], ), # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=592;drc=6d03a2ecf25ad596446c296ef1e881b60c379812 feature( name = "library_search_directories", flag_sets = [ flag_set( actions = _actions.link, flag_groups = [ flag_group( expand_if_available = "library_search_directories", iterate_over = "library_search_directories", flags = ["-L%{library_search_directories}"], ), ], ), ], ), # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=612;drc=6d03a2ecf25ad596446c296ef1e881b60c379812 feature( name = "archiver_flags", flag_sets = [ flag_set( actions = ["c++-link-static-library"], flag_groups = [ flag_group( flags = ["crsPD"], ), flag_group( expand_if_available = "output_execpath", flags = ["%{output_execpath}"], ), ], ), flag_set( actions = ["c++-link-static-library"], flag_groups = [ flag_group( expand_if_available = "libraries_to_link", iterate_over = "libraries_to_link", flag_groups = [ flag_group( expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "object_file", ), flags = ["%{libraries_to_link.name}"], ), ], ), flag_group( expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "object_file_group", ), iterate_over = "libraries_to_link.object_files", flags = ["%{libraries_to_link.object_files}"], ), ], ), ], ), feature( name = "archive_with_prebuilt_flags", flag_sets = [ flag_set( actions = ["c++-link-static-library"], flag_groups = [ flag_group( flags = ["cqsL"], ), flag_group( expand_if_available = "output_execpath", flags = ["%{output_execpath}"], ), ], ), ], ), # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=653;drc=6d03a2ecf25ad596446c296ef1e881b60c379812 feature( name = "libraries_to_link", flag_sets = [ flag_set( actions = _actions.link, flag_groups = ([ flag_group( expand_if_true = "thinlto_param_file", flags = ["-Wl,@%{thinlto_param_file}"], ), flag_group( expand_if_available = "libraries_to_link", iterate_over = "libraries_to_link", flag_groups = ( [ flag_group( expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "object_file_group", ), expand_if_false = "libraries_to_link.is_whole_archive", flags = ["-Wl,--start-lib"], ), flag_group( expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "static_library", ), expand_if_true = "libraries_to_link.is_whole_archive", flags = ["-Wl,--whole-archive"], ), flag_group( expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "object_file_group", ), iterate_over = "libraries_to_link.object_files", flags = ["%{libraries_to_link.object_files}"], ), flag_group( expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "object_file", ), flags = ["%{libraries_to_link.name}"], ), flag_group( expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "interface_library", ), flags = ["%{libraries_to_link.name}"], ), flag_group( expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "static_library", ), flags = ["%{libraries_to_link.name}"], ), flag_group( expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "dynamic_library", ), flags = ["-l%{libraries_to_link.name}"], ), flag_group( expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "versioned_dynamic_library", ), flags = ["-l:%{libraries_to_link.name}"], ), flag_group( expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "static_library", ), expand_if_true = "libraries_to_link.is_whole_archive", flags = ["-Wl,--no-whole-archive"], ), flag_group( expand_if_equal = variable_with_value( name = "libraries_to_link.type", value = "object_file_group", ), expand_if_false = "libraries_to_link.is_whole_archive", flags = ["-Wl,--end-lib"], ), ] ), ), ]), ), ], ), # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=842;drc=6d03a2ecf25ad596446c296ef1e881b60c379812 feature( name = "user_link_flags", flag_sets = [ flag_set( actions = _actions.link, flag_groups = [ flag_group( expand_if_available = "user_link_flags", iterate_over = "user_link_flags", flags = ["%{user_link_flags}"], ), ], ), ], ), feature( name = "strip_debug_symbols", flag_sets = [ flag_set( actions = _actions.link, flag_groups = [ flag_group( expand_if_available = "strip_debug_symbols", flags = ["-Wl,-S"], ), ], ), ], enabled = False, ), feature( name = "llvm_coverage_map_format", flag_sets = [ flag_set( actions = _actions.compile, flag_groups = [ flag_group( flags = [ "-fprofile-instr-generate=/data/misc/trace/clang-%%p-%%m.profraw", "-fcoverage-mapping", "-Wno-pass-failed", "-D__ANDROID_CLANG_COVERAGE__", ], ), ], ), flag_set( actions = [_actions.c_compile, _actions.cpp_compile], flag_groups = [flag_group(flags = ["-Wno-frame-larger-than="])], ), # TODO(b/233660582): support "-Wl,--wrap,open" and libprofile-clang-extras flag_set( actions = _actions.link, flag_groups = [flag_group(flags = ["-fprofile-instr-generate"])], ), flag_set( actions = _actions.link, flag_groups = [flag_group(flags = ["-Wl,--wrap,open"])], with_features = [ with_feature_set( features = ["android_coverage_lib"], ), ], ), ], requires = [feature_set(features = ["coverage"])], ), feature(name = "coverage"), feature(name = "android_coverage_lib"), ] return features # Legacy features moved from their hardcoded Bazel's Java implementation # to Starlark. # # These legacy features must come after all other features. def _get_legacy_features_end(): # Omitted legacy (unused or re-implemented) features: # # fully_static_link # user_compile_flags # sysroot features = [ feature( name = "linker_param_file", enabled = True, flag_sets = [ flag_set( actions = _actions.link + _actions.archive, flag_groups = [ flag_group( expand_if_available = "linker_param_file", flags = ["@%{linker_param_file}"], ), ], ), ], ), # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=1511;drc=6d03a2ecf25ad596446c296ef1e881b60c379812 feature( name = "compiler_input_flags", enabled = True, flag_sets = [ flag_set( actions = _actions.compile, flag_groups = [ flag_group( expand_if_available = "source_file", flags = ["-c", "%{source_file}"], ), ], ), ], ), # https://cs.opensource.google/bazel/bazel/+/master:src/main/java/com/google/devtools/build/lib/rules/cpp/CppActionConfigs.java;l=1538;drc=6d03a2ecf25ad596446c296ef1e881b60c379812 feature( name = "compiler_output_flags", enabled = True, flag_sets = [ flag_set( actions = _actions.compile, flag_groups = [ flag_group( expand_if_available = "output_assembly_file", flags = ["-S"], ), flag_group( expand_if_available = "output_preprocess_file", flags = ["-E"], ), flag_group( expand_if_available = "output_file", flags = ["-o", "%{output_file}"], ), ], ), ], ), ] return features def _link_crtbegin(crt_files): # in practice, either all of these are supported for a toolchain or none of them do if crt_files.shared_library_crtbegin == None or crt_files.shared_binary_crtbegin == None or crt_files.static_binary_crtbegin == None: return [] features = [ feature( # User facing feature name = "link_crt", enabled = True, implies = ["link_crtbegin", "link_crtend"], ), feature( name = "link_crtbegin", enabled = True, ), feature( name = "link_crtbegin_so", enabled = True, flag_sets = [ flag_set( actions = [_actions.cpp_link_dynamic_library], flag_groups = [ flag_group( flags = [crt_files.shared_library_crtbegin.path], ), ], with_features = [ with_feature_set( features = ["link_crt", "link_crtbegin"], ), ], ), ], ), feature( name = "link_crtbegin_dynamic", enabled = True, flag_sets = [ flag_set( actions = [_actions.cpp_link_executable], flag_groups = [ flag_group( flags = [crt_files.shared_binary_crtbegin.path], ), ], with_features = [ with_feature_set( features = [ "dynamic_executable", "link_crt", "link_crtbegin", ], ), ], ), ], ), feature( name = "link_crtbegin_static", enabled = True, flag_sets = [ flag_set( actions = [_actions.cpp_link_executable], flag_groups = [ flag_group( flags = [crt_files.static_binary_crtbegin.path], ), ], with_features = [ with_feature_set( features = [ "link_crt", "link_crtbegin", "static_executable", ], ), ], ), ], ), ] return features def _link_crtend(crt_files): # in practice, either all of these are supported for a toolchain or none of them do if crt_files.shared_library_crtend == None or crt_files.binary_crtend == None: return None return [ feature( name = "link_crtend", enabled = True, ), feature( name = "link_crtend_so", enabled = True, flag_sets = [ flag_set( actions = [_actions.cpp_link_dynamic_library], flag_groups = [ flag_group( flags = [crt_files.shared_library_crtend.path], ), ], with_features = [ with_feature_set( features = ["link_crt", "link_crtend"], ), ], ), ], ), feature( name = "link_crtend_binary", enabled = True, flag_sets = [ flag_set( actions = [_actions.cpp_link_executable], flag_groups = [ flag_group( flags = [crt_files.binary_crtend.path], ), ], with_features = [ with_feature_set( features = ["link_crt", "link_crtend"], ), ], ), ], ), ] # TODO(b/276932249): Restrict for Fuzzer when we have Fuzzer in Bazel def _get_thinlto_features(): features = [ feature( name = "android_thin_lto", enabled = False, flag_sets = [ flag_set( actions = _actions.compile + _actions.link + _actions.assemble, flag_groups = [ flag_group( flags = [ "-flto=thin", "-fsplit-lto-unit", ], ), ], ), ], ), feature( name = "android_thin_lto_whole_program_vtables", enabled = False, requires = [feature_set(features = ["android_thin_lto"])], flag_sets = [ flag_set( actions = _actions.link, flag_groups = [ flag_group( flags = ["-fwhole-program-vtables"], ), ], ), ], ), # See Soong code: # https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/lto.go;l=133;drc=2c435a00ff73dc485855824ee49d2dec1a01e592 feature( name = "android_thin_lto_limit_cross_tu_inline", enabled = True, requires = [feature_set(features = ["android_thin_lto"])], flag_sets = [ flag_set( actions = _actions.link, flag_groups = [ flag_group( flags = ["-Wl,-plugin-opt,-import-instr-limit=5"], ), ], with_features = [ with_feature_set( not_features = [ # TODO(b/267220812): Update for PGO "autofdo", ], ), ], ), ], ), ] return features def _make_flag_set(actions, flags, with_features = [], with_not_features = []): return flag_set( actions = actions, flag_groups = [ flag_group( flags = flags, ), ], with_features = [ with_feature_set( features = with_features, not_features = with_not_features, ), ], ) # TODO(b/276756817): Restrict for VNDK when we have VNDK in Bazel # TODO(b/276756319): Restrict for riscv64 when we have riscv64 in Bazel # TODO(b/276932249): Restrict for Fuzzer when we have Fuzzer in Bazel # TODO(b/276931992): Restrict for Asan when we have Asan in Bazel def _get_cfi_features(target_arch, target_os): if target_os in [_oses.Windows, _oses.Darwin, _oses.LinuxMusl]: return [] features = [ feature( name = "android_cfi", enabled = False, flag_sets = [ _make_flag_set( _actions.c_and_cpp_compile, _generated_sanitizer_constants.CfiCFlags, ), _make_flag_set( _actions.link, _generated_sanitizer_constants.CfiLdFlags, ), _make_flag_set( _actions.assemble, _generated_sanitizer_constants.CfiAsFlags, ), ], implies = ["android_thin_lto"] + ( ["arm_isa_thumb"] if target_arch == _arches.Arm else [] ), ), ] features += [ feature( name = "android_cfi_cross_dso", enabled = True, requires = [feature_set(features = ["android_cfi"])], flag_sets = [ _make_flag_set( actions = _actions.c_and_cpp_compile + _actions.link, flags = [_generated_sanitizer_constants.CfiCrossDsoFlag], with_features = ["dynamic_executable"], with_not_features = ["static_executable"], ), ], ), ] features += [ feature( name = "android_cfi_assembly_support", enabled = False, requires = [feature_set(features = ["android_cfi"])], flag_sets = [ _make_flag_set( _actions.c_and_cpp_compile, [_generated_sanitizer_constants.CfiAssemblySupportFlag], ), ], ), ] features += [ feature( name = "android_cfi_exports_map", enabled = False, requires = [feature_set(features = ["android_cfi"])], flag_sets = [ _make_flag_set( _actions.link, [ _generated_config_constants.VersionScriptFlagPrefix + _generated_sanitizer_constants.CfiExportsMapPath + "/" + _generated_sanitizer_constants.CfiExportsMapFilename, ], ), ], ), ] features += [ feature( name = "android_cfi_visibility_default", enabled = True, requires = [feature_set(features = ["android_cfi"])], flag_sets = [ flag_set( actions = _actions.c_and_cpp_compile, flag_groups = [ flag_group( flags = [ _generated_config_constants.VisibilityDefaultFlag, ], ), ], with_features = [ with_feature_set( not_features = ["visibility_hidden"], ), ], ), ], ), ] return features def _get_visibiility_hidden_feature(): return [ feature( name = "visibility_hidden", enabled = False, flag_sets = [ _make_flag_set( _actions.c_and_cpp_compile, [_generated_config_constants.VisibilityHiddenFlag], ), ], ), ] def _ubsan_flag_feature(name, actions, flags): return feature( name = name, enabled = True, flag_sets = [ flag_set( actions = actions, flag_groups = [ flag_group( flags = flags, ), ], with_features = [ with_feature_set( features = ["ubsan_enabled"], ), ], ), ], ) def _host_or_device_specific_ubsan_feature(target_os): if is_os_device(target_os): return _ubsan_flag_feature( "ubsan_device_only_flags", _actions.compile, _generated_sanitizer_constants.DeviceOnlySanitizeFlags, ) return _ubsan_flag_feature( "ubsan_host_only_flags", _actions.compile, _generated_sanitizer_constants.HostOnlySanitizeFlags, ) def _exclude_ubsan_rt_feature(path): if not path: return None return _ubsan_flag_feature( "ubsan_exclude_rt", _actions.link, ["-Wl,--exclude-libs=" + path.basename], ) int_overflow_ignorelist_path = "build/soong/cc/config" int_overflow_ignorelist_filename = "integer_overflow_blocklist.txt" def _get_ubsan_features(target_os, libclang_rt_ubsan_minimal): if target_os in [_oses.Windows, _oses.Darwin]: return [] ALL_UBSAN_ACTIONS = _actions.compile + _actions.link + _actions.assemble ubsan_features = [ feature( name = "ubsan_enabled", enabled = False, ), ] ubsan_features += [ feature( name = "ubsan_integer_overflow", enabled = False, flag_sets = [ flag_set( actions = ALL_UBSAN_ACTIONS, flag_groups = [ flag_group( flags = [ "-fsanitize=unsigned-integer-overflow", "-fsanitize=signed-integer-overflow", ], ), ], ), flag_set( actions = _actions.compile, flag_groups = [ flag_group( flags = [ "-fsanitize-ignorelist=%s/%s" % ( int_overflow_ignorelist_path, int_overflow_ignorelist_filename, ), ], ), ], ), ], implies = ["ubsan_minimal_runtime", "ubsan_enabled"], ), ] ubsan_checks = [ "alignment", "bool", "builtin", "bounds", "array-bounds", "local-bounds", "enum", "float-cast-overflow", "float-divide-by-zero", "function", "implicit-unsigned-integer-truncation", "implicit-signed-integer-truncation", "implicit-integer-sign-change", "integer-divide-by-zero", "nonnull-attribute", "null", "nullability-arg", "nullability-assign", "nullability-return", "objc-cast", "object-size", "pointer-overflow", "return", "returns-nonnull-attribute", "shift", "shift-base", "shift-exponent", "unsigned-shift-base", "signed-integer-overflow", "unreachable", "unsigned-integer-overflow", "vla-bound", "vptr", # check groups "undefined", "implicit-integer-truncation", "implicit-integer-arithmetic-value-change", "implicit-conversion", "integer", "nullability", ] ubsan_features += [ feature( name = "ubsan_" + check_name, enabled = False, flag_sets = [ flag_set( actions = ALL_UBSAN_ACTIONS, flag_groups = [ flag_group( flags = ["-fsanitize=%s" % check_name], ), ], ), ], implies = ["ubsan_minimal_runtime", "ubsan_enabled"], ) for check_name in ubsan_checks ] ubsan_features += [ feature( name = "ubsan_no_sanitize_link_runtime", enabled = target_os in [ _oses.Android, _oses.LinuxBionic, _oses.LinuxMusl, ], flag_sets = [ flag_set( actions = _actions.link, flag_groups = [ flag_group( flags = [ "-fno-sanitize-link-runtime", ], ), ], with_features = [ with_feature_set( features = ["ubsan_enabled"], ), ], ), ], ), ] # non-Bionic toolchain prebuilts are missing UBSan's vptr and function san. # Musl toolchain prebuilts have vptr and function sanitizers, but enabling # them implicitly enables RTTI which causes RTTI mismatch issues with # dependencies. ubsan_features += [ feature( name = "ubsan_disable_unsupported_non_bionic_checks", enabled = target_os not in [_oses.LinuxBionic, _oses.Android], flag_sets = [ flag_set( actions = _actions.compile, flag_groups = [ flag_group( flags = [ "-fno-sanitize=function,vptr", ], ), ], with_features = [ with_feature_set( features = ["ubsan_integer_overflow"], ), ] + [ with_feature_set(features = ["ubsan_" + check_name]) for check_name in ubsan_checks ], ), ], ), ] ubsan_features += [ _host_or_device_specific_ubsan_feature(target_os), _exclude_ubsan_rt_feature(libclang_rt_ubsan_minimal), ] ubsan_features += [ feature( name = "ubsan_minimal_runtime", enabled = False, flag_sets = [ flag_set( actions = ALL_UBSAN_ACTIONS, flag_groups = [ flag_group( flags = [ "-fsanitize-minimal-runtime", "-fno-sanitize-trap=integer,undefined", "-fno-sanitize-recover=integer,undefined", ], ), ], ), ], ), ] ubsan_features += [ feature( name = "ubsan_disable_unsupported_integer_checks", enabled = True, flag_sets = [ # TODO(b/119329758): If this bug is fixed, this shouldn't be # needed anymore flag_set( actions = _actions.compile, flag_groups = [ flag_group( flags = [ "-fno-sanitize=implicit-integer-sign-change", ], ), ], with_features = [ with_feature_set( features = ["ubsan_integer"], not_features = [ "ubsan_implicit-integer-sign-change", ], ), ], ), # TODO(b/171275751): If this bug is fixed, this shouldn't be # needed anymore flag_set( actions = _actions.compile, flag_groups = [ flag_group( flags = [ "-fno-sanitize=unsigned-shift-base", ], ), ], with_features = [ with_feature_set( features = ["ubsan_integer"], not_features = [ "ubsan_unsigned-shift-base", ], ), ], ), ], ), ] return ubsan_features def _manual_binder_interface_feature(): return feature( name = "do_not_check_manual_binder_interfaces", enabled = False, flag_sets = [ flag_set( actions = _actions.compile, flag_groups = [ flag_group( flags = [ "-DDO_NOT_CHECK_MANUAL_BINDER_INTERFACES", ], ), ], ), ], ) # Create the full list of features. def get_features( ctx, builtin_include_dirs, crt_files): target_os = ctx.attr.target_os target_arch = ctx.attr.target_arch target_flags = ctx.attr.target_flags compile_only_flags = ctx.attr.compiler_flags linker_only_flags = ctx.attr.linker_flags deviceMaxPageSize = ctx.attr._product_variables[ProductVariablesInfo].DeviceMaxPageSizeSupported if deviceMaxPageSize and (target_arch == "arm" or target_arch == "arm64"): linker_only_flags = ctx.attr.linker_flags + \ ["-Wl,-z,max-page-size=" + deviceMaxPageSize] libclang_rt_builtin = ctx.file.libclang_rt_builtin libclang_rt_ubsan_minimal = ctx.file.libclang_rt_ubsan_minimal rtti_toggle = ctx.attr.rtti_toggle os_is_device = is_os_device(target_os) arch_is_64_bit = target_arch.endswith("64") # Aggregate all features in order. # Note that the feature-list helper methods called below may return empty # lists, depending on whether these features should be enabled. These are still # listed in the below stanza as-is to preserve ordering. features = [ # Do not depend on Bazel's built-in legacy features and action configs: feature(name = "no_legacy_features"), # This must always come first, after no_legacy_features. _link_crtbegin(crt_files), # Explicitly depend on a subset of legacy configs: _get_legacy_features_begin(), # get_c_std_features must come before _compiler_flag_features and user # compile flags, as build targets may use copts/cflags to explicitly # change the -std version to overwrite the defaults or c{,pp}_std attribute # value. _get_c_std_features(), # Features tied to sdk version _get_sdk_version_features(os_is_device, target_arch), _compiler_flag_features(ctx, target_arch, target_os, target_flags + compile_only_flags), _rpath_features(target_os, arch_is_64_bit), _rtti_features(rtti_toggle), _use_libcrt_feature(libclang_rt_builtin), # Shared compile/link flags that should also be part of the link actions. _linker_flag_feature("linker_target_flags", flags = target_flags), # Link-only flags. _linker_flag_feature("linker_flags", flags = linker_only_flags + _additional_linker_flags(os_is_device)), _archiver_flag_feature("additional_archiver_flags", flags = _additional_archiver_flags(target_os)), _undefined_symbols_feature(target_os), _dynamic_linker_flag_feature(target_os, arch_is_64_bit), _binary_linker_flag_feature("dynamic_executable", flags = _shared_binary_linker_flags(target_os)), # distinct from other static flags as it can be disabled separately _binary_linker_flag_feature("static_flag", flags = ["-static"], enabled = False), # default for executables is dynamic linking _binary_linker_flag_feature("static_executable", flags = _static_binary_linker_flags(os_is_device), enabled = False), _pack_dynamic_relocations_features(target_os), # System include directories features _toolchain_include_feature(system_includes = builtin_include_dirs), # Compiling stub.c sources to stub libraries _stub_library_feature(), _get_legacy_features_end(), # Optimization _get_thinlto_features(), # Sanitizers _get_cfi_features(target_arch, target_os), _get_ubsan_features(target_os, libclang_rt_ubsan_minimal), # Misc features _get_visibiility_hidden_feature(), # This must always come last. _link_crtend(crt_files), _manual_binder_interface_feature(), ] return _flatten([f for f in features if f != None])