| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553 |
- # Part of the Carbon Language project, under the Apache License v2.0 with LLVM
- # Exceptions. See /LICENSE for license information.
- # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- """A Starlark cc_toolchain configuration rule"""
- load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES")
- load(
- "@rules_cc//cc:cc_toolchain_config_lib.bzl",
- "feature",
- "feature_set",
- "flag_group",
- "flag_set",
- "with_feature_set",
- )
- load("@rules_cc//cc:defs.bzl", "cc_toolchain")
- load("@rules_cc//cc/common:cc_common.bzl", "cc_common")
- load(
- ":cc_toolchain_actions.bzl",
- "all_compile_actions",
- "all_cpp_compile_actions",
- "all_link_actions",
- "codegen_compile_actions",
- "preprocessor_compile_actions",
- )
- load(
- ":cc_toolchain_base_features.bzl",
- "base_features",
- "output_flags_feature",
- "user_flags_feature",
- )
- load(":cc_toolchain_config_features.bzl", "target_os_features")
- load(":cc_toolchain_debugging.bzl", "debugging_features")
- load(
- ":cc_toolchain_linking.bzl",
- "default_link_libraries_feature",
- "linking_features",
- "macos_link_libraries_feature",
- )
- load(":cc_toolchain_modules.bzl", "modules_features")
- load(
- ":cc_toolchain_optimization.bzl",
- "aarch64_cpu_flags",
- "optimization_features",
- "x86_64_cpu_flags",
- )
- load(
- ":cc_toolchain_sanitizer_features.bzl",
- "macos_asan_workarounds",
- "sanitizer_features",
- "sanitizer_static_lib_flags",
- )
- load(
- ":cc_toolchain_tools.bzl",
- "llvm_action_configs",
- "llvm_tool_paths",
- )
- load(
- ":clang_detected_variables.bzl",
- "clang_bindir",
- "clang_include_dirs_list",
- "clang_resource_dir",
- "clang_version_for_cache",
- "llvm_bindir",
- "sysroot_dir",
- )
- def _build_features(ctx):
- # TODO: Refactor this into a reusable form in its own file.
- default_flags_feature = feature(
- name = "default_flags",
- enabled = True,
- flag_sets = [
- flag_set(
- actions = all_compile_actions + all_link_actions,
- flag_groups = [
- flag_group(flags = [
- "-no-canonical-prefixes",
- "-fcolor-diagnostics",
- ]),
- flag_group(
- expand_if_available = "sysroot",
- flags = ["--sysroot=%{sysroot}"],
- ),
- ],
- ),
- flag_set(
- actions = all_compile_actions,
- flag_groups = [
- # First, flags for all compiles, regardless of output.
- flag_group(flags = [
- "-Werror",
- "-Wall",
- "-Wextra",
- "-Wthread-safety",
- "-Wself-assign",
- "-Wimplicit-fallthrough",
- "-Wctad-maybe-unsupported",
- "-Wextra-semi",
- "-Wmissing-prototypes",
- "-Wzero-as-null-pointer-constant",
- "-Wdelete-non-virtual-dtor",
- # TODO: Regression that warns on anonymous unions;
- # remove depending on fix.
- "-Wno-missing-designated-field-initializers",
- # Don't warn on external code as we can't
- # necessarily patch it easily. Note that these have
- # to be initial directories in the `#include` line.
- "--system-header-prefix=absl/",
- "--system-header-prefix=benchmark/",
- "--system-header-prefix=boost/",
- "--system-header-prefix=clang-tools-extra/",
- "--system-header-prefix=clang/",
- "--system-header-prefix=gmock/",
- "--system-header-prefix=gtest/",
- "--system-header-prefix=libfuzzer/",
- "--system-header-prefix=llvm/",
- "--system-header-prefix=re2/",
- "--system-header-prefix=tools/cpp/",
- "--system-header-prefix=tree_sitter/",
- # Compile actions shouldn't link anything.
- "-c",
- ]),
- # Flags controlling the production of specific outputs from
- # compile actions.
- 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 = "dependency_file",
- flags = ["-MD", "-MF", "%{dependency_file}"],
- ),
- flag_group(
- expand_if_available = "output_file",
- flags = ["-frandom-seed=%{output_file}"],
- ),
- ],
- ),
- flag_set(
- # Flags specific to compiling C++ source.
- actions = all_cpp_compile_actions,
- flag_groups = [flag_group(flags = [
- "-std=c++20",
- ])],
- ),
- flag_set(
- actions = codegen_compile_actions,
- flag_groups = [flag_group(flags = [
- "-ffunction-sections",
- "-fdata-sections",
- ])],
- ),
- flag_set(
- actions = codegen_compile_actions,
- flag_groups = [flag_group(
- expand_if_available = "pic",
- flags = ["-fPIC"],
- )],
- ),
- flag_set(
- actions = preprocessor_compile_actions,
- flag_groups = [
- flag_group(flags = [
- # Disable a warning and override builtin macros to
- # ensure a hermetic build.
- "-Wno-builtin-macro-redefined",
- "-D__DATE__=\"redacted\"",
- "-D__TIMESTAMP__=\"redacted\"",
- "-D__TIME__=\"redacted\"",
- # Pass the clang version as a define so that bazel
- # caching is more likely to notice version changes.
- "-DCLANG_VERSION_FOR_CACHE=\"%s\"" % clang_version_for_cache,
- ]),
- flag_group(
- flags = ["-D%{preprocessor_defines}"],
- iterate_over = "preprocessor_defines",
- ),
- flag_group(
- expand_if_available = "includes",
- flags = ["-include", "%{includes}"],
- iterate_over = "includes",
- ),
- flag_group(
- flags = ["-iquote", "%{quote_include_paths}"],
- iterate_over = "quote_include_paths",
- ),
- flag_group(
- flags = ["-I%{include_paths}"],
- iterate_over = "include_paths",
- ),
- flag_group(
- flags = ["-isystem", "%{system_include_paths}"],
- iterate_over = "system_include_paths",
- ),
- ],
- ),
- flag_set(
- actions = [
- ACTION_NAMES.cpp_link_dynamic_library,
- ACTION_NAMES.cpp_link_nodeps_dynamic_library,
- ],
- flag_groups = [flag_group(flags = ["-shared"])],
- ),
- flag_set(
- actions = all_link_actions,
- flag_groups = [
- flag_group(
- expand_if_available = "strip_debug_symbols",
- flags = ["-Wl,-S"],
- ),
- flag_group(
- expand_if_available = "library_search_directories",
- flags = ["-L%{library_search_directories}"],
- iterate_over = "library_search_directories",
- ),
- flag_group(
- expand_if_available =
- "runtime_library_search_directories",
- iterate_over = "runtime_library_search_directories",
- flags = [
- "-Wl,-rpath,$ORIGIN/%{runtime_library_search_directories}",
- ],
- ),
- ],
- ),
- ],
- )
- libcxx_feature = feature(
- name = "libcxx",
- enabled = True,
- flag_sets = [
- flag_set(
- actions = all_cpp_compile_actions + all_link_actions,
- flag_groups = [flag_group(flags = [
- "-stdlib=libc++",
- ])],
- with_features = [
- # libc++ is only used on non-Windows platforms.
- with_feature_set(not_features = ["windows_target"]),
- ],
- ),
- flag_set(
- actions = all_link_actions,
- flag_groups = [flag_group(flags = [
- "-unwindlib=libunwind",
- ])],
- with_features = [
- # libc++ is only used on non-Windows platforms.
- with_feature_set(not_features = ["windows_target"]),
- ],
- ),
- ],
- )
- # An enabled feature that requires the `fastbuild` compilation. This is used
- # to toggle general features on by default, while allowing them to be
- # directly enabled and disabled more generally as desired.
- enable_in_fastbuild = feature(
- name = "enable_in_fastbuild",
- enabled = True,
- requires = [feature_set(["fastbuild"])],
- implies = [
- "asan",
- "asan_min_size",
- "minimal_optimization_flags",
- "minimal_debug_info_flags",
- ],
- )
- # Clang HARDENING_MODE has 4 possible values:
- # https://libcxx.llvm.org/Hardening.html#notes-for-users
- #
- # Do not enable DEBUG hardening mode, even for -c dbg, because its
- # performance impact on llvm-symbolizer is too severe -- this flag
- # results in symbolization becoming quadratic in the number of debug
- # symbols, in practice meaning it never completes.
- libcpp_debug_flags = [
- "-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE",
- ]
- libcpp_release_flags = [
- "-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST",
- ]
- # TODO: Refactor this into a reusable form in its own file.
- linux_flags_feature = feature(
- name = "linux_flags",
- enabled = True,
- flag_sets = [
- flag_set(
- actions = all_link_actions,
- flag_groups = [flag_group(
- flags = [
- "-fuse-ld=lld",
- # Force the C++ standard library and runtime libraries
- # to be statically linked. This works even with libc++
- # and libunwind despite the names, provided libc++ is
- # built with the CMake option:
- # - `-DCMAKE_POSITION_INDEPENDENT_CODE=ON`
- "-static-libstdc++",
- "-static-libgcc",
- # Link with Clang's runtime library. This is always
- # linked statically.
- "-rtlib=compiler-rt",
- # Explicitly add LLVM libs to the search path to preempt
- # the detected GCC installation's library paths. Those
- # might have a system installed libc++ and we want to
- # find the one next to our Clang.
- "-L" + llvm_bindir + "/../lib",
- # Link with pthread.
- "-lpthread",
- # Force linking the static libc++abi archive here. This
- # *should* be linked automatically, but not every
- # release of LLVM correctly sets the CMake flags to do
- # so.
- "-l:libc++abi.a",
- ],
- )],
- ),
- flag_set(
- actions = all_compile_actions,
- flag_groups = [flag_group(flags = libcpp_debug_flags)],
- with_features = [with_feature_set(not_features = ["opt"])],
- ),
- flag_set(
- actions = all_compile_actions,
- flag_groups = [flag_group(flags = libcpp_release_flags)],
- with_features = [with_feature_set(features = ["opt"])],
- ),
- flag_set(
- actions = [ACTION_NAMES.cpp_link_executable],
- flag_groups = [flag_group(
- expand_if_available = "force_pic",
- flags = ["-pie"],
- )],
- ),
- ],
- )
- # TODO: Refactor this into a reusable form in its own file.
- macos_flags_feature = feature(
- name = "macos_flags",
- enabled = True,
- flag_sets = [
- flag_set(
- actions = [ACTION_NAMES.cpp_link_executable],
- flag_groups = [flag_group(
- expand_if_available = "force_pic",
- flags = ["-fpie"],
- )],
- ),
- ],
- )
- # TODO: Refactor this into a reusable form in its own file.
- freebsd_flags_feature = feature(
- name = "freebsd_flags",
- enabled = True,
- flag_sets = [
- flag_set(
- actions = [
- ACTION_NAMES.c_compile,
- ACTION_NAMES.cpp_compile,
- ACTION_NAMES.cpp_header_parsing,
- ACTION_NAMES.cpp_module_compile,
- ],
- flag_groups = [flag_group(flags = ["-DHAVE_MALLCTL"])],
- ),
- flag_set(
- actions = [ACTION_NAMES.cpp_link_executable],
- flag_groups = [flag_group(
- expand_if_available = "force_pic",
- flags = ["-pie"],
- )],
- ),
- ],
- )
- # The order of the features determines the relative order of flags used.
- features = []
- features += base_features
- features += target_os_features(ctx.attr.target_os)
- features += [
- default_flags_feature,
- libcxx_feature,
- ]
- features += sanitizer_features
- features += optimization_features
- # TODO: Refactor target-specific feature management to be part of
- # `optimization_features`.
- if ctx.attr.target_cpu in ["aarch64", "arm64"]:
- features.append(aarch64_cpu_flags)
- else:
- features.append(x86_64_cpu_flags)
- features += modules_features
- features += debugging_features
- # Next, add the features based on the target platform. Here too the
- # features are order sensitive.
- if ctx.attr.target_os == "linux":
- features.append(sanitizer_static_lib_flags)
- features.append(linux_flags_feature)
- sysroot = None
- elif ctx.attr.target_os == "windows":
- # TODO: Need to figure out if we need to add windows specific features
- # I think the .pdb debug files will need to be handled differently,
- # so that might be an example where a feature must be added.
- sysroot = None
- elif ctx.attr.target_os == "macos":
- features.append(macos_asan_workarounds)
- features.append(macos_flags_feature)
- sysroot = sysroot_dir
- elif ctx.attr.target_os == "freebsd":
- features.append(sanitizer_static_lib_flags)
- features.append(freebsd_flags_feature)
- sysroot = sysroot_dir
- else:
- fail("Unsupported target OS!")
- # Next, append the libraries to link.
- features += linking_features
- # TODO: Refactor the target-specific feature management here to be part of
- # building `linking_features`.
- features += [
- feature(name = "supports_dynamic_linker", enabled = ctx.attr.target_os == "linux"),
- feature(name = "supports_start_end_lib", enabled = ctx.attr.target_os == "linux"),
- ]
- if ctx.attr.target_os == "macos":
- features.append(macos_link_libraries_feature)
- else:
- features.append(default_link_libraries_feature)
- # Lastly, we add a feature that enables others in the default `fastbuild`
- # mode. This is also a good place to add any project-specific features.
- features.append(enable_in_fastbuild)
- # Add user flags and the output flags at the end.
- features.append(user_flags_feature)
- features.append(output_flags_feature)
- return features
- def _impl(ctx):
- # TODO: See if this can be refactored into platform features.
- if ctx.attr.target_os == "linux":
- sysroot = None
- elif ctx.attr.target_os == "windows":
- sysroot = None
- elif ctx.attr.target_os == "macos":
- sysroot = sysroot_dir
- elif ctx.attr.target_os == "freebsd":
- sysroot = sysroot_dir
- else:
- fail("Unsupported target OS!")
- identifier = "local-{0}-{1}".format(ctx.attr.target_cpu, ctx.attr.target_os)
- return cc_common.create_cc_toolchain_config_info(
- ctx = ctx,
- features = _build_features(ctx),
- action_configs = llvm_action_configs(llvm_bindir, clang_bindir),
- cxx_builtin_include_directories = clang_include_dirs_list + [
- # Add Clang's resource directory to the end of the builtin include
- # directories to cover the use of sanitizer resource files by the
- # driver.
- clang_resource_dir + "/share",
- ],
- builtin_sysroot = sysroot,
- # This configuration only supports local non-cross builds so derive
- # everything from the target CPU selected.
- toolchain_identifier = identifier,
- host_system_name = identifier,
- target_system_name = identifier,
- target_cpu = ctx.attr.target_cpu,
- # This is used to expose a "flag" that `config_setting` rules can use to
- # determine if the compiler is Clang.
- compiler = "clang",
- # These attributes aren't meaningful at all so just use placeholder
- # values.
- target_libc = "local",
- abi_version = "local",
- abi_libc_version = "local",
- # We do have to pass in our tool paths.
- tool_paths = llvm_tool_paths(llvm_bindir, clang_bindir),
- )
- cc_toolchain_config = rule(
- implementation = _impl,
- attrs = {
- "target_cpu": attr.string(mandatory = True),
- "target_os": attr.string(mandatory = True),
- },
- provides = [CcToolchainConfigInfo],
- )
- def cc_local_toolchain_suite(name, configs):
- """Create a toolchain suite that uses the local Clang/LLVM install.
- Args:
- name: The name of the toolchain suite to produce.
- configs: An array of (os, cpu) pairs to support in the toolchain.
- """
- # An empty filegroup to use when stubbing out the toolchains.
- native.filegroup(
- name = name + "_empty",
- srcs = [],
- )
- # Create the individual local toolchains for each CPU.
- for (os, cpu) in configs:
- config_name = "{0}_{1}_{2}".format(name, os, cpu)
- cc_toolchain_config(
- name = config_name + "_config",
- target_os = os,
- target_cpu = cpu,
- )
- cc_toolchain(
- name = config_name + "_tools",
- all_files = ":" + name + "_empty",
- ar_files = ":" + name + "_empty",
- as_files = ":" + name + "_empty",
- compiler_files = ":" + name + "_empty",
- dwp_files = ":" + name + "_empty",
- linker_files = ":" + name + "_empty",
- objcopy_files = ":" + name + "_empty",
- strip_files = ":" + name + "_empty",
- supports_param_files = 1,
- toolchain_config = ":" + config_name + "_config",
- toolchain_identifier = config_name,
- )
- compatible_with = ["@platforms//cpu:" + cpu, "@platforms//os:" + os]
- native.toolchain(
- name = config_name,
- exec_compatible_with = compatible_with,
- target_compatible_with = compatible_with,
- toolchain = config_name + "_tools",
- toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
- )
|