| load("@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", "feature", "flag_group", "flag_set", "tool_path", "with_feature_set") |
| load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES") |
| |
| # Clang-specific configuration. |
| _ClangVersionInfo = provider(fields = ["directory", "includes"]) |
| |
| def _clang_version_impl(ctx): |
| directory = ctx.file.directory |
| provider = _ClangVersionInfo( |
| directory = directory, |
| includes = [directory.short_path + "/" + d for d in ctx.attr.includes], |
| ) |
| return [provider] |
| |
| clang_version = rule( |
| implementation = _clang_version_impl, |
| attrs = { |
| "directory": attr.label(allow_single_file = True, mandatory = True), |
| "includes": attr.string_list(default = []), |
| }, |
| ) |
| |
| # Toolchain definitions. |
| DEFINES = [ |
| "-DANDROID", |
| "-D__compiler_offsetof=__builtin_offsetof", |
| "-D_FORTIFY_SOURCE=2", |
| "-DNDEBUG", |
| "-UDEBUG", |
| ] |
| |
| # These defines should only apply to targets which are not under |
| # @external/. This can be controlled by adding "-non_external_compiler_flags" |
| # to the features list for external/ packages. |
| # This corresponds to special-casing in Soong (see "external/" in build/soong/cc/compiler.go). |
| NON_EXTERNAL_DEFINES = [ |
| "-DANDROID_STRICT", |
| ] |
| COMPILER_FLAGS = [ |
| "-g", |
| "-O2", |
| "-no-canonical-prefixes", |
| "-nostdlibinc", |
| "-faddrsig", |
| "-fcolor-diagnostics", |
| "-fdata-sections", |
| "-fdebug-prefix-map=/proc/self/cwd=", |
| "-fexperimental-new-pass-manager", |
| "-ffunction-sections", |
| "-fmessage-length=0", |
| "-fno-exceptions", |
| "-fno-short-enums", |
| "-fno-strict-aliasing", |
| "-ftrivial-auto-var-init=pattern", |
| "-fstack-protector-strong", |
| "-funwind-tables", |
| "-fPIC", |
| ] |
| ASM_COMPILER_FLAGS = [ |
| "-D__ASSEMBLY__", |
| ] |
| C_COMPILER_FLAGS = [ |
| "-std=gnu99", |
| ] |
| CC_COMPILER_STANDARD_STD_FLAGS = [ |
| "-std=gnu++17", |
| ] |
| |
| # Should be toggled instead of CC_COMPILER_STANARD_STD_FLAGS if |
| # the soong module has "cpp_std: 'experimental'". In bazel, tied |
| # to the feature "cpp_std_experimental". |
| CC_COMPILER_EXPERIMENTAL_STD_FLAGS = [ |
| "-std=gnu++2a", |
| ] |
| CC_COMPILER_FLAGS = [ |
| "-D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS", |
| "-fno-rtti", |
| "-fvisibility-inlines-hidden", |
| "-Wimplicit-fallthrough", |
| ] |
| WARNINGS = [ |
| "-W", |
| "-Wall", |
| "-Wa,--noexecstack", |
| "-Werror", |
| "-Werror=address", |
| "-Werror=address-of-temporary", |
| "-Werror=date-time", |
| "-Werror=format-security", |
| "-Werror=implicit-function-declaration", |
| "-Werror=int-conversion", |
| "-Werror=int-to-pointer-cast", |
| "-Werror=non-virtual-dtor", |
| "-Werror=pointer-to-int-cast", |
| "-Werror=return-type", |
| "-Werror=sequence-point", |
| "-Winit-self", |
| "-Wno-c++98-compat-extra-semi", |
| "-Wno-c99-designator", |
| "-Wno-defaulted-function-deleted", |
| "-Wno-format-pedantic", |
| "-Wno-gnu-include-next", |
| "-Wno-inconsistent-missing-override", |
| "-Wno-multichar", |
| # http://b/145210666 |
| "-Wno-reorder-init-list", |
| "-Wno-reserved-id-macro", |
| "-Wno-return-std-move-in-c++11", |
| "-Wno-sign-compare", |
| "-Wno-tautological-constant-compare", |
| "-Wno-tautological-type-limit-compare", |
| "-Wno-tautological-unsigned-enum-zero-compare", |
| "-Wno-tautological-unsigned-zero-compare", |
| "-Wno-thread-safety-negative", |
| "-Wno-unused", |
| "-Wno-unused-command-line-argument", |
| "-Wno-zero-as-null-pointer-constant", |
| "-Wpointer-arith", |
| "-Wsign-promo", |
| "-Wstrict-aliasing=2", |
| ] |
| LINKER_FLAGS = [ |
| "-nostdlib", |
| "-Wl,-z,noexecstack", |
| "-Wl,-z,relro", |
| "-Wl,-z,now", |
| "-Wl,--build-id=md5", |
| "-Wl,--warn-shared-textrel", |
| "-Wl,--fatal-warnings", |
| "-Wl,--no-undefined-version", |
| "-Wl,--exclude-libs,libgcc.a", |
| "-Wl,--exclude-libs,libgcc_stripped.a", |
| "-fuse-ld=lld", |
| "-Wl,--no-undefined", |
| "-Wl,--hash-style=gnu", |
| "-Wl,--gc-sections", |
| ] |
| STATIC_LINKER_FLAGS = [ |
| "-static", |
| ] |
| DYNAMIC_LINKER_FLAGS = [] |
| |
| def _tool_paths(clang_version_info): |
| return [ |
| tool_path( |
| name = "gcc", |
| path = clang_version_info.directory.basename + "/bin/clang", |
| ), |
| tool_path( |
| name = "ld", |
| path = clang_version_info.directory.basename + "/bin/ld.lld", |
| ), |
| tool_path( |
| name = "ar", |
| path = clang_version_info.directory.basename + "/bin/llvm-ar", |
| ), |
| tool_path( |
| name = "cpp", |
| path = "/bin/false", |
| ), |
| tool_path( |
| name = "gcov", |
| path = "/bin/false", |
| ), |
| tool_path( |
| name = "nm", |
| path = clang_version_info.directory.basename + "/bin/llvm-nm", |
| ), |
| tool_path( |
| name = "objdump", |
| path = clang_version_info.directory.basename + "/bin/llvm-objdump", |
| ), |
| # Soong has a wrapper around strip. |
| # https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/strip.go;l=62;drc=master |
| # https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/builder.go;l=991-1025;drc=master |
| tool_path( |
| name = "strip", |
| path = clang_version_info.directory.basename + "/bin/llvm-strip", |
| ), |
| ] |
| |
| def _compiler_flag_features( |
| flags = [], |
| asm_only_flags = [], |
| c_only_flags = [], |
| non_external_flags = []): |
| features = [] |
| if non_external_flags: |
| features.append(feature( |
| name = "non_external_compiler_flags", |
| enabled = True, |
| flag_sets = [ |
| flag_set( |
| actions = [ |
| ACTION_NAMES.c_compile, |
| ACTION_NAMES.cpp_compile, |
| ACTION_NAMES.assemble, |
| ACTION_NAMES.preprocess_assemble, |
| ], |
| flag_groups = [ |
| flag_group( |
| flags = non_external_flags, |
| ), |
| ], |
| ), |
| ], |
| )) |
| if flags: |
| features.append(feature( |
| name = "common_compiler_flags", |
| enabled = True, |
| flag_sets = [ |
| flag_set( |
| actions = [ |
| ACTION_NAMES.c_compile, |
| ACTION_NAMES.cpp_compile, |
| ACTION_NAMES.assemble, |
| ACTION_NAMES.preprocess_assemble, |
| ], |
| flag_groups = [ |
| flag_group( |
| flags = flags, |
| ), |
| ], |
| ), |
| ], |
| )) |
| if asm_only_flags: |
| features.append(feature( |
| name = "asm_compiler_flags", |
| enabled = True, |
| flag_sets = [ |
| flag_set( |
| actions = [ |
| ACTION_NAMES.assemble, |
| ACTION_NAMES.preprocess_assemble, |
| ], |
| flag_groups = [ |
| flag_group( |
| flags = asm_only_flags, |
| ), |
| ], |
| ), |
| ], |
| )) |
| if c_only_flags: |
| features.append(feature( |
| name = "c_compiler_flags", |
| enabled = True, |
| flag_sets = [ |
| flag_set( |
| actions = [ |
| ACTION_NAMES.c_compile, |
| ACTION_NAMES.assemble, |
| ACTION_NAMES.preprocess_assemble, |
| ], |
| flag_groups = [ |
| flag_group( |
| flags = c_only_flags, |
| ), |
| ], |
| ), |
| ], |
| )) |
| features.append(feature( |
| name = "cc_compiler_flags", |
| enabled = True, |
| flag_sets = [ |
| flag_set( |
| actions = [ |
| ACTION_NAMES.cpp_compile, |
| ], |
| flag_groups = [ |
| flag_group( |
| flags = CC_COMPILER_FLAGS, |
| ), |
| ], |
| ), |
| ], |
| )) |
| features.append(feature( |
| name = "cpp_std_experimental", |
| flag_sets = [ |
| flag_set( |
| actions = [ |
| ACTION_NAMES.cpp_compile, |
| ], |
| flag_groups = [ |
| flag_group( |
| flags = CC_COMPILER_EXPERIMENTAL_STD_FLAGS, |
| ), |
| ], |
| ), |
| ], |
| )) |
| features.append(feature( |
| name = "cpp_std_standard", |
| enabled = True, |
| flag_sets = [ |
| flag_set( |
| actions = [ |
| ACTION_NAMES.cpp_compile, |
| ], |
| with_features = [ |
| with_feature_set(not_features = ["cpp_std_experimental"]), |
| ], |
| flag_groups = [ |
| flag_group( |
| flags = CC_COMPILER_STANDARD_STD_FLAGS, |
| ), |
| ], |
| ), |
| ], |
| )) |
| return features |
| |
| def _rpath_features(): |
| runtime_library_search_directories_feature = feature( |
| name = "runtime_library_search_directories", |
| flag_sets = [ |
| flag_set( |
| actions = [ |
| ACTION_NAMES.cpp_link_executable, |
| ACTION_NAMES.cpp_link_dynamic_library, |
| ACTION_NAMES.cpp_link_nodeps_dynamic_library, |
| ACTION_NAMES.lto_index_for_executable, |
| ACTION_NAMES.lto_index_for_dynamic_library, |
| ACTION_NAMES.lto_index_for_nodeps_dynamic_library, |
| ], |
| 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 = [ |
| ACTION_NAMES.cpp_link_executable, |
| ACTION_NAMES.cpp_link_dynamic_library, |
| ACTION_NAMES.cpp_link_nodeps_dynamic_library, |
| ACTION_NAMES.lto_index_for_executable, |
| ACTION_NAMES.lto_index_for_dynamic_library, |
| ACTION_NAMES.lto_index_for_nodeps_dynamic_library, |
| ], |
| 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"], |
| ), |
| ], |
| ), |
| ], |
| ) |
| disable_rpath_feature = feature( |
| name = "disable_rpath", |
| enabled = False, |
| ) |
| return [runtime_library_search_directories_feature, disable_rpath_feature] |
| |
| def _linker_flag_feature(name, flags = [], additional_static_flags = [], additional_dynamic_flags = []): |
| if not flags: |
| return None |
| return feature( |
| name = name, |
| enabled = True, |
| flag_sets = [ |
| flag_set( |
| actions = [ |
| ACTION_NAMES.assemble, |
| ACTION_NAMES.preprocess_assemble, |
| ACTION_NAMES.cpp_link_executable, |
| ], |
| flag_groups = [ |
| flag_group( |
| flags = flags, |
| ), |
| ], |
| ), |
| flag_set( |
| actions = [ |
| ACTION_NAMES.cpp_link_executable, |
| ], |
| flag_groups = [ |
| flag_group( |
| flags = flags + additional_static_flags, |
| ), |
| ], |
| ), |
| flag_set( |
| actions = [ |
| ACTION_NAMES.cpp_link_dynamic_library, |
| ], |
| flag_groups = [ |
| flag_group( |
| flags = flags + additional_dynamic_flags, |
| ), |
| ], |
| ), |
| ], |
| ) |
| |
| 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 = [ |
| ACTION_NAMES.assemble, |
| ACTION_NAMES.preprocess_assemble, |
| ACTION_NAMES.linkstamp_compile, |
| ACTION_NAMES.c_compile, |
| ACTION_NAMES.cpp_compile, |
| ACTION_NAMES.cpp_header_parsing, |
| ACTION_NAMES.cpp_module_compile, |
| ACTION_NAMES.cpp_module_codegen, |
| ACTION_NAMES.lto_backend, |
| ACTION_NAMES.clif_match, |
| ], |
| flag_groups = [ |
| flag_group( |
| flags = flags, |
| ), |
| ], |
| ), |
| ], |
| ) |
| |
| def _system_libraries_feature(system_libraries = []): |
| if not system_libraries: |
| return None |
| return feature( |
| name = "system_libraries", |
| enabled = True, |
| flag_sets = [ |
| flag_set( |
| actions = [ |
| ACTION_NAMES.cpp_link_executable, |
| ], |
| flag_groups = [ |
| flag_group( |
| flags = system_libraries, |
| ), |
| ], |
| ), |
| ], |
| ) |
| |
| def _cc_toolchain_config_impl(ctx): |
| clang_version_info = ctx.attr.clang_version[_ClangVersionInfo] |
| builtin_include_dirs = [] |
| |
| # This is so that Bazel doesn't validate .d files against the set of headers |
| # declared in BUILD files (Blueprint files don't contain that data) |
| builtin_include_dirs.extend(["/"]) |
| |
| builtin_include_dirs.extend(clang_version_info.includes) |
| compiler_flag_features = _compiler_flag_features( |
| flags = DEFINES + COMPILER_FLAGS + WARNINGS + ctx.attr.target_flags, |
| asm_only_flags = ASM_COMPILER_FLAGS, |
| c_only_flags = C_COMPILER_FLAGS, |
| non_external_flags = NON_EXTERNAL_DEFINES, |
| ) |
| linker_target_flag_feature = _linker_flag_feature( |
| "linker_target_flags", |
| flags = ctx.attr.target_flags, |
| ) |
| linker_flag_feature = _linker_flag_feature( |
| "linker_flags", |
| flags = LINKER_FLAGS + ctx.attr.linker_flags, |
| additional_static_flags = STATIC_LINKER_FLAGS, |
| additional_dynamic_flags = DYNAMIC_LINKER_FLAGS, |
| ) |
| toolchain_include_directories_feature = _toolchain_include_feature( |
| system_includes = builtin_include_dirs, |
| ) |
| system_libraries_feature = None |
| features = compiler_flag_features + _rpath_features() + [linker_target_flag_feature, linker_flag_feature, toolchain_include_directories_feature, system_libraries_feature] |
| features = [feature for feature in features if feature != None] |
| return cc_common.create_cc_toolchain_config_info( |
| ctx = ctx, |
| toolchain_identifier = "x86_64-toolchain", |
| host_system_name = "i686-unknown-linux-gnu", |
| target_system_name = "x86_64-unknown-unknown", |
| target_cpu = "x86_64", |
| target_libc = "unknown", |
| compiler = "clang", |
| abi_version = "unknown", |
| abi_libc_version = "unknown", |
| tool_paths = _tool_paths(clang_version_info), |
| features = features, |
| cxx_builtin_include_directories = builtin_include_dirs, |
| ) |
| |
| _cc_toolchain_config = rule( |
| implementation = _cc_toolchain_config_impl, |
| attrs = { |
| "clang_version": attr.label(mandatory = True, providers = [_ClangVersionInfo]), |
| "target_flags": attr.string_list(default = []), |
| "linker_flags": attr.string_list(default = []), |
| }, |
| provides = [CcToolchainConfigInfo], |
| ) |
| |
| # Macro to set up both the toolchain and the config. |
| def android_cc_toolchain( |
| name, |
| clang_version = None, |
| # This should come from the clang_version provider. |
| # Instead, it's hard-coded because this is a macro, not a rule. |
| clang_version_directory = None, |
| target_flags = [], |
| linker_flags = [], |
| toolchain_identifier = None): |
| # Write the toolchain config. |
| _cc_toolchain_config( |
| name = "%s_config" % name, |
| clang_version = clang_version, |
| target_flags = target_flags, |
| linker_flags = linker_flags, |
| ) |
| |
| # Create the filegroups needed for sandboxing toolchain inputs to C++ actions. |
| native.filegroup( |
| name = "%s_compiler_clang_includes" % name, |
| srcs = |
| native.glob([clang_version_directory + "/lib64/clang/*/include/**"]), |
| ) |
| |
| native.filegroup( |
| name = "%s_compiler_binaries" % name, |
| srcs = native.glob([ |
| clang_version_directory + "/bin/clang*", |
| ]), |
| ) |
| |
| native.filegroup( |
| name = "%s_linker_binaries" % name, |
| srcs = native.glob([ |
| # Linking shared libraries uses clang. |
| clang_version_directory + "/bin/clang*", |
| ]) + [ |
| clang_version_directory + "/bin/lld", |
| clang_version_directory + "/bin/ld.lld", |
| ], |
| ) |
| |
| native.filegroup( |
| name = "%s_ar_files" % name, |
| srcs = [clang_version_directory + "/bin/llvm-ar"], |
| ) |
| |
| native.filegroup( |
| name = "%s_compiler_files" % name, |
| srcs = [ |
| "%s_compiler_binaries" % name, |
| "%s_compiler_clang_includes" % name, |
| ], |
| ) |
| native.filegroup( |
| name = "%s_linker_files" % name, |
| srcs = [ |
| "%s_linker_binaries" % name, |
| ], |
| ) |
| native.filegroup( |
| name = "%s_all_files" % name, |
| srcs = [ |
| "%s_compiler_files" % name, |
| "%s_linker_files" % name, |
| "%s_ar_files" % name, |
| ], |
| ) |
| |
| # Create the actual cc_toolchain. |
| # The dependency on //:empty is intentional; it's necessary so that Bazel |
| # can parse .d files correctly (see the comment in $TOP/BUILD) |
| native.cc_toolchain( |
| name = name, |
| all_files = "%s_all_files" % name, |
| as_files = "//:empty", # Note the "//" prefix, see comment above |
| ar_files = "%s_ar_files" % name, |
| compiler_files = "%s_compiler_files" % name, |
| dwp_files = ":empty", |
| linker_files = "%s_linker_files" % name, |
| objcopy_files = ":empty", |
| strip_files = ":empty", |
| supports_param_files = 0, |
| toolchain_config = ":%s_config" % name, |
| toolchain_identifier = toolchain_identifier, |
| ) |