| # Copyright 2022 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """ |
| C++ toolchain definitions for Clang. |
| """ |
| |
| load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES") |
| load( |
| "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", |
| "feature", |
| "flag_group", |
| "flag_set", |
| "tool_path", |
| "with_feature_set", |
| ) |
| load("@prebuilt_clang//:generated_constants.bzl", clang_constants = "constants") |
| load("@//:build/bazel/toolchains/clang/sanitizer.bzl", "sanitizer_features") |
| |
| def _prebuilt_clang_cc_toolchain_config_impl(ctx): |
| clang_binprefix = "bin/" |
| |
| # See CppConfiguration.java class in Bazel sources for the list of |
| # all tool_path() names that must be defined. |
| tool_paths = [ |
| tool_path(name = "ar", path = clang_binprefix + "llvm-ar"), |
| tool_path(name = "cpp", path = clang_binprefix + "cpp"), |
| tool_path(name = "gcc", path = clang_binprefix + "clang"), |
| tool_path(name = "gcov", path = "/usr/bin/false"), |
| tool_path(name = "gcov-tool", path = "/usr/bin/false"), |
| tool_path(name = "ld", path = clang_binprefix + "llvm-ld"), |
| tool_path(name = "llvm-cov", path = clang_binprefix + "llvm-cov"), |
| tool_path(name = "nm", path = clang_binprefix + "llvm-nm"), |
| tool_path("objcopy", path = clang_binprefix + "llvm-objcopy"), |
| tool_path("objdump", path = clang_binprefix + "llvm-objdump"), |
| tool_path("strip", path = clang_binprefix + "llvm-strip"), |
| tool_path(name = "dwp", path = "/usr/bin/false"), |
| tool_path(name = "llbm-profdata", path = clang_binprefix + "llvm-profdata"), |
| ] |
| |
| # Redefine the dependency_files feature in order to use -MMD instead of -MD |
| # which ensures that system headers files are not listed in the dependency file. |
| # Doing this allows remote builds to work with our prebuilt toolchain. Otherwise |
| # the paths in cxx_builtin_include_directories will not match the ones that are |
| # generated in the remote builder, resulting in an error like: |
| # |
| # ``` |
| # ERROR: ..../workspace/build/bazel/tests/hello_world/BUILD.bazel:5:10: Compiling build/bazel/tests/hello_world/main.cc failed: undeclared inclusion(s) in rule '//build/bazel/tests/hello_world:hello_world': |
| # this rule is missing dependency declarations for the following files included by 'build/bazel/tests/hello_world/main.cc': |
| # '/b/f/w/external/prebuilt_clang/include/c++/v1/stdio.h' |
| # '/b/f/w/external/prebuilt_clang/include/c++/v1/__config' |
| # '/b/f/w/external/prebuilt_clang/include/x86_64-unknown-linux-gnu/c++/v1/__config_site' |
| # '/b/f/w/external/prebuilt_clang/include/c++/v1/stddef.h' |
| # '/b/f/w/external/prebuilt_clang/lib/clang/16.0.0/include/stddef.h' |
| # '/b/f/w/external/prebuilt_clang/include/c++/v1/wchar.h' |
| # '/b/f/w/external/prebuilt_clang/lib/clang/16.0.0/include/stdarg.h' |
| # Target //build/bazel/tests/hello_world:hello_world failed to build |
| # ``` |
| # Where `/b/f/w/` is the path of the execroot in the remote builder. |
| # |
| # Note that trying to set paths relative to the execroot in cxx_builtin_include_directories |
| # does not work (Bazel resolves them to absolute paths before recording them and trying to launch |
| # remote builds). |
| # |
| # Another benefit is that we can symlink the prebuilt clang directory |
| # in our @prebuilt_clang repository now. This does not work with -MD because |
| # the path generated by the compiler for dependencies are fully resolved |
| # and would not match the content of cxx_builtin_include_directories, |
| # resulting in errors like the one above, where the path listed in the |
| # dependency would be something like |
| # `/fuchsia/prebuilt/third_party/clang/linux-x64/include/c++/v1/wchar.h` |
| # instead of the expected `external/prebuilt_clang/include/c++/c1/wchar.h` |
| |
| # See https://cs.opensource.google/bazel/bazel/+/master:tools/cpp/unix_cc_toolchain_config.bzl;drc=ed03d3edc3bab62942f2f9fab51f342fc8280930;l=1009 |
| # for the original feature() definition. |
| dependency_file_feature = feature( |
| name = "dependency_file", |
| enabled = True, |
| flag_sets = [ |
| flag_set( |
| actions = [ |
| ACTION_NAMES.assemble, |
| ACTION_NAMES.preprocess_assemble, |
| ACTION_NAMES.c_compile, |
| ACTION_NAMES.cpp_compile, |
| ACTION_NAMES.cpp_module_compile, |
| ACTION_NAMES.objc_compile, |
| ACTION_NAMES.objcpp_compile, |
| ACTION_NAMES.cpp_header_parsing, |
| ACTION_NAMES.clif_match, |
| ], |
| flag_groups = [ |
| flag_group( |
| flags = ["-MMD", "-MF", "%{dependency_file}"], |
| expand_if_available = "dependency_file", |
| ), |
| ], |
| ), |
| ], |
| ) |
| |
| ml_inliner_feature = feature( |
| name = "ml_inliner", |
| flag_sets = [ |
| flag_set( |
| actions = [ |
| ACTION_NAMES.c_compile, |
| ACTION_NAMES.cpp_compile, |
| ACTION_NAMES.cpp_module_compile, |
| ], |
| flag_groups = [ |
| flag_group( |
| flags = [ |
| "-mllvm", |
| "-enable-ml-inliner=release", |
| ], |
| ), |
| ], |
| with_features = [with_feature_set( |
| features = ["opt"], |
| )], |
| ), |
| ], |
| ) |
| |
| coverage_feature = feature( |
| name = "coverage", |
| flag_sets = [ |
| flag_set( |
| actions = [ |
| ACTION_NAMES.c_compile, |
| ACTION_NAMES.cpp_compile, |
| ACTION_NAMES.cpp_link_dynamic_library, |
| ACTION_NAMES.cpp_link_executable, |
| ACTION_NAMES.cpp_link_nodeps_dynamic_library, |
| ], |
| flag_groups = [ |
| flag_group( |
| flags = [ |
| "-fprofile-instr-generate", |
| "-fcoverage-mapping", |
| # Apply some optimizations so tests are fast, |
| # but not too much so that coverage is inaccurate. |
| "-O1", |
| ], |
| ), |
| ], |
| ), |
| ], |
| ) |
| |
| features = [dependency_file_feature, ml_inliner_feature, coverage_feature] + sanitizer_features |
| |
| return cc_common.create_cc_toolchain_config_info( |
| ctx = ctx, |
| toolchain_identifier = "prebuilt_clang", |
| tool_paths = tool_paths, |
| features = features, |
| action_configs = [], |
| cxx_builtin_include_directories = clang_constants.builtin_include_paths, |
| builtin_sysroot = ctx.attr.sysroot, |
| target_cpu = "_".join([ctx.attr.target_os, ctx.attr.target_arch]), |
| |
| # Required by constructor, but otherwise ignored by Bazel. |
| # These string values are arbitrary, but are easy to grep |
| # in our source tree if they ever happen to appear in |
| # build error messages. |
| host_system_name = "__bazel_host_system_name__", |
| target_system_name = "__bazel_target_system_name__", |
| target_libc = "__bazel_target_libc__", |
| abi_version = "__bazel_abi_version__", |
| abi_libc_version = "__bazel_abi_libc_version__", |
| compiler = "__bazel_compiler__", |
| ) |
| |
| _prebuilt_clang_cc_toolchain_config = rule( |
| implementation = _prebuilt_clang_cc_toolchain_config_impl, |
| attrs = { |
| "target_os": attr.string(mandatory = True), |
| "target_arch": attr.string(mandatory = True), |
| "sysroot": attr.string(mandatory = True), |
| }, |
| ) |
| |
| def prebuilt_clang_cc_toolchain( |
| name, |
| host_os, |
| host_arch, |
| target_os, |
| target_arch, |
| sysroot_files, |
| sysroot_path): |
| """Define C++ toolchain related targets for a prebuilt Clang installation. |
| |
| This defines cc_toolchain(), cc_toolchain_config() and toolchain() targets |
| for a given Clang prebuilt installation and target (os,arch) pair |
| with a specific sysroot. |
| |
| Args: |
| name: Name of the cc_toolchain() target. The corresponding |
| toolchain() target will use "${name}_cc_toolchain", and |
| the cc_toolchain_config() will use "${name}_toolchain_config". |
| |
| host_os: Host os string (e.g. "linux" or "mac"). |
| host_arch: Host cpu architecture string (e.g. "x64" or "arm64"). |
| target_os: Target os string (e.g. "linux" or "fuchsia"). |
| target_arch: Target cpu architecture string. |
| sysroot_files: A target list for the sysroot files to be used. |
| sysroot_path: Path to the sysroot directory to be used. |
| """ |
| empty = "@prebuilt_clang//:empty" |
| |
| _prebuilt_clang_cc_toolchain_config( |
| name = name + "_toolchain_config", |
| target_os = target_os, |
| target_arch = target_arch, |
| sysroot = sysroot_path, |
| ) |
| |
| common_compiler_files = [ |
| "@prebuilt_clang//:compiler_binaries", |
| "@prebuilt_clang//:headers", |
| ] |
| |
| common_linker_files = [ |
| "@prebuilt_clang//:linker_binaries", |
| "@prebuilt_clang//:runtime_libraries", |
| ] |
| |
| native.filegroup( |
| name = name + "_compiler_files", |
| srcs = common_compiler_files + sysroot_files, |
| ) |
| |
| native.filegroup( |
| name = name + "_linker_files", |
| srcs = common_linker_files + sysroot_files, |
| ) |
| |
| native.filegroup( |
| name = name + "_all_files", |
| srcs = common_compiler_files + common_linker_files + sysroot_files, |
| ) |
| |
| native.cc_toolchain( |
| name = name, |
| all_files = ":%s_all_files" % name, |
| ar_files = "@prebuilt_clang//:ar_binaries", |
| as_files = empty, |
| compiler_files = ":%s_compiler_files" % name, |
| dwp_files = empty, |
| linker_files = ":%s_linker_files" % name, |
| objcopy_files = "@prebuilt_clang//:objcopy_binaries", |
| strip_files = "@prebuilt_clang//:strip_binaries", |
| # TODO(digit): Determine appropriate `supports_param_files` value |
| # after decyphering the Bazel documentation or inspecting its source |
| # code. :-( |
| supports_param_files = 0, |
| toolchain_config = name + "_toolchain_config", |
| toolchain_identifier = "prebuilt_clang", |
| ) |
| |
| native.toolchain( |
| name = name + "_cc_toolchain", |
| exec_compatible_with = [ |
| "@//build/bazel/platforms/os:" + host_os, |
| "@//build/bazel/platforms/arch:" + host_arch, |
| ], |
| target_compatible_with = [ |
| "@//build/bazel/platforms/os:" + target_os, |
| "@//build/bazel/platforms/arch:" + target_arch, |
| ], |
| toolchain = ":" + name, |
| toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", |
| ) |
| |
| def define_host_prebuilt_clang_cc_toolchains(name, host_os, host_arch): |
| """Define host C++ toolchains that target both x64 and arm64 using a prebuilt Clang installation. |
| |
| Args: |
| name: A prefix for the name of the toolchains generated by this function. |
| host_os: Host os string using Fuchsia conventions. |
| host_arch: Host cpu architecture string, using Fuchsia conventions. |
| """ |
| if host_os == "linux": |
| _sysroot_files_x64 = ["@//:linux_sysroot_x64"] |
| _sysroot_files_arm64 = ["@//:linux_sysroot_arm64"] |
| _sysroot_path = "prebuilt/third_party/sysroot/linux" |
| else: |
| _sysroot_files_x64 = [] |
| _sysroot_files_arm64 = [] |
| _sysroot_path = "" |
| |
| prebuilt_clang_cc_toolchain( |
| name = name + "_" + host_os + "_x64", |
| host_os = host_os, |
| host_arch = host_arch, |
| target_os = host_os, |
| target_arch = "x64", |
| sysroot_files = _sysroot_files_x64, |
| sysroot_path = _sysroot_path, |
| ) |
| |
| prebuilt_clang_cc_toolchain( |
| name = name + "_" + host_os + "_arm64", |
| host_os = host_os, |
| host_arch = host_arch, |
| target_os = host_os, |
| target_arch = "arm64", |
| sysroot_files = _sysroot_files_arm64, |
| sysroot_path = _sysroot_path, |
| ) |