Merge pull request #244 from keith:ks/allow-extra-args-to-cc_sysroot

PiperOrigin-RevId: 682280945
Change-Id: I1f0256f6c99dd1e67efdcd08145700e10ab26e6a
diff --git a/.bcr/metadata.template.json b/.bcr/metadata.template.json
index 9f0e465..8cf8ee2 100644
--- a/.bcr/metadata.template.json
+++ b/.bcr/metadata.template.json
@@ -1,6 +1,12 @@
 {
   "homepage": "https://github.com/bazelbuild/rules_cc",
-  "maintainers": [],
+  "maintainers": [
+    {
+      "email": "ilist@google.com",
+      "github": "comius",
+      "name": "Ivo Ristovski List"
+    }
+  ],
   "versions": [],
   "yanked_versions": {}
 }
diff --git a/.bcr/presubmit.yml b/.bcr/presubmit.yml
index 52869b1..902c89c 100644
--- a/.bcr/presubmit.yml
+++ b/.bcr/presubmit.yml
@@ -1,8 +1,12 @@
 matrix:
   platform: ["centos7", "debian10", "macos", "ubuntu2004", "windows"]
+  bazel:
+  - 6.x
+  - 7.x
 tasks:
   verify_targets:
     name: "Verify build targets"
     platform: ${{ platform }}
+    bazel: ${{ bazel }}
     build_targets:
       - "@rules_cc//cc/..."
diff --git a/.bcr/source.template.json b/.bcr/source.template.json
index 4f14819..53c3bbe 100644
--- a/.bcr/source.template.json
+++ b/.bcr/source.template.json
@@ -1,5 +1,5 @@
 {
   "integrity": "",
   "strip_prefix": "{REPO}-{VERSION}",
-  "url": "https://github.com/{OWNER}/{REPO}/archive/refs/tags/{TAG}.tar.gz"
+  "url": "https://github.com/{OWNER}/{REPO}/releases/download/{TAG}/rules_cc-{TAG}.tar.gz"
 }
diff --git a/.gitignore b/.gitignore
index 65e8edc..7f69f3a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,2 @@
-/bazel-*
\ No newline at end of file
+/bazel-*
+MODULE.bazel.lock
diff --git a/MODULE.bazel b/MODULE.bazel
index 91092b0..5fa70e9 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -8,8 +8,8 @@
 bazel_dep(name = "platforms", version = "0.0.10")
 bazel_dep(name = "stardoc", version = "0.7.0")
 
-cc_configure = use_extension("@bazel_tools//tools/cpp:cc_configure.bzl", "cc_configure_extension")
-use_repo(cc_configure, "local_config_cc_toolchains")
+cc_configure = use_extension("//cc:extensions.bzl", "cc_configure_extension")
+use_repo(cc_configure, "local_config_cc", "local_config_cc_toolchains")
 
 register_toolchains("@local_config_cc_toolchains//:all")
 
diff --git a/cc/BUILD b/cc/BUILD
index d0db658..0fb5da3 100644
--- a/cc/BUILD
+++ b/cc/BUILD
@@ -102,4 +102,9 @@
 
 cc_toolchain_alias(name = "current_cc_toolchain")
 
+cc_toolchain_alias(
+    name = "optional_current_cc_toolchain",
+    mandatory = False,
+)
+
 cc_libc_top_alias(name = "current_libc_top")
diff --git a/cc/action_names.bzl b/cc/action_names.bzl
index 3df7cfa..31a5967 100644
--- a/cc/action_names.bzl
+++ b/cc/action_names.bzl
@@ -33,6 +33,13 @@
 # Name of the C++ header parsing action.
 CPP_HEADER_PARSING_ACTION_NAME = "c++-header-parsing"
 
+# Name of the C++ deps scanning action.
+CPP_MODULE_DEPS_SCANNING_ACTION_NAME = "c++-module-deps-scanning"
+
+# Name of the C++ module compile action.
+CPP20_MODULE_COMPILE_ACTION_NAME = "c++20-module-compile"
+CPP20_MODULE_CODEGEN_ACTION_NAME = "c++20-module-codegen"
+
 # Name of the C++ module compile action.
 CPP_MODULE_COMPILE_ACTION_NAME = "c++-module-compile"
 
@@ -42,6 +49,8 @@
 # Name of the assembly preprocessing action.
 PREPROCESS_ASSEMBLE_ACTION_NAME = "preprocess-assemble"
 
+LLVM_COV = "llvm-cov"
+
 # Name of the action producing ThinLto index.
 LTO_INDEXING_ACTION_NAME = "lto-indexing"
 
@@ -85,9 +94,15 @@
 # A string constant for the objc fully-link link action.
 OBJC_FULLY_LINK_ACTION_NAME = "objc-fully-link"
 
-# A string constant for the clif action.
+# A string constant for the clif actions.
 CLIF_MATCH_ACTION_NAME = "clif-match"
 
+# A string constant for the obj copy actions.
+OBJ_COPY_ACTION_NAME = "objcopy_embed_data"
+
+# A string constant for the validation action for cc_static_library.
+VALIDATE_STATIC_LIBRARY = "validate-static-library"
+
 ACTION_NAMES = struct(
     c_compile = C_COMPILE_ACTION_NAME,
     cpp_compile = CPP_COMPILE_ACTION_NAME,
@@ -95,9 +110,13 @@
     cc_flags_make_variable = CC_FLAGS_MAKE_VARIABLE_ACTION_NAME,
     cpp_module_codegen = CPP_MODULE_CODEGEN_ACTION_NAME,
     cpp_header_parsing = CPP_HEADER_PARSING_ACTION_NAME,
+    cpp_module_deps_scanning = CPP_MODULE_DEPS_SCANNING_ACTION_NAME,
+    cpp20_module_compile = CPP20_MODULE_COMPILE_ACTION_NAME,
+    cpp20_module_codegen = CPP20_MODULE_CODEGEN_ACTION_NAME,
     cpp_module_compile = CPP_MODULE_COMPILE_ACTION_NAME,
     assemble = ASSEMBLE_ACTION_NAME,
     preprocess_assemble = PREPROCESS_ASSEMBLE_ACTION_NAME,
+    llvm_cov = LLVM_COV,
     lto_indexing = LTO_INDEXING_ACTION_NAME,
     lto_backend = LTO_BACKEND_ACTION_NAME,
     lto_index_for_executable = LTO_INDEX_FOR_EXECUTABLE_ACTION_NAME,
@@ -113,6 +132,8 @@
     objc_fully_link = OBJC_FULLY_LINK_ACTION_NAME,
     objcpp_compile = OBJCPP_COMPILE_ACTION_NAME,
     clif_match = CLIF_MATCH_ACTION_NAME,
+    objcopy_embed_data = OBJ_COPY_ACTION_NAME,
+    validate_static_library = VALIDATE_STATIC_LIBRARY,
 )
 
 # Names of actions that parse or compile C++ code.
diff --git a/cc/compiler/BUILD b/cc/compiler/BUILD
index 41f00e4..eecccaa 100644
--- a/cc/compiler/BUILD
+++ b/cc/compiler/BUILD
@@ -29,9 +29,9 @@
     name = "foo",
     srcs = ["foo.cc"],
     copts = select({
-        "@rules_cc//cc/compiler:gcc": [...],
-        "@rules_cc//cc/compiler:clang": [...],
-        "@rules_cc//cc/compiler:msvc-cl": [...],
+        "//cc/compiler:gcc": [...],
+        "//cc/compiler:clang": [...],
+        "//cc/compiler:msvc-cl": [...],
         # Fallback case for an undetected compiler.
         "//conditions:default": [...],
     }),
@@ -47,25 +47,25 @@
 
 config_setting(
     name = "clang",
-    flag_values = {"@bazel_tools//tools/cpp:compiler": "clang"},
+    flag_values = {"@rules_cc//cc/private/toolchain:compiler": "clang"},
 )
 
 config_setting(
     name = "clang-cl",
-    flag_values = {"@bazel_tools//tools/cpp:compiler": "clang-cl"},
+    flag_values = {"@rules_cc//cc/private/toolchain:compiler": "clang-cl"},
 )
 
 config_setting(
     name = "gcc",
-    flag_values = {"@bazel_tools//tools/cpp:compiler": "gcc"},
+    flag_values = {"@rules_cc//cc/private/toolchain:compiler": "gcc"},
 )
 
 config_setting(
     name = "mingw-gcc",
-    flag_values = {"@bazel_tools//tools/cpp:compiler": "mingw-gcc"},
+    flag_values = {"@rules_cc//cc/private/toolchain:compiler": "mingw-gcc"},
 )
 
 config_setting(
     name = "msvc-cl",
-    flag_values = {"@bazel_tools//tools/cpp:compiler": "msvc-cl"},
+    flag_values = {"@rules_cc//cc/private/toolchain:compiler": "msvc-cl"},
 )
diff --git a/cc/extensions.bzl b/cc/extensions.bzl
index 72b2dca..1ac80dc 100644
--- a/cc/extensions.bzl
+++ b/cc/extensions.bzl
@@ -13,12 +13,11 @@
 # limitations under the License.
 """Module extension for cc auto configuration."""
 
-load("@bazel_tools//tools/osx:xcode_configure.bzl", "xcode_configure")
 load("//cc/private/toolchain:cc_configure.bzl", "cc_autoconf", "cc_autoconf_toolchains")
 
-def _cc_configure_impl(_):
+def _cc_configure_extension_impl(ctx):
     cc_autoconf_toolchains(name = "local_config_cc_toolchains")
     cc_autoconf(name = "local_config_cc")
-    xcode_configure("@bazel_tools//tools/osx:xcode_locator.m")
+    return ctx.extension_metadata(reproducible = True)
 
-cc_configure = module_extension(implementation = _cc_configure_impl)
+cc_configure_extension = module_extension(implementation = _cc_configure_extension_impl)
diff --git a/cc/private/toolchain/BUILD.empty b/cc/private/toolchain/BUILD.empty.tpl
similarity index 92%
rename from cc/private/toolchain/BUILD.empty
rename to cc/private/toolchain/BUILD.empty.tpl
index a873d0c..6e2d202 100644
--- a/cc/private/toolchain/BUILD.empty
+++ b/cc/private/toolchain/BUILD.empty.tpl
@@ -13,10 +13,13 @@
 # limitations under the License.
 
 load("@rules_cc//cc:defs.bzl", "cc_library", "cc_toolchain", "cc_toolchain_suite")
+load(":cc_toolchain_config.bzl", "cc_toolchain_config")
 
 package(default_visibility = ["//visibility:public"])
 
-load(":cc_toolchain_config.bzl", "cc_toolchain_config")
+cc_library(
+    name = "link_extra_lib",
+)
 
 cc_library(
     name = "malloc",
@@ -30,8 +33,8 @@
 cc_toolchain_suite(
     name = "toolchain",
     toolchains = {
-        "local": ":local",
-        "local|local": ":local",
+        "%{cpu}|local": ":local",
+        "%{cpu}": ":local",
     },
 )
 
diff --git a/cc/private/toolchain/BUILD.static.freebsd b/cc/private/toolchain/BUILD.static.bsd
similarity index 63%
rename from cc/private/toolchain/BUILD.static.freebsd
rename to cc/private/toolchain/BUILD.static.bsd
index d8a7b2d..b0d52e6 100644
--- a/cc/private/toolchain/BUILD.static.freebsd
+++ b/cc/private/toolchain/BUILD.static.bsd
@@ -12,12 +12,30 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# This becomes the BUILD file for @local_config_cc// under FreeBSD.
+# This becomes the BUILD file for @local_config_cc// under FreeBSD and OpenBSD.
+
+load(":cc_toolchain_config.bzl", "cc_toolchain_config")
+load("@rules_cc//cc:defs.bzl", "cc_library", "cc_toolchain", "cc_toolchain_suite")
 
 package(default_visibility = ["//visibility:public"])
 
-load("@rules_cc//cc:defs.bzl", "cc_library", "cc_toolchain", "cc_toolchain_suite")
-load(":cc_toolchain_config.bzl", "cc_toolchain_config")
+cc_library(name = "empty_lib")
+
+# Label flag for extra libraries to be linked into every binary.
+# TODO(bazel-team): Support passing flag multiple times to build a list.
+label_flag(
+    name = "link_extra_libs",
+    build_setting_default = ":empty_lib",
+)
+
+# The final extra library to be linked into every binary target. This collects
+# the above flag, but may also include more libraries depending on config.
+cc_library(
+    name = "link_extra_lib",
+    deps = [
+        ":link_extra_libs",
+    ],
+)
 
 cc_library(
     name = "malloc",
@@ -32,10 +50,12 @@
 cc_toolchain_suite(
     name = "toolchain",
     toolchains = {
-        "armeabi-v7a": ":cc-compiler-armeabi-v7a",
         "armeabi-v7a|compiler": ":cc-compiler-armeabi-v7a",
-        "freebsd": ":cc-compiler-freebsd",
         "freebsd|compiler": ":cc-compiler-freebsd",
+        "openbsd|compiler": ":cc-compiler-openbsd",
+        "armeabi-v7a": ":cc-compiler-armeabi-v7a",
+        "freebsd": ":cc-compiler-freebsd",
+        "openbsd": ":cc-compiler-openbsd",
     },
 )
 
@@ -70,7 +90,41 @@
         "@platforms//os:freebsd",
     ],
     toolchain = ":cc-compiler-freebsd",
-    toolchain_type = "@rules_cc//cc:toolchain_type",
+    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
+)
+
+cc_toolchain(
+    name = "cc-compiler-openbsd",
+    all_files = ":empty",
+    ar_files = ":empty",
+    as_files = ":empty",
+    compiler_files = ":empty",
+    dwp_files = ":empty",
+    linker_files = ":empty",
+    objcopy_files = ":empty",
+    strip_files = ":empty",
+    supports_param_files = 0,
+    toolchain_config = ":local_openbsd",
+    toolchain_identifier = "local_openbsd",
+)
+
+cc_toolchain_config(
+    name = "local_openbsd",
+    cpu = "openbsd",
+)
+
+toolchain(
+    name = "cc-toolchain-openbsd",
+    exec_compatible_with = [
+        "@platforms//cpu:x86_64",
+        "@platforms//os:openbsd",
+    ],
+    target_compatible_with = [
+        "@platforms//cpu:x86_64",
+        "@platforms//os:openbsd",
+    ],
+    toolchain = ":cc-compiler-openbsd",
+    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
 )
 
 cc_toolchain(
@@ -99,11 +153,11 @@
         "@platforms//cpu:arm",
     ],
     target_compatible_with = [
-        "@platforms//cpu:arm",
+        "@platforms//cpu:armv7",
         "@platforms//os:android",
     ],
     toolchain = ":cc-compiler-armeabi-v7a",
-    toolchain_type = "@rules_cc//cc:toolchain_type",
+    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
 )
 
 filegroup(
diff --git a/cc/private/toolchain/BUILD.toolchains.tpl b/cc/private/toolchain/BUILD.toolchains.tpl
index 3fee112..7d3d6d6 100644
--- a/cc/private/toolchain/BUILD.toolchains.tpl
+++ b/cc/private/toolchain/BUILD.toolchains.tpl
@@ -5,16 +5,16 @@
     exec_compatible_with = HOST_CONSTRAINTS,
     target_compatible_with = HOST_CONSTRAINTS,
     toolchain = "@local_config_cc//:cc-compiler-%{name}",
-    toolchain_type = "@rules_cc//cc:toolchain_type",
+    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
 )
 
 toolchain(
     name = "cc-toolchain-armeabi-v7a",
     exec_compatible_with = HOST_CONSTRAINTS,
     target_compatible_with = [
-        "@platforms//cpu:arm",
+        "@platforms//cpu:armv7",
         "@platforms//os:android",
     ],
     toolchain = "@local_config_cc//:cc-compiler-armeabi-v7a",
-    toolchain_type = "@rules_cc//cc:toolchain_type",
+    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
 )
diff --git a/cc/private/toolchain/BUILD.tpl b/cc/private/toolchain/BUILD.tpl
index 9241326..99896dc 100644
--- a/cc/private/toolchain/BUILD.tpl
+++ b/cc/private/toolchain/BUILD.tpl
@@ -12,16 +12,34 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# This becomes the BUILD file for @local_config_cc// under non-FreeBSD unixes.
-
-package(default_visibility = ["//visibility:public"])
+# This becomes the BUILD file for @local_config_cc// under non-BSD unixes.
 
 load(":cc_toolchain_config.bzl", "cc_toolchain_config")
 load(":armeabi_cc_toolchain_config.bzl", "armeabi_cc_toolchain_config")
 load("@rules_cc//cc:defs.bzl", "cc_toolchain", "cc_toolchain_suite")
 
+package(default_visibility = ["//visibility:public"])
+
 licenses(["notice"])  # Apache 2.0
 
+cc_library(name = "empty_lib")
+
+# Label flag for extra libraries to be linked into every binary.
+# TODO(bazel-team): Support passing flag multiple times to build a list.
+label_flag(
+    name = "link_extra_libs",
+    build_setting_default = ":empty_lib",
+)
+
+# The final extra library to be linked into every binary target. This collects
+# the above flag, but may also include more libraries depending on config.
+cc_library(
+    name = "link_extra_lib",
+    deps = [
+        ":link_extra_libs",
+    ],
+)
+
 cc_library(
     name = "malloc",
 )
@@ -37,6 +55,15 @@
 )
 
 filegroup(
+    name = "validate_static_library",
+    srcs = ["validate_static_library.sh"],
+)
+
+filegroup(
+    name = "deps_scanner_wrapper",
+    srcs = ["deps_scanner_wrapper.sh"],
+)
+filegroup(
     name = "compiler_deps",
     srcs = glob(["extra_tools/**"], allow_empty = True) + [%{cc_compiler_deps}],
 )
@@ -66,7 +93,9 @@
     linker_files = ":compiler_deps",
     objcopy_files = ":empty",
     strip_files = ":empty",
-    supports_param_files = %{supports_param_files},
+    supports_header_parsing = 1,
+    supports_param_files = 1,
+    module_map = %{modulemap},
 )
 
 cc_toolchain_config(
@@ -84,6 +113,7 @@
     compile_flags = [%{compile_flags}],
     opt_compile_flags = [%{opt_compile_flags}],
     dbg_compile_flags = [%{dbg_compile_flags}],
+    conly_flags = [%{conly_flags}],
     cxx_flags = [%{cxx_flags}],
     link_flags = [%{link_flags}],
     link_libs = [%{link_libs}],
@@ -92,6 +122,7 @@
     coverage_compile_flags = [%{coverage_compile_flags}],
     coverage_link_flags = [%{coverage_link_flags}],
     supports_start_end_lib = %{supports_start_end_lib},
+    extra_flags_per_feature = %{extra_flags_per_feature},
 )
 
 # Android tooling requires a default toolchain for the armeabi-v7a cpu.
diff --git a/cc/private/toolchain/BUILD.windows.tpl b/cc/private/toolchain/BUILD.windows.tpl
index 66dbafd..d554869 100644
--- a/cc/private/toolchain/BUILD.windows.tpl
+++ b/cc/private/toolchain/BUILD.windows.tpl
@@ -14,11 +14,30 @@
 
 # This becomes the BUILD file for @local_config_cc// under Windows.
 
-package(default_visibility = ["//visibility:public"])
-
 load("@rules_cc//cc:defs.bzl", "cc_toolchain", "cc_toolchain_suite", "cc_library")
 load(":windows_cc_toolchain_config.bzl", "cc_toolchain_config")
 load(":armeabi_cc_toolchain_config.bzl", "armeabi_cc_toolchain_config")
+
+package(default_visibility = ["//visibility:public"])
+
+cc_library(name = "empty_lib")
+
+# Label flag for extra libraries to be linked into every binary.
+# TODO(bazel-team): Support passing flag multiple times to build a list.
+label_flag(
+    name = "link_extra_libs",
+    build_setting_default = ":empty_lib",
+)
+
+# The final extra library to be linked into every binary target. This collects
+# the above flag, but may also include more libraries depending on config.
+cc_library(
+    name = "link_extra_lib",
+    deps = [
+        ":link_extra_libs",
+    ],
+)
+
 cc_library(
     name = "malloc",
 )
@@ -40,7 +59,13 @@
 
 filegroup(
     name = "msvc_compiler_files",
-    srcs = [":builtin_include_directory_paths_msvc"]
+    srcs = [
+        ":builtin_include_directory_paths_msvc",
+        "%{msvc_deps_scanner_wrapper_path_x86}",
+        "%{msvc_deps_scanner_wrapper_path_x64}",
+        "%{msvc_deps_scanner_wrapper_path_arm}",
+        "%{msvc_deps_scanner_wrapper_path_arm64}",
+    ]
 )
 
 # Hardcoded toolchain, legacy behaviour.
@@ -49,11 +74,23 @@
     toolchains = {
         "armeabi-v7a|compiler": ":cc-compiler-armeabi-v7a",
         "x64_windows|msvc-cl": ":cc-compiler-x64_windows",
+        "x64_x86_windows|msvc-cl": ":cc-compiler-x64_x86_windows",
+        "x64_arm_windows|msvc-cl": ":cc-compiler-x64_arm_windows",
+        "x64_arm64_windows|msvc-cl": ":cc-compiler-arm64_windows",
+        "arm64_windows|msvc-cl": ":cc-compiler-arm64_windows",
         "x64_windows|msys-gcc": ":cc-compiler-x64_windows_msys",
+        "x64_x86_windows|msys-gcc": ":cc-compiler-x64_x86_windows_msys",
         "x64_windows|mingw-gcc": ":cc-compiler-x64_windows_mingw",
+        "x64_x86_windows|mingw-gcc": ":cc-compiler-x64_x86_windows_mingw",
         "x64_windows|clang-cl": ":cc-compiler-x64_windows-clang-cl",
         "x64_windows_msys": ":cc-compiler-x64_windows_msys",
         "x64_windows": ":cc-compiler-x64_windows",
+        "x64_x86_windows": ":cc-compiler-x64_x86_windows",
+        "x64_arm_windows": ":cc-compiler-x64_arm_windows",
+        "x64_arm64_windows": ":cc-compiler-arm64_windows",
+        "arm64_windows": ":cc-compiler-arm64_windows",
+        "x64_arm64_windows|clang-cl": ":cc-compiler-arm64_windows-clang-cl",
+        "arm64_windows|clang-cl": ":cc-compiler-arm64_windows-clang-cl",
         "armeabi-v7a": ":cc-compiler-armeabi-v7a",
     },
 )
@@ -85,8 +122,6 @@
     cxx_builtin_include_directories = [%{cxx_builtin_include_directories}],
     tool_paths = {%{tool_paths}},
     tool_bin_path = "%{tool_bin_path}",
-    dbg_mode_debug_flag = "%{dbg_mode_debug_flag}",
-    fastbuild_mode_debug_flag = "%{fastbuild_mode_debug_flag}",
 )
 
 toolchain(
@@ -101,7 +136,53 @@
         "@platforms//os:windows",
     ],
     toolchain = ":cc-compiler-x64_windows_msys",
-    toolchain_type = "@rules_cc//cc:toolchain_type",
+    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
+)
+
+cc_toolchain(
+    name = "cc-compiler-x64_x86_windows_msys",
+    toolchain_identifier = "msys_x64_x86",
+    toolchain_config = ":msys_x64_x86",
+    all_files = ":empty",
+    ar_files = ":empty",
+    as_files = ":mingw_compiler_files",
+    compiler_files = ":mingw_compiler_files",
+    dwp_files = ":empty",
+    linker_files = ":empty",
+    objcopy_files = ":empty",
+    strip_files = ":empty",
+    supports_param_files = 1,
+)
+
+cc_toolchain_config(
+    name = "msys_x64_x86",
+    cpu = "x64_x86_windows",
+    compiler = "msys-gcc",
+    host_system_name = "local",
+    target_system_name = "local",
+    target_libc = "msys",
+    abi_version = "local",
+    abi_libc_version = "local",
+    cxx_builtin_include_directories = [%{cxx_builtin_include_directories}],
+    tool_paths = {%{tool_paths}},
+    tool_bin_path = "%{tool_bin_path}",
+    default_compile_flags = ["-m32"],
+    default_link_flags = ["-m32"],
+)
+
+toolchain(
+    name = "cc-toolchain-x64_x86_windows_msys",
+    exec_compatible_with = [
+        "@platforms//cpu:x86_64",
+        "@platforms//os:windows",
+        "@rules_cc//cc/private/toolchain:msys",
+    ],
+    target_compatible_with = [
+        "@platforms//cpu:x86_32",
+        "@platforms//os:windows",
+    ],
+    toolchain = ":cc-compiler-x64_x86_windows_msys",
+    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
 )
 
 cc_toolchain(
@@ -131,8 +212,6 @@
     tool_bin_path = "%{mingw_tool_bin_path}",
     cxx_builtin_include_directories = [%{mingw_cxx_builtin_include_directories}],
     tool_paths = {%{mingw_tool_paths}},
-    dbg_mode_debug_flag = "%{dbg_mode_debug_flag}",
-    fastbuild_mode_debug_flag = "%{fastbuild_mode_debug_flag}",
 )
 
 toolchain(
@@ -147,7 +226,53 @@
         "@platforms//os:windows",
     ],
     toolchain = ":cc-compiler-x64_windows_mingw",
-    toolchain_type = "@rules_cc//cc:toolchain_type",
+    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
+)
+
+cc_toolchain(
+    name = "cc-compiler-x64_x86_windows_mingw",
+    toolchain_identifier = "msys_x64_x86_mingw",
+    toolchain_config = ":msys_x64_x86_mingw",
+    all_files = ":empty",
+    ar_files = ":empty",
+    as_files = ":mingw_compiler_files",
+    compiler_files = ":mingw_compiler_files",
+    dwp_files = ":empty",
+    linker_files = ":empty",
+    objcopy_files = ":empty",
+    strip_files = ":empty",
+    supports_param_files = 0,
+)
+
+cc_toolchain_config(
+    name = "msys_x64_x86_mingw",
+    cpu = "x64_x86_windows",
+    compiler = "mingw-gcc",
+    host_system_name = "local",
+    target_system_name = "local",
+    target_libc = "mingw",
+    abi_version = "local",
+    abi_libc_version = "local",
+    tool_bin_path = "%{mingw_tool_bin_path}",
+    cxx_builtin_include_directories = [%{mingw_cxx_builtin_include_directories}],
+    tool_paths = {%{mingw_tool_paths}},
+    default_compile_flags = ["-m32"],
+    default_link_flags = ["-m32"],
+)
+
+toolchain(
+    name = "cc-toolchain-x64_x86_windows_mingw",
+    exec_compatible_with = [
+        "@platforms//cpu:x86_64",
+        "@platforms//os:windows",
+        "@rules_cc//cc/private/toolchain:mingw",
+    ],
+    target_compatible_with = [
+        "@platforms//cpu:x86_32",
+        "@platforms//os:windows",
+    ],
+    toolchain = ":cc-compiler-x64_x86_windows_mingw",
+    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
 )
 
 cc_toolchain(
@@ -175,30 +300,34 @@
     abi_version = "local",
     abi_libc_version = "local",
     toolchain_identifier = "msvc_x64",
-    msvc_env_tmp = "%{msvc_env_tmp}",
-    msvc_env_path = "%{msvc_env_path}",
-    msvc_env_include = "%{msvc_env_include}",
-    msvc_env_lib = "%{msvc_env_lib}",
-    msvc_cl_path = "%{msvc_cl_path}",
-    msvc_ml_path = "%{msvc_ml_path}",
-    msvc_link_path = "%{msvc_link_path}",
-    msvc_lib_path = "%{msvc_lib_path}",
-    cxx_builtin_include_directories = [%{msvc_cxx_builtin_include_directories}],
+    msvc_env_tmp = "%{msvc_env_tmp_x64}",
+    msvc_env_path = "%{msvc_env_path_x64}",
+    msvc_env_include = "%{msvc_env_include_x64}",
+    msvc_env_lib = "%{msvc_env_lib_x64}",
+    msvc_cl_path = "%{msvc_cl_path_x64}",
+    msvc_ml_path = "%{msvc_ml_path_x64}",
+    msvc_link_path = "%{msvc_link_path_x64}",
+    msvc_lib_path = "%{msvc_lib_path_x64}",
+    cxx_builtin_include_directories = [%{msvc_cxx_builtin_include_directories_x64}],
     tool_paths = {
-        "ar": "%{msvc_lib_path}",
-        "ml": "%{msvc_ml_path}",
-        "cpp": "%{msvc_cl_path}",
-        "gcc": "%{msvc_cl_path}",
+        "ar": "%{msvc_lib_path_x64}",
+        "ml": "%{msvc_ml_path_x64}",
+        "cpp": "%{msvc_cl_path_x64}",
+        "gcc": "%{msvc_cl_path_x64}",
         "gcov": "wrapper/bin/msvc_nop.bat",
-        "ld": "%{msvc_link_path}",
+        "ld": "%{msvc_link_path_x64}",
         "nm": "wrapper/bin/msvc_nop.bat",
         "objcopy": "wrapper/bin/msvc_nop.bat",
         "objdump": "wrapper/bin/msvc_nop.bat",
         "strip": "wrapper/bin/msvc_nop.bat",
+        "dumpbin": "%{msvc_dumpbin_path_x64}",
+        "cpp-module-deps-scanner": "%{msvc_deps_scanner_wrapper_path_x64}",
     },
+    archiver_flags = ["/MACHINE:X64"],
     default_link_flags = ["/MACHINE:X64"],
-    dbg_mode_debug_flag = "%{dbg_mode_debug_flag}",
-    fastbuild_mode_debug_flag = "%{fastbuild_mode_debug_flag}",
+    dbg_mode_debug_flag = "%{dbg_mode_debug_flag_x64}",
+    fastbuild_mode_debug_flag = "%{fastbuild_mode_debug_flag_x64}",
+    supports_parse_showincludes = %{msvc_parse_showincludes_x64},
 )
 
 toolchain(
@@ -212,10 +341,217 @@
         "@platforms//os:windows",
     ],
     toolchain = ":cc-compiler-x64_windows",
-    toolchain_type = "@rules_cc//cc:toolchain_type",
+    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
 )
 
 cc_toolchain(
+    name = "cc-compiler-x64_x86_windows",
+    toolchain_identifier = "msvc_x64_x86",
+    toolchain_config = ":msvc_x64_x86",
+    all_files = ":empty",
+    ar_files = ":empty",
+    as_files = ":msvc_compiler_files",
+    compiler_files = ":msvc_compiler_files",
+    dwp_files = ":empty",
+    linker_files = ":empty",
+    objcopy_files = ":empty",
+    strip_files = ":empty",
+    supports_param_files = 1,
+)
+
+cc_toolchain_config(
+    name = "msvc_x64_x86",
+    cpu = "x64_windows",
+    compiler = "msvc-cl",
+    host_system_name = "local",
+    target_system_name = "local",
+    target_libc = "msvcrt",
+    abi_version = "local",
+    abi_libc_version = "local",
+    toolchain_identifier = "msvc_x64_x86",
+    msvc_env_tmp = "%{msvc_env_tmp_x86}",
+    msvc_env_path = "%{msvc_env_path_x86}",
+    msvc_env_include = "%{msvc_env_include_x86}",
+    msvc_env_lib = "%{msvc_env_lib_x86}",
+    msvc_cl_path = "%{msvc_cl_path_x86}",
+    msvc_ml_path = "%{msvc_ml_path_x86}",
+    msvc_link_path = "%{msvc_link_path_x86}",
+    msvc_lib_path = "%{msvc_lib_path_x86}",
+    cxx_builtin_include_directories = [%{msvc_cxx_builtin_include_directories_x86}],
+    tool_paths = {
+        "ar": "%{msvc_lib_path_x86}",
+        "ml": "%{msvc_ml_path_x86}",
+        "cpp": "%{msvc_cl_path_x86}",
+        "gcc": "%{msvc_cl_path_x86}",
+        "gcov": "wrapper/bin/msvc_nop.bat",
+        "ld": "%{msvc_link_path_x86}",
+        "nm": "wrapper/bin/msvc_nop.bat",
+        "objcopy": "wrapper/bin/msvc_nop.bat",
+        "objdump": "wrapper/bin/msvc_nop.bat",
+        "strip": "wrapper/bin/msvc_nop.bat",
+        "dumpbin": "%{msvc_dumpbin_path_x86}",
+        "cpp-module-deps-scanner": "%{msvc_deps_scanner_wrapper_path_x86}",
+    },
+    archiver_flags = ["/MACHINE:X86"],
+    default_link_flags = ["/MACHINE:X86"],
+    dbg_mode_debug_flag = "%{dbg_mode_debug_flag_x86}",
+    fastbuild_mode_debug_flag = "%{fastbuild_mode_debug_flag_x86}",
+    supports_parse_showincludes = %{msvc_parse_showincludes_x86},
+)
+
+toolchain(
+    name = "cc-toolchain-x64_x86_windows",
+    exec_compatible_with = [
+        "@platforms//cpu:x86_64",
+        "@platforms//os:windows",
+    ],
+    target_compatible_with = [
+        "@platforms//cpu:x86_32",
+        "@platforms//os:windows",
+    ],
+    toolchain = ":cc-compiler-x64_x86_windows",
+    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
+)
+
+cc_toolchain(
+    name = "cc-compiler-x64_arm_windows",
+    toolchain_identifier = "msvc_x64_arm",
+    toolchain_config = ":msvc_x64_arm",
+    all_files = ":empty",
+    ar_files = ":empty",
+    as_files = ":msvc_compiler_files",
+    compiler_files = ":msvc_compiler_files",
+    dwp_files = ":empty",
+    linker_files = ":empty",
+    objcopy_files = ":empty",
+    strip_files = ":empty",
+    supports_param_files = 1,
+)
+
+cc_toolchain_config(
+    name = "msvc_x64_arm",
+    cpu = "x64_windows",
+    compiler = "msvc-cl",
+    host_system_name = "local",
+    target_system_name = "local",
+    target_libc = "msvcrt",
+    abi_version = "local",
+    abi_libc_version = "local",
+    toolchain_identifier = "msvc_x64_arm",
+    msvc_env_tmp = "%{msvc_env_tmp_arm}",
+    msvc_env_path = "%{msvc_env_path_arm}",
+    msvc_env_include = "%{msvc_env_include_arm}",
+    msvc_env_lib = "%{msvc_env_lib_arm}",
+    msvc_cl_path = "%{msvc_cl_path_arm}",
+    msvc_ml_path = "%{msvc_ml_path_arm}",
+    msvc_link_path = "%{msvc_link_path_arm}",
+    msvc_lib_path = "%{msvc_lib_path_arm}",
+    cxx_builtin_include_directories = [%{msvc_cxx_builtin_include_directories_arm}],
+    tool_paths = {
+        "ar": "%{msvc_lib_path_arm}",
+        "ml": "%{msvc_ml_path_arm}",
+        "cpp": "%{msvc_cl_path_arm}",
+        "gcc": "%{msvc_cl_path_arm}",
+        "gcov": "wrapper/bin/msvc_nop.bat",
+        "ld": "%{msvc_link_path_arm}",
+        "nm": "wrapper/bin/msvc_nop.bat",
+        "objcopy": "wrapper/bin/msvc_nop.bat",
+        "objdump": "wrapper/bin/msvc_nop.bat",
+        "strip": "wrapper/bin/msvc_nop.bat",
+        "dumpbin": "%{msvc_dumpbin_path_arm}",
+        "cpp-module-deps-scanner": "%{msvc_deps_scanner_wrapper_path_arm}",
+    },
+    archiver_flags = ["/MACHINE:ARM"],
+    default_link_flags = ["/MACHINE:ARM"],
+    dbg_mode_debug_flag = "%{dbg_mode_debug_flag_arm}",
+    fastbuild_mode_debug_flag = "%{fastbuild_mode_debug_flag_arm}",
+    supports_parse_showincludes = %{msvc_parse_showincludes_arm},
+)
+
+toolchain(
+    name = "cc-toolchain-x64_arm_windows",
+    exec_compatible_with = [
+        "@platforms//cpu:x86_64",
+        "@platforms//os:windows",
+    ],
+    target_compatible_with = [
+        "@platforms//cpu:arm",
+        "@platforms//os:windows",
+    ],
+    toolchain = ":cc-compiler-x64_arm_windows",
+    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
+)
+
+cc_toolchain(
+    name = "cc-compiler-arm64_windows",
+    toolchain_identifier = "msvc_arm64",
+    toolchain_config = ":msvc_arm64",
+    all_files = ":empty",
+    ar_files = ":empty",
+    as_files = ":msvc_compiler_files",
+    compiler_files = ":msvc_compiler_files",
+    dwp_files = ":empty",
+    linker_files = ":empty",
+    objcopy_files = ":empty",
+    strip_files = ":empty",
+    supports_param_files = 1,
+)
+
+cc_toolchain_config(
+    name = "msvc_arm64",
+    cpu = "x64_windows",
+    compiler = "msvc-cl",
+    host_system_name = "local",
+    target_system_name = "local",
+    target_libc = "msvcrt",
+    abi_version = "local",
+    abi_libc_version = "local",
+    toolchain_identifier = "msvc_arm64",
+    msvc_env_tmp = "%{msvc_env_tmp_arm64}",
+    msvc_env_path = "%{msvc_env_path_arm64}",
+    msvc_env_include = "%{msvc_env_include_arm64}",
+    msvc_env_lib = "%{msvc_env_lib_arm64}",
+    msvc_cl_path = "%{msvc_cl_path_arm64}",
+    msvc_ml_path = "%{msvc_ml_path_arm64}",
+    msvc_link_path = "%{msvc_link_path_arm64}",
+    msvc_lib_path = "%{msvc_lib_path_arm64}",
+    cxx_builtin_include_directories = [%{msvc_cxx_builtin_include_directories_arm64}],
+    tool_paths = {
+        "ar": "%{msvc_lib_path_arm64}",
+        "ml": "%{msvc_ml_path_arm64}",
+        "cpp": "%{msvc_cl_path_arm64}",
+        "gcc": "%{msvc_cl_path_arm64}",
+        "gcov": "wrapper/bin/msvc_nop.bat",
+        "ld": "%{msvc_link_path_arm64}",
+        "nm": "wrapper/bin/msvc_nop.bat",
+        "objcopy": "wrapper/bin/msvc_nop.bat",
+        "objdump": "wrapper/bin/msvc_nop.bat",
+        "strip": "wrapper/bin/msvc_nop.bat",
+        "dumpbin": "%{msvc_dumpbin_path_arm64}",
+        "cpp-module-deps-scanner": "%{msvc_deps_scanner_wrapper_path_arm64}",
+    },
+    archiver_flags = ["/MACHINE:ARM64"],
+    default_link_flags = ["/MACHINE:ARM64"],
+    dbg_mode_debug_flag = "%{dbg_mode_debug_flag_arm64}",
+    fastbuild_mode_debug_flag = "%{fastbuild_mode_debug_flag_arm64}",
+    supports_parse_showincludes = %{msvc_parse_showincludes_arm64},
+)
+
+toolchain(
+    name = "cc-toolchain-arm64_windows",
+    exec_compatible_with = [
+        "@platforms//os:windows",
+    ],
+    target_compatible_with = [
+        "@platforms//cpu:arm64",
+        "@platforms//os:windows",
+    ],
+    toolchain = ":cc-compiler-arm64_windows",
+    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
+)
+
+
+cc_toolchain(
     name = "cc-compiler-x64_windows-clang-cl",
     toolchain_identifier = "clang_cl_x64",
     toolchain_config = ":clang_cl_x64",
@@ -240,30 +576,32 @@
     abi_version = "local",
     abi_libc_version = "local",
     toolchain_identifier = "clang_cl_x64",
-    msvc_env_tmp = "%{clang_cl_env_tmp}",
-    msvc_env_path = "%{clang_cl_env_path}",
-    msvc_env_include = "%{clang_cl_env_include}",
-    msvc_env_lib = "%{clang_cl_env_lib}",
-    msvc_cl_path = "%{clang_cl_cl_path}",
-    msvc_ml_path = "%{clang_cl_ml_path}",
-    msvc_link_path = "%{clang_cl_link_path}",
-    msvc_lib_path = "%{clang_cl_lib_path}",
-    cxx_builtin_include_directories = [%{clang_cl_cxx_builtin_include_directories}],
+    msvc_env_tmp = "%{clang_cl_env_tmp_x64}",
+    msvc_env_path = "%{clang_cl_env_path_x64}",
+    msvc_env_include = "%{clang_cl_env_include_x64}",
+    msvc_env_lib = "%{clang_cl_env_lib_x64}",
+    msvc_cl_path = "%{clang_cl_cl_path_x64}",
+    msvc_ml_path = "%{clang_cl_ml_path_x64}",
+    msvc_link_path = "%{clang_cl_link_path_x64}",
+    msvc_lib_path = "%{clang_cl_lib_path_x64}",
+    cxx_builtin_include_directories = [%{clang_cl_cxx_builtin_include_directories_x64}],
     tool_paths = {
-        "ar": "%{clang_cl_lib_path}",
-        "ml": "%{clang_cl_ml_path}",
-        "cpp": "%{clang_cl_cl_path}",
-        "gcc": "%{clang_cl_cl_path}",
+        "ar": "%{clang_cl_lib_path_x64}",
+        "ml": "%{clang_cl_ml_path_x64}",
+        "cpp": "%{clang_cl_cl_path_x64}",
+        "gcc": "%{clang_cl_cl_path_x64}",
         "gcov": "wrapper/bin/msvc_nop.bat",
-        "ld": "%{clang_cl_link_path}",
+        "ld": "%{clang_cl_link_path_x64}",
         "nm": "wrapper/bin/msvc_nop.bat",
         "objcopy": "wrapper/bin/msvc_nop.bat",
         "objdump": "wrapper/bin/msvc_nop.bat",
         "strip": "wrapper/bin/msvc_nop.bat",
     },
-    default_link_flags = ["/MACHINE:X64", "/DEFAULTLIB:clang_rt.builtins-x86_64.lib"],
-    dbg_mode_debug_flag = "%{clang_cl_dbg_mode_debug_flag}",
-    fastbuild_mode_debug_flag = "%{clang_cl_fastbuild_mode_debug_flag}",
+    archiver_flags = ["/MACHINE:X64"],
+    default_link_flags = ["/MACHINE:X64"],
+    dbg_mode_debug_flag = "%{clang_cl_dbg_mode_debug_flag_x64}",
+    fastbuild_mode_debug_flag = "%{clang_cl_fastbuild_mode_debug_flag_x64}",
+    supports_parse_showincludes = %{clang_cl_parse_showincludes_x64},
 )
 
 toolchain(
@@ -278,7 +616,74 @@
         "@platforms//os:windows",
     ],
     toolchain = ":cc-compiler-x64_windows-clang-cl",
-    toolchain_type = "@rules_cc//cc:toolchain_type",
+    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
+)
+
+cc_toolchain(
+    name = "cc-compiler-arm64_windows-clang-cl",
+    toolchain_identifier = "clang_cl_arm64",
+    toolchain_config = ":clang_cl_arm64",
+    all_files = ":empty",
+    ar_files = ":empty",
+    as_files = ":clangcl_compiler_files",
+    compiler_files = ":clangcl_compiler_files",
+    dwp_files = ":empty",
+    linker_files = ":empty",
+    objcopy_files = ":empty",
+    strip_files = ":empty",
+    supports_param_files = 1,
+)
+
+cc_toolchain_config(
+    name = "clang_cl_arm64",
+    cpu = "arm64_windows",
+    compiler = "clang-cl",
+    host_system_name = "local",
+    target_system_name = "aarch64-pc-windows-msvc",
+    target_libc = "msvcrt",
+    abi_version = "local",
+    abi_libc_version = "local",
+    toolchain_identifier = "clang_cl_arm64",
+    msvc_env_tmp = "%{clang_cl_env_tmp_arm64}",
+    msvc_env_path = "%{clang_cl_env_path_arm64}",
+    msvc_env_include = "%{clang_cl_env_include_arm64}",
+    msvc_env_lib = "%{clang_cl_env_lib_arm64}",
+    msvc_cl_path = "%{clang_cl_cl_path_arm64}",
+    msvc_ml_path = "%{clang_cl_ml_path_arm64}",
+    msvc_link_path = "%{clang_cl_link_path_arm64}",
+    msvc_lib_path = "%{clang_cl_lib_path_arm64}",
+    cxx_builtin_include_directories = [%{clang_cl_cxx_builtin_include_directories_arm64}],
+    tool_paths = {
+        "ar": "%{clang_cl_lib_path_arm64}",
+        "ml": "%{clang_cl_ml_path_arm64}",
+        "cpp": "%{clang_cl_cl_path_arm64}",
+        "gcc": "%{clang_cl_cl_path_arm64}",
+        "gcov": "wrapper/bin/msvc_nop.bat",
+        "ld": "%{clang_cl_link_path_arm64}",
+        "nm": "wrapper/bin/msvc_nop.bat",
+        "objcopy": "wrapper/bin/msvc_nop.bat",
+        "objdump": "wrapper/bin/msvc_nop.bat",
+        "strip": "wrapper/bin/msvc_nop.bat",
+    },
+    archiver_flags = ["/MACHINE:ARM64"],
+    default_link_flags = ["/MACHINE:ARM64"],
+    dbg_mode_debug_flag = "%{clang_cl_dbg_mode_debug_flag_arm64}",
+    fastbuild_mode_debug_flag = "%{clang_cl_fastbuild_mode_debug_flag_arm64}",
+    supports_parse_showincludes = %{clang_cl_parse_showincludes_arm64},
+)
+
+toolchain(
+    name = "cc-toolchain-arm64_windows-clang-cl",
+    exec_compatible_with = [
+        "@platforms//os:windows",
+        "@rules_cc//cc/private/toolchain:clang-cl",
+    ],
+    target_compatible_with = [
+        "@platforms//cpu:arm64",
+        "@platforms//os:windows",
+    ],
+    toolchain = ":cc-compiler-arm64_windows-clang-cl",
+    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
 )
 
 cc_toolchain(
@@ -303,14 +708,9 @@
     exec_compatible_with = [
     ],
     target_compatible_with = [
-        "@platforms//cpu:arm",
+        "@platforms//cpu:armv7",
         "@platforms//os:android",
     ],
     toolchain = ":cc-compiler-armeabi-v7a",
-    toolchain_type = "@rules_cc//cc:toolchain_type",
-)
-
-filegroup(
-    name = "link_dynamic_library",
-    srcs = ["link_dynamic_library.sh"],
+    toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
 )
diff --git a/cc/private/toolchain/armeabi_cc_toolchain_config.bzl b/cc/private/toolchain/armeabi_cc_toolchain_config.bzl
index 66c5752..7d4baad 100644
--- a/cc/private/toolchain/armeabi_cc_toolchain_config.bzl
+++ b/cc/private/toolchain/armeabi_cc_toolchain_config.bzl
@@ -49,6 +49,7 @@
         tool_path(name = "gcc", path = "/bin/false"),
         tool_path(name = "gcov", path = "/bin/false"),
         tool_path(name = "ld", path = "/bin/false"),
+        tool_path(name = "llvm-profdata", path = "/bin/false"),
         tool_path(name = "nm", path = "/bin/false"),
         tool_path(name = "objcopy", path = "/bin/false"),
         tool_path(name = "objdump", path = "/bin/false"),
diff --git a/cc/private/toolchain/freebsd_cc_toolchain_config.bzl b/cc/private/toolchain/bsd_cc_toolchain_config.bzl
similarity index 93%
rename from cc/private/toolchain/freebsd_cc_toolchain_config.bzl
rename to cc/private/toolchain/bsd_cc_toolchain_config.bzl
index 3521d92..3ad8d1f 100644
--- a/cc/private/toolchain/freebsd_cc_toolchain_config.bzl
+++ b/cc/private/toolchain/bsd_cc_toolchain_config.bzl
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""A Starlark cc_toolchain configuration rule for freebsd."""
+"""A Starlark cc_toolchain configuration rule for FreeBSD and OpenBSD."""
 
 load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES")
 load(
@@ -24,7 +24,7 @@
     "tool",
     "tool_path",
     "with_feature_set",
-)
+)  # buildifier: disable=deprecated-function
 
 all_compile_actions = [
     ACTION_NAMES.c_compile,
@@ -56,13 +56,14 @@
 
 def _impl(ctx):
     cpu = ctx.attr.cpu
+    is_bsd = cpu == "freebsd" or cpu == "openbsd"
     compiler = "compiler"
-    toolchain_identifier = "local_freebsd" if cpu == "freebsd" else "stub_armeabi-v7a"
-    host_system_name = "local" if cpu == "freebsd" else "armeabi-v7a"
-    target_system_name = "local" if cpu == "freebsd" else "armeabi-v7a"
-    target_libc = "local" if cpu == "freebsd" else "armeabi-v7a"
-    abi_version = "local" if cpu == "freebsd" else "armeabi-v7a"
-    abi_libc_version = "local" if cpu == "freebsd" else "armeabi-v7a"
+    toolchain_identifier = "local_{}".format(cpu) if is_bsd else "stub_armeabi-v7a"
+    host_system_name = "local" if is_bsd else "armeabi-v7a"
+    target_system_name = "local" if is_bsd else "armeabi-v7a"
+    target_libc = "local" if is_bsd else "armeabi-v7a"
+    abi_version = "local" if is_bsd else "armeabi-v7a"
+    abi_libc_version = "local" if is_bsd else "armeabi-v7a"
 
     objcopy_embed_data_action = action_config(
         action_name = "objcopy_embed_data",
@@ -70,7 +71,7 @@
         tools = [tool(path = "/usr/bin/objcopy")],
     )
 
-    action_configs = [objcopy_embed_data_action] if cpu == "freebsd" else []
+    action_configs = [objcopy_embed_data_action] if is_bsd else []
 
     default_link_flags_feature = feature(
         name = "default_link_flags",
@@ -159,7 +160,7 @@
             ),
             flag_set(
                 actions = all_cpp_compile_actions + [ACTION_NAMES.lto_backend],
-                flag_groups = [flag_group(flags = ["-std=c++0x"])],
+                flag_groups = [flag_group(flags = ["-std=c++17"])],
             ),
         ],
     )
@@ -224,7 +225,7 @@
         ],
     )
 
-    if cpu == "freebsd":
+    if is_bsd:
         features = [
             default_compile_flags_feature,
             default_link_flags_feature,
@@ -240,12 +241,12 @@
     else:
         features = [supports_dynamic_linker_feature, supports_pic_feature]
 
-    if (cpu == "freebsd"):
+    if (is_bsd):
         cxx_builtin_include_directories = ["/usr/lib/clang", "/usr/local/include", "/usr/include"]
     else:
         cxx_builtin_include_directories = []
 
-    if cpu == "freebsd":
+    if is_bsd:
         tool_paths = [
             tool_path(name = "ar", path = "/usr/bin/ar"),
             tool_path(name = "compat-ld", path = "/usr/bin/ld"),
diff --git a/cc/private/toolchain/cc_configure.bzl b/cc/private/toolchain/cc_configure.bzl
index c7b19de..ce0dac5 100644
--- a/cc/private/toolchain/cc_configure.bzl
+++ b/cc/private/toolchain/cc_configure.bzl
@@ -46,7 +46,6 @@
 
 cc_autoconf_toolchains = repository_rule(
     environ = [
-        "BAZEL_USE_CPP_ONLY_TOOLCHAIN",
         "BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN",
     ],
     implementation = cc_autoconf_toolchains_impl,
@@ -65,24 +64,26 @@
     cpu_value = get_cpu_value(repository_ctx)
     if "BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN" in env and env["BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN"] == "1":
         paths = resolve_labels(repository_ctx, [
-            "@rules_cc//cc/private/toolchain:BUILD.empty",
+            "@rules_cc//cc/private/toolchain:BUILD.empty.tpl",
             "@rules_cc//cc/private/toolchain:empty_cc_toolchain_config.bzl",
         ])
         repository_ctx.symlink(paths["@rules_cc//cc/private/toolchain:empty_cc_toolchain_config.bzl"], "cc_toolchain_config.bzl")
-        repository_ctx.symlink(paths["@rules_cc//cc/private/toolchain:BUILD.empty"], "BUILD")
-    elif cpu_value == "freebsd":
+        repository_ctx.template("BUILD", paths["@rules_cc//cc/private/toolchain:BUILD.empty.tpl"], {
+            "%{cpu}": get_cpu_value(repository_ctx),
+        })
+    elif cpu_value == "freebsd" or cpu_value == "openbsd":
         paths = resolve_labels(repository_ctx, [
-            "@rules_cc//cc/private/toolchain:BUILD.static.freebsd",
-            "@rules_cc//cc/private/toolchain:freebsd_cc_toolchain_config.bzl",
+            "@rules_cc//cc/private/toolchain:BUILD.static.bsd",
+            "@rules_cc//cc/private/toolchain:bsd_cc_toolchain_config.bzl",
         ])
 
-        # This is defaulting to a static crosstool, we should eventually
-        # autoconfigure this platform too.  Theorically, FreeBSD should be
-        # straightforward to add but we cannot run it in a docker container so
-        # skipping until we have proper tests for FreeBSD.
-        repository_ctx.symlink(paths["@rules_cc//cc/private/toolchain:freebsd_cc_toolchain_config.bzl"], "cc_toolchain_config.bzl")
-        repository_ctx.symlink(paths["@rules_cc//cc/private/toolchain:BUILD.static.freebsd"], "BUILD")
-    elif cpu_value == "x64_windows":
+        # This is defaulting to a static crosstool. We should eventually
+        # autoconfigure this platform too. Theoretically, FreeBSD and OpenBSD
+        # should be straightforward to add but we cannot run them in a Docker
+        # container so skipping until we have proper tests for these platforms.
+        repository_ctx.symlink(paths["@rules_cc//cc/private/toolchain:bsd_cc_toolchain_config.bzl"], "cc_toolchain_config.bzl")
+        repository_ctx.symlink(paths["@rules_cc//cc/private/toolchain:BUILD.static.bsd"], "BUILD")
+    elif cpu_value in ["x64_windows", "arm64_windows"]:
         # TODO(ibiryukov): overriden_tools are only supported in configure_unix_toolchain.
         # We might want to add that to Windows too(at least for msys toolchain).
         configure_windows_toolchain(repository_ctx)
@@ -111,16 +112,17 @@
         "ABI_VERSION",
         "BAZEL_COMPILER",
         "BAZEL_HOST_SYSTEM",
+        "BAZEL_CONLYOPTS",
         "BAZEL_CXXOPTS",
         "BAZEL_LINKOPTS",
         "BAZEL_LINKLIBS",
+        "BAZEL_LLVM_COV",
+        "BAZEL_LLVM_PROFDATA",
         "BAZEL_PYTHON",
         "BAZEL_SH",
         "BAZEL_TARGET_CPU",
         "BAZEL_TARGET_LIBC",
         "BAZEL_TARGET_SYSTEM",
-        "BAZEL_USE_CPP_ONLY_TOOLCHAIN",
-        "BAZEL_USE_XCODE_TOOLCHAIN",
         "BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN",
         "BAZEL_USE_LLVM_NATIVE_COVERAGE",
         "BAZEL_LLVM",
@@ -130,9 +132,12 @@
         "CC_CONFIGURE_DEBUG",
         "CC_TOOLCHAIN_NAME",
         "CPLUS_INCLUDE_PATH",
+        "DEVELOPER_DIR",
         "GCOV",
+        "LIBTOOL",
         "HOMEBREW_RUBY_PATH",
         "SYSTEMROOT",
+        "USER",
     ] + MSVC_ENVVARS,
     implementation = cc_autoconf_impl,
     configure = True,
diff --git a/cc/private/toolchain/clang_deps_scanner_wrapper.sh.tpl b/cc/private/toolchain/clang_deps_scanner_wrapper.sh.tpl
new file mode 100644
index 0000000..0bff014
--- /dev/null
+++ b/cc/private/toolchain/clang_deps_scanner_wrapper.sh.tpl
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+#
+# Ship the environment to the C++ action
+#
+set -eu
+
+# Set-up the environment
+%{env}
+
+# Call the C++ compiler
+%{deps_scanner} -format=p1689 -- %{cc} "$@" >"$DEPS_SCANNER_OUTPUT_FILE"
diff --git a/cc/private/toolchain/clang_installation_error.bat.tpl b/cc/private/toolchain/clang_installation_error.bat.tpl
index e3a61a4..13668ae 100644
--- a/cc/private/toolchain/clang_installation_error.bat.tpl
+++ b/cc/private/toolchain/clang_installation_error.bat.tpl
@@ -18,7 +18,7 @@
 echo The target you are compiling requires the Clang compiler. 1>&2
 echo Bazel couldn't find a valid Clang installation on your machine. 1>&2
 %{clang_error_message}
-echo Please check your installation following https://docs.bazel.build/versions/main/windows.html#using 1>&2
+echo Please check your installation following https://bazel.build/docs/windows#using 1>&2
 echo. 1>&2
 
 exit /b 1
diff --git a/cc/private/toolchain/gcc_deps_scanner_wrapper.sh.tpl b/cc/private/toolchain/gcc_deps_scanner_wrapper.sh.tpl
new file mode 100644
index 0000000..9436493
--- /dev/null
+++ b/cc/private/toolchain/gcc_deps_scanner_wrapper.sh.tpl
@@ -0,0 +1,12 @@
+#!/bin/bash
+#
+# Ship the environment to the C++ action
+#
+set -eu
+
+# Set-up the environment
+%{env}
+
+# Call the C++ compiler
+
+%{cc} -E -x c++ -fmodules-ts -fdeps-file=out.tmp -fdeps-format=p1689r5 "$@" >"$DEPS_SCANNER_OUTPUT_FILE"
diff --git a/cc/private/toolchain/generate_system_module_map.sh b/cc/private/toolchain/generate_system_module_map.sh
new file mode 100755
index 0000000..deb52c2
--- /dev/null
+++ b/cc/private/toolchain/generate_system_module_map.sh
@@ -0,0 +1,35 @@
+#!/bin/bash
+# Copyright 2020 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+set -eu
+
+echo 'module "crosstool" [system] {'
+
+if [[ "$OSTYPE" == darwin* ]]; then
+  for dir in $@; do
+    find "$dir" -type f \( -name "*.h" -o -name "*.def" -o -path "*/c++/*" \) \
+      | LANG=C sort -u | while read -r header; do
+        echo "  textual header \"${header}\""
+      done
+  done
+else
+  for dir in $@; do
+    find -L "${dir}" -type f 2>/dev/null | LANG=C sort -u | while read -r header; do
+      echo "  textual header \"${header}\""
+    done
+  done
+fi
+
+echo "}"
diff --git a/cc/private/toolchain/lib_cc_configure.bzl b/cc/private/toolchain/lib_cc_configure.bzl
index bcd9013..975dd44 100644
--- a/cc/private/toolchain/lib_cc_configure.bzl
+++ b/cc/private/toolchain/lib_cc_configure.bzl
@@ -51,7 +51,7 @@
       Basic usage:
         split_escaped("a:b:c", ":") -> [ "a", "b", "c" ]
 
-      Delimeter that is not supposed to be splitten on has to be %-escaped:
+      Delimiter that is not supposed to be splitten on has to be %-escaped:
         split_escaped("a%:b", ":") -> [ "a:b" ]
 
       Literal % can be represented by escaping it as %%:
@@ -137,7 +137,8 @@
         if enable_warning:
             auto_configure_warning("'%s' environment variable is not set, using '%s' as default" % (name, default))
         return default
-    return auto_configure_fail("'%s' environment variable is not set" % name)
+    auto_configure_fail("'%s' environment variable is not set" % name)
+    return None
 
 def which(repository_ctx, cmd, default = None):
     """A wrapper around repository_ctx.which() to provide a fallback value. Doesn't %-escape the value!
@@ -176,7 +177,8 @@
         repository_ctx,
         command,
         environment = None,
-        expect_failure = False):
+        expect_failure = False,
+        expect_empty_output = False):
     """Execute a command, return stdout if succeed and throw an error if it fails. Doesn't %-escape the result!
 
     Args:
@@ -184,6 +186,7 @@
       command: command to execute.
       environment: dictionary with environment variables to set for the command.
       expect_failure: True if the command is expected to fail.
+      expect_empty_output: True if the command is expected to produce no output.
     Returns:
       stdout of the executed command.
     """
@@ -208,10 +211,15 @@
                 ),
             )
     stripped_stdout = result.stdout.strip()
-    if not stripped_stdout:
-        auto_configure_fail(
-            "empty output from command %s, stderr: (%s)" % (command, result.stderr),
-        )
+    if expect_empty_output != (not stripped_stdout):
+        if expect_empty_output:
+            auto_configure_fail(
+                "non-empty output from command %s, stdout: (%s), stderr: (%s)" % (command, result.stdout, result.stderr),
+            )
+        else:
+            auto_configure_fail(
+                "empty output from command %s, stderr: (%s)" % (command, result.stderr),
+            )
     return stripped_stdout
 
 def get_cpu_value(repository_ctx):
@@ -222,25 +230,34 @@
     Returns:
       One of (darwin, freebsd, x64_windows, ppc, s390x, arm, aarch64, k8, piii)
     """
-    os_name = repository_ctx.os.name.lower()
+    os_name = repository_ctx.os.name
+    arch = repository_ctx.os.arch
     if os_name.startswith("mac os"):
-        return "darwin"
+        # Check if we are on x86_64 or arm64 and return the corresponding cpu value.
+        return "darwin_" + ("arm64" if arch == "aarch64" else "x86_64")
     if os_name.find("freebsd") != -1:
         return "freebsd"
+    if os_name.find("openbsd") != -1:
+        return "openbsd"
     if os_name.find("windows") != -1:
-        return "x64_windows"
+        if arch == "aarch64":
+            return "arm64_windows"
+        else:
+            return "x64_windows"
 
-    # Use uname to figure out whether we are on x86_32 or x86_64
-    result = repository_ctx.execute(["uname", "-m"])
-    if result.stdout.strip() in ["power", "ppc64le", "ppc", "ppc64"]:
+    if arch in ["power", "ppc64le", "ppc", "ppc64"]:
         return "ppc"
-    if result.stdout.strip() in ["s390x"]:
+    if arch in ["s390x"]:
         return "s390x"
-    if result.stdout.strip() in ["arm", "armv7l"]:
+    if arch in ["mips64"]:
+        return "mips64"
+    if arch in ["riscv64"]:
+        return "riscv64"
+    if arch in ["arm", "armv7l"]:
         return "arm"
-    if result.stdout.strip() in ["aarch64"]:
+    if arch in ["aarch64"]:
         return "aarch64"
-    return "k8" if result.stdout.strip() in ["amd64", "x86_64", "x64"] else "piii"
+    return "k8" if arch in ["amd64", "x86_64", "x64"] else "piii"
 
 def is_cc_configure_debug(repository_ctx):
     """Returns True if CC_CONFIGURE_DEBUG is set to 1."""
diff --git a/cc/private/toolchain/linux_cc_wrapper.sh.tpl b/cc/private/toolchain/linux_cc_wrapper.sh.tpl
index a83be50..629741e 100644
--- a/cc/private/toolchain/linux_cc_wrapper.sh.tpl
+++ b/cc/private/toolchain/linux_cc_wrapper.sh.tpl
@@ -18,8 +18,37 @@
 #
 set -eu
 
+OUTPUT=
+
+function parse_option() {
+    local -r opt="$1"
+    if [[ "${OUTPUT}" = "1" ]]; then
+        OUTPUT=$opt
+    elif [[ "$opt" = "-o" ]]; then
+        # output is coming
+        OUTPUT=1
+    fi
+}
+
+# let parse the option list
+for i in "$@"; do
+    if [[ "$i" = @* && -r "${i:1}" ]]; then
+        while IFS= read -r opt
+        do
+            parse_option "$opt"
+        done < "${i:1}" || exit 1
+    else
+        parse_option "$i"
+    fi
+done
+
 # Set-up the environment
 %{env}
 
 # Call the C++ compiler
 %{cc} "$@"
+
+# Generate an empty file if header processing succeeded.
+if [[ "${OUTPUT}" == *.h.processed ]]; then
+  echo -n > "${OUTPUT}"
+fi
diff --git a/cc/private/toolchain/msvc_deps_scanner_wrapper.bat.tpl b/cc/private/toolchain/msvc_deps_scanner_wrapper.bat.tpl
new file mode 100644
index 0000000..2c6200f
--- /dev/null
+++ b/cc/private/toolchain/msvc_deps_scanner_wrapper.bat.tpl
@@ -0,0 +1,16 @@
+:: Copyright 2024 The Bazel Authors. All rights reserved.
+::
+:: Licensed under the Apache License, Version 2.0 (the "License");
+:: you may not use this file except in compliance with the License.
+:: You may obtain a copy of the License at
+::
+::    http://www.apache.org/licenses/LICENSE-2.0
+::
+:: Unless required by applicable law or agreed to in writing, software
+:: distributed under the License is distributed on an "AS IS" BASIS,
+:: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+:: See the License for the specific language governing permissions and
+:: limitations under the License.
+
+@echo OFF
+"%{cc}" /scanDependencies- /TP %* >%DEPS_SCANNER_OUTPUT_FILE%
diff --git a/cc/private/toolchain/osx_cc_wrapper.sh.tpl b/cc/private/toolchain/osx_cc_wrapper.sh.tpl
index 28bd47b..e40a98b 100644
--- a/cc/private/toolchain/osx_cc_wrapper.sh.tpl
+++ b/cc/private/toolchain/osx_cc_wrapper.sh.tpl
@@ -27,9 +27,8 @@
 #
 set -eu
 
-INSTALL_NAME_TOOL="/usr/bin/install_name_tool"
-
 LIBS=
+LIB_PATHS=
 LIB_DIRS=
 RPATHS=
 OUTPUT=
@@ -40,9 +39,13 @@
         OUTPUT=$opt
     elif [[ "$opt" =~ ^-l(.*)$ ]]; then
         LIBS="${BASH_REMATCH[1]} $LIBS"
+    elif [[ "$opt" =~ ^(.*)\.so$ ]]; then
+        LIB_PATHS="${opt} $LIB_PATHS"
+    elif [[ "$opt" =~ ^(.*)\.dylib$ ]]; then
+        LIB_PATHS="${opt} $LIB_PATHS"
     elif [[ "$opt" =~ ^-L(.*)$ ]]; then
         LIB_DIRS="${BASH_REMATCH[1]} $LIB_DIRS"
-    elif [[ "$opt" =~ ^-Wl,-rpath,\@loader_path/(.*)$ ]]; then
+    elif [[ "$opt" =~ ^\@loader_path/(.*)$ ]]; then
         RPATHS="${BASH_REMATCH[1]} ${RPATHS}"
     elif [[ "$opt" = "-o" ]]; then
         # output is coming
@@ -52,7 +55,7 @@
 
 # let parse the option list
 for i in "$@"; do
-    if [[ "$i" = @* ]]; then
+    if [[ "$i" = @* && -r "${i:1}" ]]; then
         while IFS= read -r opt
         do
             parse_option "$opt"
@@ -68,6 +71,11 @@
 # Call the C++ compiler
 %{cc} "$@"
 
+# Generate an empty file if header processing succeeded.
+if [[ "${OUTPUT}" == *.h.processed ]]; then
+  echo -n > "${OUTPUT}"
+fi
+
 function get_library_path() {
     for libdir in ${LIB_DIRS}; do
         if [ -f ${libdir}/lib$1.so ]; then
@@ -96,6 +104,11 @@
     get_realpath $1 | sed 's|^.*/bazel-out/|bazel-out/|'
 }
 
+function call_install_name() {
+    /usr/bin/xcrun install_name_tool -change $(get_otool_path "$1") \
+        "@loader_path/$2/$3" "${OUTPUT}"
+}
+
 # Do replacements in the output
 for rpath in ${RPATHS}; do
     for lib in ${LIBS}; do
@@ -110,10 +123,16 @@
         if [[ -n "${libname-}" ]]; then
             libpath=$(get_library_path ${lib})
             if [ -n "${libpath}" ]; then
-                ${INSTALL_NAME_TOOL} -change $(get_otool_path "${libpath}") \
-                    "@loader_path/${rpath}/${libname}" "${OUTPUT}"
+                call_install_name "${libpath}" "${rpath}" "${libname}"
+            fi
+        fi
+    done
+    for libpath in ${LIB_PATHS}; do
+        if [ -f "$libpath" ]; then
+            libname=$(basename "$libpath")
+            if [ -f "$(dirname ${OUTPUT})/${rpath}/${libname}" ]; then
+                call_install_name "${libpath}" "${rpath}" "${libname}"
             fi
         fi
     done
 done
-
diff --git a/cc/private/toolchain/unix_cc_configure.bzl b/cc/private/toolchain/unix_cc_configure.bzl
index 0c936de..0629a50 100644
--- a/cc/private/toolchain/unix_cc_configure.bzl
+++ b/cc/private/toolchain/unix_cc_configure.bzl
@@ -20,6 +20,7 @@
     "auto_configure_warning",
     "auto_configure_warning_maybe",
     "escape_string",
+    "execute",
     "get_env_var",
     "get_starlark_list",
     "resolve_labels",
@@ -34,16 +35,19 @@
     unique_elements = {element: None for element in iterable}
     return unique_elements.keys()
 
+def _generate_system_module_map(repository_ctx, dirs, script_path):
+    return execute(repository_ctx, [script_path] + dirs)
+
 def _prepare_include_path(repo_ctx, path):
-    """Resolve and sanitize include path before outputting it into the crosstool.
+    """Resolve include path before outputting it into the crosstool.
 
     Args:
       repo_ctx: repository_ctx object.
-      path: an include path to be sanitized.
+      path: an include path to be resolved.
 
     Returns:
-      Sanitized include path that can be written to the crosstoot. Resulting path
-      is absolute if it is outside the repository and relative otherwise.
+      Resolved include path. Resulting path is absolute if it is outside the
+      repository and relative otherwise.
     """
 
     repo_root = str(repo_ctx.path("."))
@@ -52,22 +56,24 @@
     repo_root += "/"
     path = str(repo_ctx.path(path))
     if path.startswith(repo_root):
-        return escape_string(path[len(repo_root):])
-    return escape_string(path)
+        return path[len(repo_root):]
+    return path
 
-def _find_tool(repository_ctx, tool, overriden_tools):
-    """Find a tool for repository, taking overriden tools into account."""
-    if tool in overriden_tools:
-        return overriden_tools[tool]
+def _find_tool(repository_ctx, tool, overridden_tools):
+    """Find a tool for repository, taking overridden tools into account."""
+    if tool in overridden_tools:
+        return overridden_tools[tool]
     return which(repository_ctx, tool, "/usr/bin/" + tool)
 
-def _get_tool_paths(repository_ctx, overriden_tools):
+def _get_tool_paths(repository_ctx, overridden_tools):
     """Compute the %-escaped path to the various tools"""
     return dict({
-        k: escape_string(_find_tool(repository_ctx, k, overriden_tools))
+        k: escape_string(_find_tool(repository_ctx, k, overridden_tools))
         for k in [
             "ar",
             "ld",
+            "llvm-cov",
+            "llvm-profdata",
             "cpp",
             "gcc",
             "dwp",
@@ -76,6 +82,7 @@
             "objcopy",
             "objdump",
             "strip",
+            "c++filt",
         ]
     }.items())
 
@@ -103,17 +110,8 @@
         path = path[:-_OSX_FRAMEWORK_SUFFIX_LEN].strip()
     return path
 
-def get_escaped_cxx_inc_directories(repository_ctx, cc, lang_flag, additional_flags = []):
-    """Compute the list of default %-escaped C++ include directories.
-
-    Args:
-      repository_ctx: The repository context.
-      cc: path to the C compiler.
-      lang_flag: value for the language flag (c, c++).
-      additional_flags: additional flags to pass to cc.
-    Returns:
-      a list of escaped system include directories.
-    """
+def _get_cxx_include_directories(repository_ctx, print_resource_dir_supported, cc, lang_flag, additional_flags = []):
+    """Compute the list of C++ include directories."""
     result = repository_ctx.execute([cc, "-E", lang_flag, "-", "-v"] + additional_flags)
     index1 = result.stderr.find(_INC_DIR_MARKER_BEGIN)
     if index1 == -1:
@@ -135,9 +133,9 @@
         for p in inc_dirs.split("\n")
     ]
 
-    if _is_compiler_option_supported(repository_ctx, cc, "-print-resource-dir"):
+    if print_resource_dir_supported:
         resource_dir = repository_ctx.execute(
-            [cc, "-print-resource-dir"],
+            [cc, "-print-resource-dir"] + additional_flags,
         ).stdout.strip() + "/share"
         inc_directories.append(_prepare_include_path(repository_ctx, resource_dir))
 
@@ -155,10 +153,9 @@
     ])
     return result.stderr.find(option) == -1
 
-def _is_linker_option_supported(repository_ctx, cc, option, pattern):
+def _is_linker_option_supported(repository_ctx, cc, force_linker_flags, option, pattern):
     """Checks that `option` is supported by the C linker. Doesn't %-escape the option."""
-    result = repository_ctx.execute([
-        cc,
+    result = repository_ctx.execute([cc] + force_linker_flags + [
         option,
         "-o",
         "/dev/null",
@@ -166,63 +163,50 @@
     ])
     return result.stderr.find(pattern) == -1
 
-def _find_gold_linker_path(repository_ctx, cc):
-    """Checks if `gold` is supported by the C compiler.
+def _find_linker_path(repository_ctx, cc, linker, is_clang):
+    """Checks if a given linker is supported by the C compiler.
 
     Args:
       repository_ctx: repository_ctx.
       cc: path to the C compiler.
+      linker: linker to find
+      is_clang: whether the compiler is known to be clang
 
     Returns:
-      String to put as value to -fuse-ld= flag, or None if gold couldn't be found.
+      String to put as value to -fuse-ld= flag, or None if linker couldn't be found.
     """
     result = repository_ctx.execute([
         cc,
         str(repository_ctx.path("tools/cpp/empty.cc")),
         "-o",
         "/dev/null",
-        # Some macos clang versions don't fail when setting -fuse-ld=gold, adding
+        # Some macOS clang versions don't fail when setting -fuse-ld=gold, adding
         # these lines to force it to. This also means that we will not detect
         # gold when only a very old (year 2010 and older) is present.
         "-Wl,--start-lib",
         "-Wl,--end-lib",
-        "-fuse-ld=gold",
+        "-fuse-ld=" + linker,
         "-v",
     ])
     if result.return_code != 0:
         return None
 
-    for line in result.stderr.splitlines():
-        if line.find("gold") == -1:
-            continue
-        for flag in line.split(" "):
-            if flag.find("gold") == -1:
-                continue
-            if flag.find("--enable-gold") > -1 or flag.find("--with-plugin-ld") > -1:
-                # skip build configuration options of gcc itself
-                # TODO(hlopko): Add redhat-like worker on the CI (#9392)
-                continue
+    if not is_clang:
+        return linker
 
-            # flag is '-fuse-ld=gold' for GCC or "/usr/lib/ld.gold" for Clang
-            # strip space, single quote, and double quotes
-            flag = flag.strip(" \"'")
-
-            # remove -fuse-ld= from GCC output so we have only the flag value part
-            flag = flag.replace("-fuse-ld=", "")
-            return flag
-    auto_configure_warning(
-        "CC with -fuse-ld=gold returned 0, but its -v output " +
-        "didn't contain 'gold', falling back to the default linker.",
-    )
-    return None
+    # Extract linker path from:
+    # /usr/bin/clang ...
+    # "/usr/bin/ld.lld" -pie -z ...
+    linker_command = result.stderr.splitlines()[-1]
+    return linker_command.strip().split(" ")[0].strip("\"'")
 
 def _add_compiler_option_if_supported(repository_ctx, cc, option):
     """Returns `[option]` if supported, `[]` otherwise. Doesn't %-escape the option."""
     return [option] if _is_compiler_option_supported(repository_ctx, cc, option) else []
 
-def _add_linker_option_if_supported(repository_ctx, cc, option, pattern):
+def _add_linker_option_if_supported(repository_ctx, cc, force_linker_flags, option, pattern):
     """Returns `[option]` if supported, `[]` otherwise. Doesn't %-escape the option."""
-    return [option] if _is_linker_option_supported(repository_ctx, cc, option, pattern) else []
+    return [option] if _is_linker_option_supported(repository_ctx, cc, force_linker_flags, option, pattern) else []
 
 def _get_no_canonical_prefixes_opt(repository_ctx, cc):
     # If the compiler sometimes rewrites paths in the .d files without symlinks
@@ -280,11 +264,27 @@
         link_flags = '"--coverage"'
     return compile_flags, link_flags
 
-def _find_generic(repository_ctx, name, env_name, overriden_tools, warn = False, silent = False):
+def _is_clang(repository_ctx, cc):
+    return "clang" in repository_ctx.execute([cc, "-v"]).stderr
+
+def _is_gcc(repository_ctx, cc):
+    # GCC's version output uses the basename of argv[0] as the program name:
+    # https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/gcc.cc;h=158461167951c1b9540322fb19be6a89d6da07fc;hb=HEAD#l8728
+    cc_stdout = repository_ctx.execute([cc, "--version"]).stdout
+    return cc_stdout.startswith("gcc ") or cc_stdout.startswith("gcc-")
+
+def _get_compiler_name(repository_ctx, cc):
+    if _is_clang(repository_ctx, cc):
+        return "clang"
+    if _is_gcc(repository_ctx, cc):
+        return "gcc"
+    return "compiler"
+
+def _find_generic(repository_ctx, name, env_name, overridden_tools, warn = False, silent = False):
     """Find a generic C++ toolchain tool. Doesn't %-escape the result."""
 
-    if name in overriden_tools:
-        return overriden_tools[name]
+    if name in overridden_tools:
+        return overridden_tools[name]
 
     result = name
     env_value = repository_ctx.os.environ.get(env_name)
@@ -295,7 +295,7 @@
             result = env_value
             env_value_with_paren = " (%s)" % env_value
     if result.startswith("/"):
-        # Absolute path, maybe we should make this suported by our which function.
+        # Absolute path, maybe we should make this supported by our which function.
         return result
     result = repository_ctx.which(result)
     if result == None:
@@ -308,23 +308,44 @@
             auto_configure_fail(msg)
     return result
 
-def find_cc(repository_ctx, overriden_tools):
-    return _find_generic(repository_ctx, "gcc", "CC", overriden_tools)
-
-def configure_unix_toolchain(repository_ctx, cpu_value, overriden_tools):
-    """Configure C++ toolchain on Unix platforms.
+def find_cc(repository_ctx, overridden_tools):
+    """Find the C compiler (gcc or clang) for the repository, considering overridden tools.
 
     Args:
       repository_ctx: The repository context.
-      cpu_value: current cpu name.
-      overriden_tools: overriden tools.
+      overridden_tools: A dictionary of overridden tools.
+
+    Returns:
+      The path to the C compiler.
+    """
+    cc = _find_generic(repository_ctx, "gcc", "CC", overridden_tools)
+    if _is_clang(repository_ctx, cc):
+        # If clang is run through a symlink with -no-canonical-prefixes, it does
+        # not find its own include directory, which includes the headers for
+        # libc++. Resolving the potential symlink here prevents this.
+        result = repository_ctx.execute(["readlink", "-f", cc])
+        if result.return_code == 0:
+            return result.stdout.strip()
+    return cc
+
+def configure_unix_toolchain(repository_ctx, cpu_value, overridden_tools):
+    """Configure C++ toolchain on Unix platforms.
+
+    Args:
+        repository_ctx: The repository context.
+        cpu_value: The CPU value.
+        overridden_tools: A dictionary of overridden tools.
     """
     paths = resolve_labels(repository_ctx, [
         "@rules_cc//cc/private/toolchain:BUILD.tpl",
+        "@rules_cc//cc/private/toolchain:generate_system_module_map.sh",
         "@rules_cc//cc/private/toolchain:armeabi_cc_toolchain_config.bzl",
         "@rules_cc//cc/private/toolchain:unix_cc_toolchain_config.bzl",
         "@rules_cc//cc/private/toolchain:linux_cc_wrapper.sh.tpl",
+        "@rules_cc//cc/private/toolchain:validate_static_library.sh.tpl",
         "@rules_cc//cc/private/toolchain:osx_cc_wrapper.sh.tpl",
+        "@rules_cc//cc/private/toolchain:clang_deps_scanner_wrapper.sh.tpl",
+        "@rules_cc//cc/private/toolchain:gcc_deps_scanner_wrapper.sh.tpl",
     ])
 
     repository_ctx.symlink(
@@ -338,24 +359,56 @@
     )
 
     repository_ctx.file("tools/cpp/empty.cc", "int main() {}")
-    darwin = cpu_value == "darwin"
+    darwin = cpu_value.startswith("darwin")
+    bsd = cpu_value == "freebsd" or cpu_value == "openbsd"
 
-    cc = _find_generic(repository_ctx, "gcc", "CC", overriden_tools)
-    overriden_tools = dict(overriden_tools)
-    overriden_tools["gcc"] = cc
-    overriden_tools["gcov"] = _find_generic(
+    cc = find_cc(repository_ctx, overridden_tools)
+    is_clang = _is_clang(repository_ctx, cc)
+    overridden_tools = dict(overridden_tools)
+    overridden_tools["gcc"] = cc
+    overridden_tools["gcov"] = _find_generic(
         repository_ctx,
         "gcov",
         "GCOV",
-        overriden_tools,
+        overridden_tools,
+        warn = True,
+        silent = True,
+    )
+    overridden_tools["llvm-cov"] = _find_generic(
+        repository_ctx,
+        "llvm-cov",
+        "BAZEL_LLVM_COV",
+        overridden_tools,
+        warn = True,
+        silent = True,
+    )
+    overridden_tools["llvm-profdata"] = _find_generic(
+        repository_ctx,
+        "llvm-profdata",
+        "BAZEL_LLVM_PROFDATA",
+        overridden_tools,
+        warn = True,
+        silent = True,
+    )
+    overridden_tools["ar"] = _find_generic(
+        repository_ctx,
+        "ar",
+        "AR",
+        overridden_tools,
         warn = True,
         silent = True,
     )
     if darwin:
-        overriden_tools["gcc"] = "cc_wrapper.sh"
-        overriden_tools["ar"] = "/usr/bin/libtool"
+        overridden_tools["gcc"] = "cc_wrapper.sh"
+        overridden_tools["ar"] = _find_generic(repository_ctx, "libtool", "LIBTOOL", overridden_tools)
+
     auto_configure_warning_maybe(repository_ctx, "CC used: " + str(cc))
-    tool_paths = _get_tool_paths(repository_ctx, overriden_tools)
+    tool_paths = _get_tool_paths(repository_ctx, overridden_tools)
+    tool_paths["cpp-module-deps-scanner"] = "deps_scanner_wrapper.sh"
+
+    # The parse_header tool needs to be a wrapper around the compiler as it has
+    # to touch the output file.
+    tool_paths["parse_headers"] = "cc_wrapper.sh"
     cc_toolchain_identifier = escape_string(get_env_var(
         repository_ctx,
         "CC_TOOLCHAIN_NAME",
@@ -363,6 +416,19 @@
         False,
     ))
 
+    if "nm" in tool_paths and "c++filt" in tool_paths:
+        repository_ctx.template(
+            "validate_static_library.sh",
+            paths["@rules_cc//cc/private/toolchain:validate_static_library.sh.tpl"],
+            {
+                "%{c++filt}": escape_string(str(repository_ctx.path(tool_paths["c++filt"]))),
+                # Certain weak symbols are otherwise listed with type T in the output of nm on macOS.
+                "%{nm_extra_args}": "--no-weak" if darwin else "",
+                "%{nm}": escape_string(str(repository_ctx.path(tool_paths["nm"]))),
+            },
+        )
+        tool_paths["validate_static_library"] = "validate_static_library.sh"
+
     cc_wrapper_src = (
         "@rules_cc//cc/private/toolchain:osx_cc_wrapper.sh.tpl" if darwin else "@rules_cc//cc/private/toolchain:linux_cc_wrapper.sh.tpl"
     )
@@ -374,16 +440,94 @@
             "%{env}": escape_string(get_env(repository_ctx)),
         },
     )
+    deps_scanner_wrapper_src = (
+        "@rules_cc//cc/private/toolchain:clang_deps_scanner_wrapper.sh.tpl" if is_clang else "@rules_cc//cc/private/toolchain:gcc_deps_scanner_wrapper.sh.tpl"
+    )
+    deps_scanner = "cpp-module-deps-scanner_not_found"
+    if is_clang:
+        cc_str = str(cc)
+        path_arr = cc_str.split("/")[:-1]
+        path_arr.append("clang-scan-deps")
+        deps_scanner = "/".join(path_arr)
+    repository_ctx.template(
+        "deps_scanner_wrapper.sh",
+        paths[deps_scanner_wrapper_src],
+        {
+            "%{cc}": escape_string(str(cc)),
+            "%{deps_scanner}": escape_string(deps_scanner),
+            "%{env}": escape_string(get_env(repository_ctx)),
+        },
+    )
+
+    conly_opts = split_escaped(get_env_var(
+        repository_ctx,
+        "BAZEL_CONLYOPTS",
+        "",
+        False,
+    ), ":")
 
     cxx_opts = split_escaped(get_env_var(
         repository_ctx,
         "BAZEL_CXXOPTS",
-        "-std=c++0x",
+        "-std=c++17",
         False,
     ), ":")
 
-    bazel_linklibs = "-lstdc++:-lm"
+    gold_or_lld_linker_path = (
+        _find_linker_path(repository_ctx, cc, "lld", is_clang) or
+        _find_linker_path(repository_ctx, cc, "gold", is_clang)
+    )
+    cc_path = repository_ctx.path(cc)
+    if not str(cc_path).startswith(str(repository_ctx.path(".")) + "/"):
+        # cc is outside the repository, set -B
+        bin_search_flags = ["-B" + escape_string(str(cc_path.dirname))]
+    else:
+        # cc is inside the repository, don't set -B.
+        bin_search_flags = []
+    if not gold_or_lld_linker_path:
+        ld_path = repository_ctx.path(tool_paths["ld"])
+        if ld_path.dirname != cc_path.dirname:
+            bin_search_flags.append("-B" + str(ld_path.dirname))
+    force_linker_flags = []
+    if gold_or_lld_linker_path:
+        force_linker_flags.append("-fuse-ld=" + gold_or_lld_linker_path)
+
+    # TODO: It's unclear why these flags aren't added on macOS.
+    if bin_search_flags and not darwin:
+        force_linker_flags.extend(bin_search_flags)
+    use_libcpp = darwin or bsd
+    is_as_needed_supported = _is_linker_option_supported(
+        repository_ctx,
+        cc,
+        force_linker_flags,
+        "-Wl,-no-as-needed",
+        "-no-as-needed",
+    )
+    is_push_state_supported = _is_linker_option_supported(
+        repository_ctx,
+        cc,
+        force_linker_flags,
+        "-Wl,--push-state",
+        "--push-state",
+    )
+    if use_libcpp:
+        bazel_default_libs = ["-lc++", "-lm"]
+    else:
+        bazel_default_libs = ["-lstdc++", "-lm"]
+    if is_as_needed_supported and is_push_state_supported:
+        # Do not link against C++ standard libraries unless they are actually
+        # used.
+        # We assume that --push-state support implies --pop-state support.
+        bazel_linklibs_elements = [
+            arg
+            for lib in bazel_default_libs
+            for arg in ["-Wl,--push-state,-as-needed", lib, "-Wl,--pop-state"]
+        ]
+    else:
+        bazel_linklibs_elements = bazel_default_libs
+    bazel_linklibs = ":".join(bazel_linklibs_elements)
     bazel_linkopts = ""
+
     link_opts = split_escaped(get_env_var(
         repository_ctx,
         "BAZEL_LINKOPTS",
@@ -396,33 +540,73 @@
         bazel_linklibs,
         False,
     ), ":")
-    gold_linker_path = _find_gold_linker_path(repository_ctx, cc)
-    cc_path = repository_ctx.path(cc)
-    if not str(cc_path).startswith(str(repository_ctx.path(".")) + "/"):
-        # cc is outside the repository, set -B
-        bin_search_flag = ["-B" + escape_string(str(cc_path.dirname))]
-    else:
-        # cc is inside the repository, don't set -B.
-        bin_search_flag = []
-
     coverage_compile_flags, coverage_link_flags = _coverage_flags(repository_ctx, darwin)
+    print_resource_dir_supported = _is_compiler_option_supported(
+        repository_ctx,
+        cc,
+        "-print-resource-dir",
+    )
+    no_canonical_prefixes_opt = _get_no_canonical_prefixes_opt(repository_ctx, cc)
     builtin_include_directories = _uniq(
-        get_escaped_cxx_inc_directories(repository_ctx, cc, "-xc") +
-        get_escaped_cxx_inc_directories(repository_ctx, cc, "-xc++", cxx_opts) +
-        get_escaped_cxx_inc_directories(
+        _get_cxx_include_directories(repository_ctx, print_resource_dir_supported, cc, "-xc", conly_opts) +
+        _get_cxx_include_directories(repository_ctx, print_resource_dir_supported, cc, "-xc++", cxx_opts) +
+        _get_cxx_include_directories(
             repository_ctx,
-            cc,
-            "-xc",
-            _get_no_canonical_prefixes_opt(repository_ctx, cc),
-        ) +
-        get_escaped_cxx_inc_directories(
-            repository_ctx,
+            print_resource_dir_supported,
             cc,
             "-xc++",
-            cxx_opts + _get_no_canonical_prefixes_opt(repository_ctx, cc),
-        ),
+            cxx_opts + ["-stdlib=libc++"],
+        ) +
+        _get_cxx_include_directories(
+            repository_ctx,
+            print_resource_dir_supported,
+            cc,
+            "-xc",
+            no_canonical_prefixes_opt,
+        ) +
+        _get_cxx_include_directories(
+            repository_ctx,
+            print_resource_dir_supported,
+            cc,
+            "-xc++",
+            cxx_opts + no_canonical_prefixes_opt,
+        ) +
+        _get_cxx_include_directories(
+            repository_ctx,
+            print_resource_dir_supported,
+            cc,
+            "-xc++",
+            cxx_opts + no_canonical_prefixes_opt + ["-stdlib=libc++"],
+        ) +
+        # Always included in case the user has Xcode + the CLT installed, both
+        # paths can be used interchangeably
+        ["/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk"],
     )
 
+    generate_modulemap = is_clang
+    if generate_modulemap:
+        repository_ctx.file("module.modulemap", _generate_system_module_map(
+            repository_ctx,
+            builtin_include_directories,
+            paths["@rules_cc//cc/private/toolchain:generate_system_module_map.sh"],
+        ))
+    extra_flags_per_feature = {}
+    if is_clang:
+        # Only supported by LLVM 14 and later, but required with C++20 and
+        # layering_check as C++ modules are the default.
+        # https://github.com/llvm/llvm-project/commit/0556138624edf48621dd49a463dbe12e7101f17d
+        result = repository_ctx.execute([
+            cc,
+            "-Xclang",
+            "-fno-cxx-modules",
+            "-o",
+            "/dev/null",
+            "-c",
+            str(repository_ctx.path("tools/cpp/empty.cc")),
+        ])
+        if "-fno-cxx-modules" not in result.stderr:
+            extra_flags_per_feature["use_module_maps"] = ["-Xclang", "-fno-cxx-modules"]
+
     write_builtin_include_directory_paths(repository_ctx, cc, builtin_include_directories)
     repository_ctx.template(
         "BUILD",
@@ -440,23 +624,24 @@
                 "local",
                 False,
             )),
-            "%{cc_compiler_deps}": get_starlark_list([":builtin_include_directory_paths"] + (
-                [":cc_wrapper"] if darwin else []
+            "%{cc_compiler_deps}": get_starlark_list([
+                ":builtin_include_directory_paths",
+                ":cc_wrapper",
+                ":deps_scanner_wrapper",
+            ] + (
+                [":validate_static_library"] if "validate_static_library" in tool_paths else []
             )),
             "%{cc_toolchain_identifier}": cc_toolchain_identifier,
             "%{compile_flags}": get_starlark_list(
                 [
-                    # Security hardening requires optimization.
-                    # We need to undef it as some distributions now have it enabled by default.
-                    "-U_FORTIFY_SOURCE",
                     "-fstack-protector",
-                    # All warnings are enabled. Maybe enable -Werror as well?
+                    # All warnings are enabled.
                     "-Wall",
                     # Enable a few more warnings that aren't part of -Wall.
-                ] + (
+                ] + ((
                     _add_compiler_option_if_supported(repository_ctx, cc, "-Wthread-safety") +
                     _add_compiler_option_if_supported(repository_ctx, cc, "-Wself-assign")
-                ) + (
+                )) + (
                     # Disable problematic warnings.
                     _add_compiler_option_if_supported(repository_ctx, cc, "-Wunused-but-set-parameter") +
                     # has false positives
@@ -472,38 +657,34 @@
             "%{compiler}": escape_string(get_env_var(
                 repository_ctx,
                 "BAZEL_COMPILER",
-                "compiler",
+                _get_compiler_name(repository_ctx, cc),
                 False,
             )),
+            "%{conly_flags}": get_starlark_list(conly_opts),
             "%{coverage_compile_flags}": coverage_compile_flags,
             "%{coverage_link_flags}": coverage_link_flags,
             "%{cxx_builtin_include_directories}": get_starlark_list(builtin_include_directories),
             "%{cxx_flags}": get_starlark_list(cxx_opts + _escaped_cplus_include_paths(repository_ctx)),
             "%{dbg_compile_flags}": get_starlark_list(["-g"]),
+            "%{extra_flags_per_feature}": repr(extra_flags_per_feature),
             "%{host_system_name}": escape_string(get_env_var(
                 repository_ctx,
                 "BAZEL_HOST_SYSTEM",
                 "local",
                 False,
             )),
-            "%{link_flags}": get_starlark_list((
-                ["-fuse-ld=" + gold_linker_path] if gold_linker_path else []
+            "%{link_flags}": get_starlark_list(force_linker_flags + (
+                ["-Wl,-no-as-needed"] if is_as_needed_supported else []
             ) + _add_linker_option_if_supported(
                 repository_ctx,
                 cc,
-                "-Wl,-no-as-needed",
-                "-no-as-needed",
-            ) + _add_linker_option_if_supported(
-                repository_ctx,
-                cc,
+                force_linker_flags,
                 "-Wl,-z,relro,-z,now",
                 "-z",
             ) + (
                 [
-                    "-undefined",
-                    "dynamic_lookup",
                     "-headerpad_max_install_names",
-                ] if darwin else bin_search_flag + [
+                ] if darwin else [
                     # Gold linker only? Can we enable this by default?
                     # "-Wl,--warn-execstack",
                     # "-Wl,--detect-odr-violations"
@@ -515,6 +696,7 @@
                 )
             ) + link_opts),
             "%{link_libs}": get_starlark_list(link_libs),
+            "%{modulemap}": ("\":module.modulemap\"" if generate_modulemap else "None"),
             "%{name}": cpu_value,
             "%{opt_compile_flags}": get_starlark_list(
                 [
@@ -543,15 +725,15 @@
                 ],
             ),
             "%{opt_link_flags}": get_starlark_list(
-                [] if darwin else _add_linker_option_if_supported(
+                ["-Wl,-dead_strip"] if darwin else _add_linker_option_if_supported(
                     repository_ctx,
                     cc,
+                    force_linker_flags,
                     "-Wl,--gc-sections",
                     "-gc-sections",
                 ),
             ),
-            "%{supports_param_files}": "0" if darwin else "1",
-            "%{supports_start_end_lib}": "True" if gold_linker_path else "False",
+            "%{supports_start_end_lib}": "True" if gold_or_lld_linker_path else "False",
             "%{target_cpu}": escape_string(get_env_var(
                 repository_ctx,
                 "BAZEL_TARGET_CPU",
@@ -571,7 +753,7 @@
                 False,
             )),
             "%{tool_paths}": ",\n        ".join(
-                ['"%s": "%s"' % (k, v) for k, v in tool_paths.items()],
+                ['"%s": "%s"' % (k, v) for k, v in tool_paths.items() if v != None],
             ),
             "%{unfiltered_compile_flags}": get_starlark_list(
                 _get_no_canonical_prefixes_opt(repository_ctx, cc) + [
diff --git a/cc/private/toolchain/unix_cc_toolchain_config.bzl b/cc/private/toolchain/unix_cc_toolchain_config.bzl
index 4325a68..5e0789b 100644
--- a/cc/private/toolchain/unix_cc_toolchain_config.bzl
+++ b/cc/private/toolchain/unix_cc_toolchain_config.bzl
@@ -17,15 +17,137 @@
 load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES")
 load(
     "@rules_cc//cc:cc_toolchain_config_lib.bzl",
+    "action_config",
+    "artifact_name_pattern",
+    "env_entry",
+    "env_set",
     "feature",
     "feature_set",
     "flag_group",
     "flag_set",
+    "tool",
     "tool_path",
     "variable_with_value",
     "with_feature_set",
 )
 
+def _target_os_version(ctx):
+    platform_type = ctx.fragments.apple.single_arch_platform.platform_type
+    xcode_config = ctx.attr._xcode_config[apple_common.XcodeVersionConfig]
+    return xcode_config.minimum_os_for_platform_type(platform_type)
+
+def layering_check_features(compiler, extra_flags_per_feature, is_macos):
+    if compiler != "clang":
+        return []
+    return [
+        feature(
+            name = "use_module_maps",
+            requires = [feature_set(features = ["module_maps"])],
+            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(
+                            # macOS requires -Xclang because of a bug in Apple Clang
+                            flags = (["-Xclang"] if is_macos else []) + [
+                                "-fmodule-name=%{module_name}",
+                            ] + (["-Xclang"] if is_macos else []) + [
+                                "-fmodule-map-file=%{module_map_file}",
+                            ] + extra_flags_per_feature.get("use_module_maps", []),
+                        ),
+                    ],
+                ),
+            ],
+        ),
+
+        # Tell blaze we support module maps in general, so they will be generated
+        # for all c/c++ rules.
+        # Note: not all C++ rules support module maps; thus, do not imply this
+        # feature from other features - instead, require it.
+        feature(name = "module_maps", enabled = True),
+        feature(
+            name = "layering_check",
+            implies = ["use_module_maps"],
+            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 = [
+                            "-fmodules-strict-decluse",
+                            "-Wprivate-header",
+                        ]),
+                        flag_group(
+                            iterate_over = "dependent_module_map_files",
+                            flags = (["-Xclang"] if is_macos else []) + [
+                                "-fmodule-map-file=%{dependent_module_map_files}",
+                            ],
+                        ),
+                    ],
+                ),
+            ],
+        ),
+    ]
+
+def parse_headers_support(parse_headers_tool_path):
+    """
+    Returns action configurations and features for parsing headers.
+
+    Args:
+        parse_headers_tool_path: The path to the tool used for parsing headers.
+
+    Returns:
+        A tuple containing a list of action configurations and a list of features.
+    """
+    if not parse_headers_tool_path:
+        return [], []
+    action_configs = [
+        action_config(
+            action_name = ACTION_NAMES.cpp_header_parsing,
+            tools = [
+                tool(path = parse_headers_tool_path),
+            ],
+            flag_sets = [
+                flag_set(
+                    flag_groups = [
+                        flag_group(
+                            flags = [
+                                # Note: This treats all headers as C++ headers, which may lead to
+                                # parsing failures for C headers that are not valid C++.
+                                # For such headers, use features = ["-parse_headers"] to selectively
+                                # disable parsing.
+                                "-xc++-header",
+                                "-fsyntax-only",
+                            ],
+                        ),
+                    ],
+                ),
+            ],
+            implies = [
+                # Copied from the legacy feature definition in CppActionConfigs.java.
+                "legacy_compile_flags",
+                "user_compile_flags",
+                "sysroot",
+                "unfiltered_compile_flags",
+                "compiler_input_flags",
+                "compiler_output_flags",
+            ],
+        ),
+    ]
+    features = [
+        feature(name = "parse_headers"),
+    ]
+    return action_configs, features
+
 all_compile_actions = [
     ACTION_NAMES.c_compile,
     ACTION_NAMES.cpp_compile,
@@ -35,6 +157,9 @@
     ACTION_NAMES.cpp_header_parsing,
     ACTION_NAMES.cpp_module_compile,
     ACTION_NAMES.cpp_module_codegen,
+    ACTION_NAMES.cpp_module_deps_scanning,
+    ACTION_NAMES.cpp20_module_compile,
+    ACTION_NAMES.cpp20_module_codegen,
     ACTION_NAMES.clif_match,
     ACTION_NAMES.lto_backend,
 ]
@@ -45,6 +170,9 @@
     ACTION_NAMES.cpp_header_parsing,
     ACTION_NAMES.cpp_module_compile,
     ACTION_NAMES.cpp_module_codegen,
+    ACTION_NAMES.cpp_module_deps_scanning,
+    ACTION_NAMES.cpp20_module_compile,
+    ACTION_NAMES.cpp20_module_codegen,
     ACTION_NAMES.clif_match,
 ]
 
@@ -55,6 +183,8 @@
     ACTION_NAMES.preprocess_assemble,
     ACTION_NAMES.cpp_header_parsing,
     ACTION_NAMES.cpp_module_compile,
+    ACTION_NAMES.cpp_module_deps_scanning,
+    ACTION_NAMES.cpp20_module_compile,
     ACTION_NAMES.clif_match,
 ]
 
@@ -65,6 +195,7 @@
     ACTION_NAMES.assemble,
     ACTION_NAMES.preprocess_assemble,
     ACTION_NAMES.cpp_module_codegen,
+    ACTION_NAMES.cpp20_module_codegen,
     ACTION_NAMES.lto_backend,
 ]
 
@@ -80,13 +211,144 @@
     ACTION_NAMES.lto_index_for_nodeps_dynamic_library,
 ]
 
+def _sanitizer_feature(name = "", specific_compile_flags = [], specific_link_flags = []):
+    return feature(
+        name = name,
+        flag_sets = [
+            flag_set(
+                actions = all_compile_actions,
+                flag_groups = [
+                    flag_group(flags = [
+                        "-fno-omit-frame-pointer",
+                        "-fno-sanitize-recover=all",
+                    ] + specific_compile_flags),
+                ],
+                with_features = [
+                    with_feature_set(features = [name]),
+                ],
+            ),
+            flag_set(
+                actions = all_link_actions,
+                flag_groups = [
+                    flag_group(flags = specific_link_flags),
+                ],
+                with_features = [
+                    with_feature_set(features = [name]),
+                ],
+            ),
+        ],
+    )
+
 def _impl(ctx):
+    is_linux = ctx.attr.target_libc != "macosx"
+
     tool_paths = [
         tool_path(name = name, path = path)
         for name, path in ctx.attr.tool_paths.items()
     ]
     action_configs = []
 
+    llvm_cov = ctx.attr.tool_paths.get("llvm-cov")
+    if llvm_cov:
+        llvm_cov_action = action_config(
+            action_name = ACTION_NAMES.llvm_cov,
+            tools = [
+                tool(
+                    path = llvm_cov,
+                ),
+            ],
+        )
+        action_configs.append(llvm_cov_action)
+
+    objcopy = ctx.attr.tool_paths.get("objcopy")
+    if objcopy:
+        objcopy_action = action_config(
+            action_name = ACTION_NAMES.objcopy_embed_data,
+            tools = [
+                tool(
+                    path = objcopy,
+                ),
+            ],
+        )
+        action_configs.append(objcopy_action)
+
+    validate_static_library = ctx.attr.tool_paths.get("validate_static_library")
+    if validate_static_library:
+        validate_static_library_action = action_config(
+            action_name = ACTION_NAMES.validate_static_library,
+            tools = [
+                tool(
+                    path = validate_static_library,
+                ),
+            ],
+        )
+        action_configs.append(validate_static_library_action)
+
+        symbol_check = feature(
+            name = "symbol_check",
+            implies = [ACTION_NAMES.validate_static_library],
+        )
+    else:
+        symbol_check = None
+
+    deps_scanner = "cpp-module-deps-scanner_not_found"
+    if "cpp-module-deps-scanner" in ctx.attr.tool_paths:
+        deps_scanner = ctx.attr.tool_paths["cpp-module-deps-scanner"]
+    cc = ctx.attr.tool_paths.get("gcc")
+    compile_implies = [
+        # keep same with c++-compile
+        "legacy_compile_flags",
+        "user_compile_flags",
+        "sysroot",
+        "unfiltered_compile_flags",
+        "compiler_input_flags",
+        "compiler_output_flags",
+    ]
+    cpp_module_scan_deps = action_config(
+        action_name = ACTION_NAMES.cpp_module_deps_scanning,
+        tools = [
+            tool(
+                path = deps_scanner,
+            ),
+        ],
+        implies = compile_implies,
+    )
+    action_configs.append(cpp_module_scan_deps)
+
+    cpp20_module_compile = action_config(
+        action_name = ACTION_NAMES.cpp20_module_compile,
+        tools = [
+            tool(
+                path = cc,
+            ),
+        ],
+        flag_sets = [
+            flag_set(
+                flag_groups = [
+                    flag_group(
+                        flags = [
+                            "-x",
+                            "c++-module" if ctx.attr.compiler == "clang" else "c++",
+                        ],
+                    ),
+                ],
+            ),
+        ],
+        implies = compile_implies,
+    )
+    action_configs.append(cpp20_module_compile)
+
+    cpp20_module_codegen = action_config(
+        action_name = ACTION_NAMES.cpp20_module_codegen,
+        tools = [
+            tool(
+                path = cc,
+            ),
+        ],
+        implies = compile_implies,
+    )
+    action_configs.append(cpp20_module_codegen)
+
     supports_pic_feature = feature(
         name = "supports_pic",
         enabled = True,
@@ -96,12 +358,37 @@
         enabled = True,
     )
 
+    gcc_quoting_for_param_files_feature = feature(
+        name = "gcc_quoting_for_param_files",
+        enabled = True,
+    )
+
+    static_link_cpp_runtimes_feature = feature(
+        name = "static_link_cpp_runtimes",
+        enabled = False,
+    )
+
     default_compile_flags_feature = feature(
         name = "default_compile_flags",
         enabled = True,
         flag_sets = [
             flag_set(
                 actions = all_compile_actions,
+                flag_groups = [
+                    flag_group(
+                        # Security hardening requires optimization.
+                        # We need to undef it as some distributions now have it enabled by default.
+                        flags = ["-U_FORTIFY_SOURCE"],
+                    ),
+                ],
+                with_features = [
+                    with_feature_set(
+                        not_features = ["thin_lto"],
+                    ),
+                ],
+            ),
+            flag_set(
+                actions = all_compile_actions,
                 flag_groups = ([
                     flag_group(
                         flags = ctx.attr.compile_flags,
@@ -127,6 +414,14 @@
                 with_features = [with_feature_set(features = ["opt"])],
             ),
             flag_set(
+                actions = [ACTION_NAMES.c_compile],
+                flag_groups = ([
+                    flag_group(
+                        flags = ctx.attr.conly_flags,
+                    ),
+                ] if ctx.attr.conly_flags else []),
+            ),
+            flag_set(
                 actions = all_cpp_compile_actions + [ACTION_NAMES.lto_backend],
                 flag_groups = ([
                     flag_group(
@@ -159,6 +454,18 @@
                 with_features = [with_feature_set(features = ["opt"])],
             ),
         ],
+        env_sets = [
+            env_set(
+                actions = all_link_actions + lto_index_actions + [ACTION_NAMES.cpp_link_static_library],
+                env_entries = ([
+                    env_entry(
+                        # Required for hermetic links on macOS
+                        key = "ZERO_AR_DATE",
+                        value = "1",
+                    ),
+                ]),
+            ),
+        ],
     )
 
     dbg_feature = feature(name = "dbg")
@@ -178,6 +485,9 @@
                     ACTION_NAMES.cpp_header_parsing,
                     ACTION_NAMES.cpp_module_compile,
                     ACTION_NAMES.cpp_module_codegen,
+                    ACTION_NAMES.cpp_module_deps_scanning,
+                    ACTION_NAMES.cpp20_module_compile,
+                    ACTION_NAMES.cpp20_module_codegen,
                     ACTION_NAMES.lto_backend,
                     ACTION_NAMES.clif_match,
                 ] + all_link_actions + lto_index_actions,
@@ -191,6 +501,76 @@
         ],
     )
 
+    compiler_input_flags_feature = feature(
+        name = "compiler_input_flags",
+        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.cpp_module_deps_scanning,
+                    ACTION_NAMES.cpp20_module_compile,
+                    ACTION_NAMES.cpp20_module_codegen,
+                    ACTION_NAMES.objc_compile,
+                    ACTION_NAMES.objcpp_compile,
+                    ACTION_NAMES.lto_backend,
+                ],
+                flag_groups = [
+                    flag_group(
+                        flags = ["-c", "%{source_file}"],
+                        expand_if_available = "source_file",
+                    ),
+                ],
+            ),
+        ],
+    )
+
+    compiler_output_flags_feature = feature(
+        name = "compiler_output_flags",
+        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.cpp_module_deps_scanning,
+                    ACTION_NAMES.cpp20_module_compile,
+                    ACTION_NAMES.cpp20_module_codegen,
+                    ACTION_NAMES.objc_compile,
+                    ACTION_NAMES.objcpp_compile,
+                    ACTION_NAMES.lto_backend,
+                ],
+                flag_groups = [
+                    flag_group(
+                        flags = ["-S"],
+                        expand_if_available = "output_assembly_file",
+                    ),
+                    flag_group(
+                        flags = ["-E"],
+                        expand_if_available = "output_preprocess_file",
+                    ),
+                    flag_group(
+                        flags = ["-o", "%{output_file}"],
+                        expand_if_available = "output_file",
+                    ),
+                ],
+            ),
+        ],
+    )
+
     fdo_optimize_feature = feature(
         name = "fdo_optimize",
         flag_sets = [
@@ -292,6 +672,8 @@
                     ACTION_NAMES.cpp_compile,
                     ACTION_NAMES.cpp_module_codegen,
                     ACTION_NAMES.cpp_module_compile,
+                    ACTION_NAMES.cpp20_module_compile,
+                    ACTION_NAMES.cpp20_module_codegen,
                 ],
                 flag_groups = [
                     flag_group(flags = ["-fPIC"], expand_if_available = "pic"),
@@ -302,6 +684,7 @@
 
     per_object_debug_info_feature = feature(
         name = "per_object_debug_info",
+        enabled = True,
         flag_sets = [
             flag_set(
                 actions = [
@@ -310,6 +693,7 @@
                     ACTION_NAMES.c_compile,
                     ACTION_NAMES.cpp_compile,
                     ACTION_NAMES.cpp_module_codegen,
+                    ACTION_NAMES.cpp20_module_codegen,
                 ],
                 flag_groups = [
                     flag_group(
@@ -333,6 +717,9 @@
                     ACTION_NAMES.cpp_compile,
                     ACTION_NAMES.cpp_header_parsing,
                     ACTION_NAMES.cpp_module_compile,
+                    ACTION_NAMES.cpp_module_deps_scanning,
+                    ACTION_NAMES.cpp20_module_compile,
+                    ACTION_NAMES.cpp20_module_codegen,
                     ACTION_NAMES.clif_match,
                 ],
                 flag_groups = [
@@ -385,60 +772,134 @@
         provides = ["profile"],
     )
 
-    runtime_library_search_directories_feature = feature(
-        name = "runtime_library_search_directories",
-        flag_sets = [
-            flag_set(
-                actions = all_link_actions + lto_index_actions,
-                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 = all_link_actions + lto_index_actions,
-                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"],
-                    ),
-                ],
-            ),
-        ],
-    )
+    if is_linux:
+        runtime_library_search_directories_feature = feature(
+            name = "runtime_library_search_directories",
+            flag_sets = [
+                flag_set(
+                    actions = all_link_actions + lto_index_actions,
+                    flag_groups = [
+                        flag_group(
+                            iterate_over = "runtime_library_search_directories",
+                            flag_groups = [
+                                flag_group(
+                                    flags = [
+                                        "-Xlinker",
+                                        "-rpath",
+                                        "-Xlinker",
+                                        "$EXEC_ORIGIN/%{runtime_library_search_directories}",
+                                    ],
+                                    expand_if_true = "is_cc_test",
+                                ),
+                                flag_group(
+                                    flags = [
+                                        "-Xlinker",
+                                        "-rpath",
+                                        "-Xlinker",
+                                        "$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 = all_link_actions + lto_index_actions,
+                    flag_groups = [
+                        flag_group(
+                            iterate_over = "runtime_library_search_directories",
+                            flag_groups = [
+                                flag_group(
+                                    flags = [
+                                        "-Xlinker",
+                                        "-rpath",
+                                        "-Xlinker",
+                                        "$ORIGIN/%{runtime_library_search_directories}",
+                                    ],
+                                ),
+                            ],
+                            expand_if_available =
+                                "runtime_library_search_directories",
+                        ),
+                    ],
+                    with_features = [
+                        with_feature_set(
+                            not_features = ["static_link_cpp_runtimes"],
+                        ),
+                    ],
+                ),
+            ],
+        )
+        set_install_name_feature = feature(
+            name = "set_soname",
+            flag_sets = [
+                flag_set(
+                    actions = [
+                        ACTION_NAMES.cpp_link_dynamic_library,
+                        ACTION_NAMES.cpp_link_nodeps_dynamic_library,
+                    ],
+                    flag_groups = [
+                        flag_group(
+                            flags = [
+                                "-Wl,-soname,%{runtime_solib_name}",
+                            ],
+                            expand_if_available = "runtime_solib_name",
+                        ),
+                    ],
+                ),
+            ],
+        )
+    else:
+        runtime_library_search_directories_feature = feature(
+            name = "runtime_library_search_directories",
+            flag_sets = [
+                flag_set(
+                    actions = all_link_actions + lto_index_actions,
+                    flag_groups = [
+                        flag_group(
+                            iterate_over = "runtime_library_search_directories",
+                            flag_groups = [
+                                flag_group(
+                                    flags = [
+                                        "-Xlinker",
+                                        "-rpath",
+                                        "-Xlinker",
+                                        "@loader_path/%{runtime_library_search_directories}",
+                                    ],
+                                ),
+                            ],
+                            expand_if_available = "runtime_library_search_directories",
+                        ),
+                    ],
+                ),
+            ],
+        )
+        set_install_name_feature = feature(
+            name = "set_install_name",
+            enabled = ctx.fragments.cpp.do_not_use_macos_set_install_name,
+            flag_sets = [
+                flag_set(
+                    actions = [
+                        ACTION_NAMES.cpp_link_dynamic_library,
+                        ACTION_NAMES.cpp_link_nodeps_dynamic_library,
+                    ],
+                    flag_groups = [
+                        flag_group(
+                            flags = [
+                                "-Wl,-install_name,@rpath/%{runtime_solib_name}",
+                            ],
+                            expand_if_available = "runtime_solib_name",
+                        ),
+                    ],
+                ),
+            ],
+        )
 
     fission_support_feature = feature(
         name = "fission_support",
@@ -480,6 +941,9 @@
                     ACTION_NAMES.cpp_compile,
                     ACTION_NAMES.cpp_module_codegen,
                     ACTION_NAMES.cpp_module_compile,
+                    ACTION_NAMES.cpp_module_deps_scanning,
+                    ACTION_NAMES.cpp20_module_compile,
+                    ACTION_NAMES.cpp20_module_codegen,
                 ],
                 flag_groups = [
                     flag_group(
@@ -503,6 +967,8 @@
                     ACTION_NAMES.cpp_compile,
                     ACTION_NAMES.cpp_header_parsing,
                     ACTION_NAMES.cpp_module_compile,
+                    ACTION_NAMES.cpp_module_deps_scanning,
+                    ACTION_NAMES.cpp20_module_compile,
                     ACTION_NAMES.clif_match,
                     ACTION_NAMES.objc_compile,
                     ACTION_NAMES.objcpp_compile,
@@ -574,6 +1040,8 @@
                     ACTION_NAMES.cpp_compile,
                     ACTION_NAMES.cpp_header_parsing,
                     ACTION_NAMES.cpp_module_compile,
+                    ACTION_NAMES.cpp_module_deps_scanning,
+                    ACTION_NAMES.cpp20_module_compile,
                     ACTION_NAMES.clif_match,
                     ACTION_NAMES.objc_compile,
                     ACTION_NAMES.objcpp_compile,
@@ -596,56 +1064,33 @@
         ],
     )
 
-    symbol_counts_feature = feature(
-        name = "symbol_counts",
-        flag_sets = [
-            flag_set(
-                actions = all_link_actions + lto_index_actions,
-                flag_groups = [
-                    flag_group(
-                        flags = [
-                            "-Wl,--print-symbol-counts=%{symbol_counts_output}",
-                        ],
-                        expand_if_available = "symbol_counts_output",
-                    ),
-                ],
-            ),
-        ],
-    )
-
-    llvm_coverage_map_format_feature = feature(
-        name = "llvm_coverage_map_format",
+    external_include_paths_feature = feature(
+        name = "external_include_paths",
         flag_sets = [
             flag_set(
                 actions = [
                     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_deps_scanning,
+                    ACTION_NAMES.cpp20_module_compile,
+                    ACTION_NAMES.cpp20_module_codegen,
+                    ACTION_NAMES.clif_match,
                     ACTION_NAMES.objc_compile,
                     ACTION_NAMES.objcpp_compile,
                 ],
                 flag_groups = [
                     flag_group(
-                        flags = [
-                            "-fprofile-instr-generate",
-                            "-fcoverage-mapping",
-                        ],
+                        flags = ["-isystem", "%{external_include_paths}"],
+                        iterate_over = "external_include_paths",
+                        expand_if_available = "external_include_paths",
                     ),
                 ],
             ),
-            flag_set(
-                actions = all_link_actions + lto_index_actions + [
-                    "objc-executable",
-                    "objc++-executable",
-                ],
-                flag_groups = [
-                    flag_group(flags = ["-fprofile-instr-generate"]),
-                ],
-            ),
         ],
-        requires = [feature_set(features = ["coverage"])],
-        provides = ["profile"],
     )
 
     strip_debug_symbols_feature = feature(
@@ -693,11 +1138,77 @@
         ],
     )
 
+    libraries_to_link_common_flag_groups = [
+        flag_group(
+            flags = ["-Wl,-whole-archive"],
+            expand_if_true =
+                "libraries_to_link.is_whole_archive",
+            expand_if_equal = variable_with_value(
+                name = "libraries_to_link.type",
+                value = "static_library",
+            ),
+        ),
+        flag_group(
+            flags = ["%{libraries_to_link.object_files}"],
+            iterate_over = "libraries_to_link.object_files",
+            expand_if_equal = variable_with_value(
+                name = "libraries_to_link.type",
+                value = "object_file_group",
+            ),
+        ),
+        flag_group(
+            flags = ["%{libraries_to_link.name}"],
+            expand_if_equal = variable_with_value(
+                name = "libraries_to_link.type",
+                value = "object_file",
+            ),
+        ),
+        flag_group(
+            flags = ["%{libraries_to_link.name}"],
+            expand_if_equal = variable_with_value(
+                name = "libraries_to_link.type",
+                value = "interface_library",
+            ),
+        ),
+        flag_group(
+            flags = ["%{libraries_to_link.name}"],
+            expand_if_equal = variable_with_value(
+                name = "libraries_to_link.type",
+                value = "static_library",
+            ),
+        ),
+        flag_group(
+            flags = ["-l%{libraries_to_link.name}"],
+            expand_if_equal = variable_with_value(
+                name = "libraries_to_link.type",
+                value = "dynamic_library",
+            ),
+        ),
+        flag_group(
+            flags = ["-l:%{libraries_to_link.name}"],
+            expand_if_equal = variable_with_value(
+                name = "libraries_to_link.type",
+                value = "versioned_dynamic_library",
+            ),
+        ),
+        flag_group(
+            flags = ["-Wl,-no-whole-archive"],
+            expand_if_true = "libraries_to_link.is_whole_archive",
+            expand_if_equal = variable_with_value(
+                name = "libraries_to_link.type",
+                value = "static_library",
+            ),
+        ),
+    ]
+
     libraries_to_link_feature = feature(
         name = "libraries_to_link",
         flag_sets = [
             flag_set(
-                actions = all_link_actions + lto_index_actions,
+                actions = [
+                    ACTION_NAMES.cpp_link_executable,
+                    ACTION_NAMES.cpp_link_dynamic_library,
+                ] + lto_index_actions,
                 flag_groups = [
                     flag_group(
                         iterate_over = "libraries_to_link",
@@ -709,58 +1220,7 @@
                                     value = "object_file_group",
                                 ),
                             ),
-                            flag_group(
-                                flags = ["-Wl,-whole-archive"],
-                                expand_if_true =
-                                    "libraries_to_link.is_whole_archive",
-                            ),
-                            flag_group(
-                                flags = ["%{libraries_to_link.object_files}"],
-                                iterate_over = "libraries_to_link.object_files",
-                                expand_if_equal = variable_with_value(
-                                    name = "libraries_to_link.type",
-                                    value = "object_file_group",
-                                ),
-                            ),
-                            flag_group(
-                                flags = ["%{libraries_to_link.name}"],
-                                expand_if_equal = variable_with_value(
-                                    name = "libraries_to_link.type",
-                                    value = "object_file",
-                                ),
-                            ),
-                            flag_group(
-                                flags = ["%{libraries_to_link.name}"],
-                                expand_if_equal = variable_with_value(
-                                    name = "libraries_to_link.type",
-                                    value = "interface_library",
-                                ),
-                            ),
-                            flag_group(
-                                flags = ["%{libraries_to_link.name}"],
-                                expand_if_equal = variable_with_value(
-                                    name = "libraries_to_link.type",
-                                    value = "static_library",
-                                ),
-                            ),
-                            flag_group(
-                                flags = ["-l%{libraries_to_link.name}"],
-                                expand_if_equal = variable_with_value(
-                                    name = "libraries_to_link.type",
-                                    value = "dynamic_library",
-                                ),
-                            ),
-                            flag_group(
-                                flags = ["-l:%{libraries_to_link.name}"],
-                                expand_if_equal = variable_with_value(
-                                    name = "libraries_to_link.type",
-                                    value = "versioned_dynamic_library",
-                                ),
-                            ),
-                            flag_group(
-                                flags = ["-Wl,-no-whole-archive"],
-                                expand_if_true = "libraries_to_link.is_whole_archive",
-                            ),
+                        ] + libraries_to_link_common_flag_groups + [
                             flag_group(
                                 flags = ["-Wl,--end-lib"],
                                 expand_if_equal = variable_with_value(
@@ -777,6 +1237,22 @@
                     ),
                 ],
             ),
+            # Object file groups may contain symbols that aren't referenced in the same target that
+            # produces the object files and must thus not be wrapped in --start-lib/--end-lib when
+            # linking a nodeps dynamic library.
+            flag_set(
+                actions = [ACTION_NAMES.cpp_link_nodeps_dynamic_library],
+                flag_groups = [
+                    flag_group(
+                        iterate_over = "libraries_to_link",
+                        flag_groups = libraries_to_link_common_flag_groups,
+                    ),
+                    flag_group(
+                        flags = ["-Wl,@%{thinlto_param_file}"],
+                        expand_if_true = "thinlto_param_file",
+                    ),
+                ],
+            ),
         ],
     )
 
@@ -791,7 +1267,18 @@
                         iterate_over = "user_link_flags",
                         expand_if_available = "user_link_flags",
                     ),
-                ] + ([flag_group(flags = ctx.attr.link_libs)] if ctx.attr.link_libs else []),
+                ],
+            ),
+        ],
+    )
+
+    default_link_libs_feature = feature(
+        name = "default_link_libs",
+        enabled = True,
+        flag_sets = [
+            flag_set(
+                actions = all_link_actions + lto_index_actions,
+                flag_groups = [flag_group(flags = ctx.attr.link_libs)] if ctx.attr.link_libs else [],
             ),
         ],
     )
@@ -834,34 +1321,9 @@
         ],
     )
 
-    gcc_coverage_map_format_feature = feature(
-        name = "gcc_coverage_map_format",
-        flag_sets = [
-            flag_set(
-                actions = [
-                    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,
-                    "objc-executable",
-                    "objc++-executable",
-                ],
-                flag_groups = [
-                    flag_group(
-                        flags = ["-fprofile-arcs", "-ftest-coverage"],
-                        expand_if_available = "gcov_gcno_file",
-                    ),
-                ],
-            ),
-            flag_set(
-                actions = all_link_actions + lto_index_actions,
-                flag_groups = [flag_group(flags = ["--coverage"])],
-            ),
-        ],
-        requires = [feature_set(features = ["coverage"])],
-        provides = ["profile"],
+    libtool_feature = feature(
+        name = "libtool",
+        enabled = not is_linux,
     )
 
     archiver_flags_feature = feature(
@@ -870,12 +1332,37 @@
             flag_set(
                 actions = [ACTION_NAMES.cpp_link_static_library],
                 flag_groups = [
-                    flag_group(flags = ["rcsD"]),
                     flag_group(
-                        flags = ["%{output_execpath}"],
+                        flags = [
+                            "rcsD" if is_linux else "rcs",
+                            "%{output_execpath}",
+                        ],
                         expand_if_available = "output_execpath",
                     ),
                 ],
+                with_features = [
+                    with_feature_set(
+                        not_features = ["libtool"],
+                    ),
+                ],
+            ),
+            flag_set(
+                actions = [ACTION_NAMES.cpp_link_static_library],
+                flag_groups = [
+                    flag_group(
+                        flags = [
+                            "-static",
+                            "-o",
+                            "%{output_execpath}",
+                        ],
+                        expand_if_available = "output_execpath",
+                    ),
+                ],
+                with_features = [
+                    with_feature_set(
+                        features = ["libtool"],
+                    ),
+                ],
             ),
             flag_set(
                 actions = [ACTION_NAMES.cpp_link_static_library],
@@ -903,6 +1390,24 @@
                     ),
                 ],
             ),
+            flag_set(
+                actions = [ACTION_NAMES.cpp_link_static_library],
+                flag_groups = ([
+                    flag_group(
+                        flags = ctx.attr.archive_flags,
+                    ),
+                ] if ctx.attr.archive_flags else []),
+            ),
+            flag_set(
+                actions = [ACTION_NAMES.cpp_link_static_library],
+                flag_groups = [
+                    flag_group(
+                        flags = ["%{user_archiver_flags}"],
+                        iterate_over = "user_archiver_flags",
+                        expand_if_available = "user_archiver_flags",
+                    ),
+                ],
+            ),
         ],
     )
 
@@ -938,6 +1443,8 @@
                     ACTION_NAMES.objc_compile,
                     ACTION_NAMES.objcpp_compile,
                     ACTION_NAMES.cpp_header_parsing,
+                    ACTION_NAMES.cpp_module_deps_scanning,
+                    ACTION_NAMES.cpp20_module_compile,
                     ACTION_NAMES.clif_match,
                 ],
                 flag_groups = [
@@ -950,6 +1457,32 @@
         ],
     )
 
+    serialized_diagnostics_file_feature = feature(
+        name = "serialized_diagnostics_file",
+        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.cpp_module_deps_scanning,
+                    ACTION_NAMES.clif_match,
+                ],
+                flag_groups = [
+                    flag_group(
+                        flags = ["--serialize-diagnostics", "%{serialized_diagnostics_file}"],
+                        expand_if_available = "serialized_diagnostics_file",
+                    ),
+                ],
+            ),
+        ],
+    )
+
     dynamic_library_linker_tool_feature = feature(
         name = "dynamic_library_linker_tool",
         flag_sets = [
@@ -975,6 +1508,25 @@
         ],
     )
 
+    generate_linkmap_feature = feature(
+        name = "generate_linkmap",
+        flag_sets = [
+            flag_set(
+                actions = [
+                    ACTION_NAMES.cpp_link_executable,
+                ],
+                flag_groups = [
+                    flag_group(
+                        flags = [
+                            "-Wl,-Map=%{output_execpath}.map" if is_linux else "-Wl,-map,%{output_execpath}.map",
+                        ],
+                        expand_if_available = "output_execpath",
+                    ),
+                ],
+            ),
+        ],
+    )
+
     output_execpath_flags_feature = feature(
         name = "output_execpath_flags",
         flag_sets = [
@@ -1081,18 +1633,156 @@
         ],
     )
 
-    is_linux = ctx.attr.target_libc != "macosx"
+    treat_warnings_as_errors_feature = feature(
+        name = "treat_warnings_as_errors",
+        flag_sets = [
+            flag_set(
+                actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile],
+                flag_groups = [flag_group(flags = ["-Werror"])],
+            ),
+            flag_set(
+                actions = all_link_actions,
+                flag_groups = [flag_group(
+                    flags = ["-Wl,-fatal-warnings"] if is_linux else ["-Wl,-fatal_warnings"],
+                )],
+            ),
+        ],
+    )
+
+    archive_param_file_feature = feature(
+        name = "archive_param_file",
+        enabled = True,
+    )
+
+    asan_feature = _sanitizer_feature(
+        name = "asan",
+        specific_compile_flags = [
+            "-fsanitize=address",
+            "-fno-common",
+        ],
+        specific_link_flags = [
+            "-fsanitize=address",
+        ],
+    )
+
+    tsan_feature = _sanitizer_feature(
+        name = "tsan",
+        specific_compile_flags = [
+            "-fsanitize=thread",
+        ],
+        specific_link_flags = [
+            "-fsanitize=thread",
+        ],
+    )
+
+    ubsan_feature = _sanitizer_feature(
+        name = "ubsan",
+        specific_compile_flags = [
+            "-fsanitize=undefined",
+        ],
+        specific_link_flags = [
+            "-fsanitize=undefined",
+        ],
+    )
+
+    # If you have Xcode + the CLT installed the version defaults can be
+    # too old for some standard C apis such as thread locals
+    macos_minimum_os_feature = feature(
+        name = "macos_minimum_os",
+        enabled = True,
+        flag_sets = [
+            flag_set(
+                actions = all_compile_actions + all_link_actions,
+                flag_groups = [flag_group(flags = ["-mmacosx-version-min={}".format(_target_os_version(ctx))])],
+            ),
+        ],
+    )
+
+    # Kept for backwards compatibility with the crosstool that moved. Without
+    # linking the objc runtime binaries don't link CoreFoundation for free,
+    # which breaks abseil.
+    macos_default_link_flags_feature = feature(
+        name = "macos_default_link_flags",
+        enabled = True,
+        flag_sets = [
+            flag_set(
+                actions = all_link_actions,
+                flag_groups = [flag_group(flags = [
+                    "-no-canonical-prefixes",
+                    "-fobjc-link-runtime",
+                ])],
+            ),
+        ],
+    )
+
+    # Tell bazel we support C++ modules now
+    cpp_modules_feature = feature(
+        name = "cpp_modules",
+        # set default value to False
+        # to enable the feature
+        # use --features=cpp_modules
+        # or add cpp_modules to features attr
+        enabled = False,
+    )
+
+    cpp_module_modmap_file_feature = feature(
+        name = "cpp_module_modmap_file",
+        flag_sets = [
+            flag_set(
+                actions = [
+                    ACTION_NAMES.cpp_compile,
+                    ACTION_NAMES.cpp20_module_compile,
+                    ACTION_NAMES.cpp20_module_codegen,
+                ],
+                flag_groups = [
+                    flag_group(
+                        flags = ["@%{cpp_module_modmap_file}" if ctx.attr.compiler == "clang" else "-fmodule-mapper=%{cpp_module_modmap_file}"],
+                        expand_if_available = "cpp_module_modmap_file",
+                    ),
+                ],
+            ),
+        ],
+        enabled = True,
+    )
+    if ctx.attr.compiler == "clang":
+        flag_groups = [
+            flag_group(
+                flags = ["-fmodule-output=%{cpp_module_output_file}"],
+                expand_if_available = "cpp_module_output_file",
+            ),
+        ]
+    else:
+        flag_groups = []
+    cpp20_module_compile_flags_feature = feature(
+        name = "cpp20_module_compile_flags",
+        flag_sets = [
+            flag_set(
+                actions = [
+                    ACTION_NAMES.cpp20_module_compile,
+                ],
+                flag_groups = flag_groups,
+            ),
+        ],
+        enabled = True,
+    )
 
     # TODO(#8303): Mac crosstool should also declare every feature.
     if is_linux:
+        # Linux artifact name patterns are the default.
+        artifact_name_patterns = []
         features = [
+            cpp_modules_feature,
+            cpp_module_modmap_file_feature,
+            cpp20_module_compile_flags_feature,
             dependency_file_feature,
+            serialized_diagnostics_file_feature,
             random_seed_feature,
             pic_feature,
             per_object_debug_info_feature,
             preprocessor_defines_feature,
             includes_feature,
             include_paths_feature,
+            external_include_paths_feature,
             fdo_instrument_feature,
             cs_fdo_instrument_feature,
             cs_fdo_optimize_feature,
@@ -1101,20 +1791,24 @@
             autofdo_feature,
             build_interface_libraries_feature,
             dynamic_library_linker_tool_feature,
-            symbol_counts_feature,
+            generate_linkmap_feature,
             shared_flag_feature,
             linkstamps_feature,
             output_execpath_flags_feature,
             runtime_library_search_directories_feature,
             library_search_directories_feature,
+            libtool_feature,
             archiver_flags_feature,
             force_pic_flags_feature,
             fission_support_feature,
             strip_debug_symbols_feature,
             coverage_feature,
             supports_pic_feature,
-            gcc_coverage_map_format_feature,
-            llvm_coverage_map_format_feature,
+            asan_feature,
+            tsan_feature,
+            ubsan_feature,
+            gcc_quoting_for_param_files_feature,
+            static_link_cpp_runtimes_feature,
         ] + (
             [
                 supports_start_end_lib_feature,
@@ -1124,6 +1818,7 @@
             default_link_flags_feature,
             libraries_to_link_feature,
             user_link_flags_feature,
+            default_link_libs_feature,
             static_libgcc_feature,
             fdo_optimize_feature,
             supports_dynamic_linker_feature,
@@ -1131,11 +1826,39 @@
             opt_feature,
             user_compile_flags_feature,
             sysroot_feature,
+            compiler_input_flags_feature,
+            compiler_output_flags_feature,
             unfiltered_compile_flags_feature,
-        ]
+            treat_warnings_as_errors_feature,
+            archive_param_file_feature,
+            set_install_name_feature,
+        ] + layering_check_features(ctx.attr.compiler, ctx.attr.extra_flags_per_feature, is_macos = False)
     else:
+        # macOS artifact name patterns differ from the defaults only for dynamic
+        # libraries.
+        artifact_name_patterns = [
+            artifact_name_pattern(
+                category_name = "dynamic_library",
+                prefix = "lib",
+                extension = ".dylib",
+            ),
+        ]
         features = [
-            supports_pic_feature,
+            cpp_modules_feature,
+            cpp_module_modmap_file_feature,
+            cpp20_module_compile_flags_feature,
+            macos_minimum_os_feature,
+            macos_default_link_flags_feature,
+            dependency_file_feature,
+            runtime_library_search_directories_feature,
+            set_install_name_feature,
+            libtool_feature,
+            archiver_flags_feature,
+            asan_feature,
+            tsan_feature,
+            ubsan_feature,
+            gcc_quoting_for_param_files_feature,
+            static_link_cpp_runtimes_feature,
         ] + (
             [
                 supports_start_end_lib_feature,
@@ -1144,21 +1867,36 @@
             coverage_feature,
             default_compile_flags_feature,
             default_link_flags_feature,
+            user_link_flags_feature,
+            default_link_libs_feature,
+            external_include_paths_feature,
             fdo_optimize_feature,
-            supports_dynamic_linker_feature,
             dbg_feature,
             opt_feature,
             user_compile_flags_feature,
             sysroot_feature,
+            compiler_input_flags_feature,
+            compiler_output_flags_feature,
             unfiltered_compile_flags_feature,
-            gcc_coverage_map_format_feature,
-            llvm_coverage_map_format_feature,
-        ]
+            treat_warnings_as_errors_feature,
+            archive_param_file_feature,
+            generate_linkmap_feature,
+        ] + layering_check_features(ctx.attr.compiler, ctx.attr.extra_flags_per_feature, is_macos = True)
+
+    parse_headers_action_configs, parse_headers_features = parse_headers_support(
+        parse_headers_tool_path = ctx.attr.tool_paths.get("parse_headers"),
+    )
+    action_configs += parse_headers_action_configs
+    features += parse_headers_features
+
+    if symbol_check:
+        features.append(symbol_check)
 
     return cc_common.create_cc_toolchain_config_info(
         ctx = ctx,
         features = features,
         action_configs = action_configs,
+        artifact_name_patterns = artifact_name_patterns,
         cxx_builtin_include_directories = ctx.attr.cxx_builtin_include_directories,
         toolchain_identifier = ctx.attr.toolchain_identifier,
         host_system_name = ctx.attr.host_system_name,
@@ -1169,6 +1907,7 @@
         abi_version = ctx.attr.abi_version,
         abi_libc_version = ctx.attr.abi_libc_version,
         tool_paths = tool_paths,
+        builtin_sysroot = ctx.attr.builtin_sysroot,
     )
 
 cc_toolchain_config = rule(
@@ -1176,14 +1915,18 @@
     attrs = {
         "abi_libc_version": attr.string(mandatory = True),
         "abi_version": attr.string(mandatory = True),
+        "archive_flags": attr.string_list(),
+        "builtin_sysroot": attr.string(),
         "compile_flags": attr.string_list(),
         "compiler": attr.string(mandatory = True),
+        "conly_flags": attr.string_list(),
         "coverage_compile_flags": attr.string_list(),
         "coverage_link_flags": attr.string_list(),
         "cpu": attr.string(mandatory = True),
         "cxx_builtin_include_directories": attr.string_list(),
         "cxx_flags": attr.string_list(),
         "dbg_compile_flags": attr.string_list(),
+        "extra_flags_per_feature": attr.string_list_dict(),
         "host_system_name": attr.string(mandatory = True),
         "link_flags": attr.string_list(),
         "link_libs": attr.string_list(),
@@ -1195,6 +1938,11 @@
         "tool_paths": attr.string_dict(),
         "toolchain_identifier": attr.string(mandatory = True),
         "unfiltered_compile_flags": attr.string_list(),
+        "_xcode_config": attr.label(default = configuration_field(
+            fragment = "apple",
+            name = "xcode_config_label",
+        )),
     },
+    fragments = ["apple", "cpp"],
     provides = [CcToolchainConfigInfo],
 )
diff --git a/cc/private/toolchain/validate_static_library.sh.tpl b/cc/private/toolchain/validate_static_library.sh.tpl
new file mode 100755
index 0000000..d769408
--- /dev/null
+++ b/cc/private/toolchain/validate_static_library.sh.tpl
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+#
+# Copyright 2023 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+set -euo pipefail
+
+# Find all duplicate symbols in the given static library:
+# 1. Use nm to list all global symbols in the library in POSIX format:
+#    libstatic.a[my_object.o]: my_function T 1234 abcd
+# 2. Use sed to transform the output to a format that can be sorted by symbol
+#    name and is readable by humans:
+#    my_object.o: T my_function
+#    By using the `t` and `d` commands, lines for symbols of type U (undefined)
+#    as well as V and W (weak) and their local lowercase variants are removed.
+# 3. Use sort to sort the lines by symbol name.
+# 4. Use uniq to only keep the lines corresponding to duplicate symbols.
+# 5. Use c++filt to demangle the symbol names.
+#    c++filt is applied to the duplicated symbols instead of using the -C flag
+#    of nm because it is not in POSIX and demangled names may not be unique
+#    (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=35201).
+DUPLICATE_SYMBOLS=$(
+  "%{nm}" -A -g -P %{nm_extra_args} "$1" |
+  sed -E -e 's/.*\[([^][]+)\]: (.+) ([A-TX-Z]) [a-f0-9]+ [a-f0-9]+/\1: \3 \2/g' -e t -e d |
+  LC_ALL=C sort -k 3 |
+  LC_ALL=C uniq -D -f 2 |
+  "%{c++filt}")
+if [[ -n "$DUPLICATE_SYMBOLS" ]]; then
+  >&2 echo "Duplicate symbols found in $1:"
+  >&2 echo "$DUPLICATE_SYMBOLS"
+  exit 1
+else
+  touch "$2"
+fi
diff --git a/cc/private/toolchain/vc_installation_error.bat.tpl b/cc/private/toolchain/vc_installation_error.bat.tpl
index 9cdd658..2285422 100644
--- a/cc/private/toolchain/vc_installation_error.bat.tpl
+++ b/cc/private/toolchain/vc_installation_error.bat.tpl
@@ -18,7 +18,7 @@
 echo The target you are compiling requires Visual C++ build tools. 1>&2
 echo Bazel couldn't find a valid Visual C++ build tools installation on your machine. 1>&2
 %{vc_error_message}
-echo Please check your installation following https://docs.bazel.build/versions/main/windows.html#using 1>&2
+echo Please check your installation following https://bazel.build/docs/windows#using 1>&2
 echo. 1>&2
 
 exit /b 1
diff --git a/cc/private/toolchain/windows_cc_configure.bzl b/cc/private/toolchain/windows_cc_configure.bzl
index 598d4b2..bd87d41 100644
--- a/cc/private/toolchain/windows_cc_configure.bzl
+++ b/cc/private/toolchain/windows_cc_configure.bzl
@@ -25,12 +25,35 @@
     "write_builtin_include_directory_paths",
 )
 
+_targets_archs = {"arm": "amd64_arm", "arm64": "amd64_arm64", "x64": "amd64", "x86": "amd64_x86"}
+_targets_lib_folder = {"arm": "arm", "arm64": "arm64", "x86": ""}
+
+def _lookup_env_var(env, name, default = None):
+    """Lookup environment variable case-insensitve.
+
+    If a matching (case-insensitive) entry is found in the env dict both
+    the key and the value are returned. The returned key might differ from
+    name in casing.
+
+    If a matching key was found its value is returned otherwise
+    the default is returned.
+
+    Return a (key, value) tuple"""
+    for key, value in env.items():
+        if name.lower() == key.lower():
+            return (key, value)
+    return (name, default)
+
+def _get_env_var(repository_ctx, name, default = None):
+    """Returns a value from an environment variable."""
+    return _lookup_env_var(repository_ctx.os.environ, name, default)[1]
+
 def _get_path_env_var(repository_ctx, name):
     """Returns a path from an environment variable.
 
     Removes quotes, replaces '/' with '\', and strips trailing '\'s."""
-    if name in repository_ctx.os.environ:
-        value = repository_ctx.os.environ[name]
+    value = _get_env_var(repository_ctx, name)
+    if value != None:
         if value[0] == "\"":
             if len(value) == 1 or value[-1] != "\"":
                 auto_configure_fail("'%s' environment variable has no trailing quote" % name)
@@ -39,9 +62,7 @@
             value = value.replace("/", "\\")
         if value[-1] == "\\":
             value = value.rstrip("\\")
-        return value
-    else:
-        return None
+    return value
 
 def _get_temp_env(repository_ctx):
     """Returns the value of TMP, or TEMP, or if both undefined then C:\\Windows."""
@@ -72,7 +93,7 @@
     tool_bin_path = tool_path_prefix + "/bin"
     tool_path = {}
 
-    for tool in ["ar", "compat-ld", "cpp", "dwp", "gcc", "gcov", "ld", "nm", "objcopy", "objdump", "strip"]:
+    for tool in ["ar", "cpp", "dwp", "gcc", "gcov", "ld", "nm", "objcopy", "objdump", "strip"]:
         if msys_root:
             tool_path[tool] = tool_bin_path + "/" + tool
         else:
@@ -94,13 +115,19 @@
 
 def _add_system_root(repository_ctx, env):
     """Running VCVARSALL.BAT and VCVARSQUERYREGISTRY.BAT need %SYSTEMROOT%\\\\system32 in PATH."""
-    if "PATH" not in env:
-        env["PATH"] = ""
-    env["PATH"] = env["PATH"] + ";" + _get_system_root(repository_ctx) + "\\system32"
+    env_key, env_value = _lookup_env_var(env, "PATH", default = "")
+    env[env_key] = env_value + ";" + _get_system_root(repository_ctx) + "\\system32"
     return env
 
-def _find_vc_path(repository_ctx):
-    """Find Visual C++ build tools install path. Doesn't %-escape the result."""
+def find_vc_path(repository_ctx):
+    """Find Visual C++ build tools install path. Doesn't %-escape the result.
+
+    Args:
+        repository_ctx: The repository context.
+
+    Returns:
+        The path to the Visual C++ build tools installation.
+    """
 
     # 1. Check if BAZEL_VC or BAZEL_VS is already set by user.
     bazel_vc = _get_path_env_var(repository_ctx, "BAZEL_VC")
@@ -136,7 +163,27 @@
         " installed.",
     )
 
-    # 2. Check if VS%VS_VERSION%COMNTOOLS is set, if true then try to find and use
+    # 2. Use vswhere to locate all Visual Studio installations
+    program_files_dir = _get_path_env_var(repository_ctx, "PROGRAMFILES(X86)")
+    if not program_files_dir:
+        program_files_dir = "C:\\Program Files (x86)"
+        auto_configure_warning_maybe(
+            repository_ctx,
+            "'PROGRAMFILES(X86)' environment variable is not set, using '%s' as default" % program_files_dir,
+        )
+
+    vswhere_binary = program_files_dir + "\\Microsoft Visual Studio\\Installer\\vswhere.exe"
+    if repository_ctx.path(vswhere_binary).exists:
+        result = repository_ctx.execute([vswhere_binary, "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", "-property", "installationPath", "-latest"])
+        auto_configure_warning_maybe(repository_ctx, "vswhere query result:\n\nSTDOUT(start)\n%s\nSTDOUT(end)\nSTDERR(start):\n%s\nSTDERR(end)\n" %
+                                                     (result.stdout, result.stderr))
+        installation_path = result.stdout.strip()
+        if not result.stderr and installation_path:
+            vc_dir = installation_path + "\\VC"
+            auto_configure_warning_maybe(repository_ctx, "Visual C++ build tools found at %s" % vc_dir)
+            return vc_dir
+
+    # 3. Check if VS%VS_VERSION%COMNTOOLS is set, if true then try to find and use
     # vcvarsqueryregistry.bat / VsDevCmd.bat to detect VC++.
     auto_configure_warning_maybe(repository_ctx, "Looking for VS%VERSION%COMNTOOLS environment variables, " +
                                                  "eg. VS140COMNTOOLS")
@@ -149,15 +196,16 @@
         ("VS100COMNTOOLS", "vcvarsqueryregistry.bat"),
         ("VS90COMNTOOLS", "vcvarsqueryregistry.bat"),
     ]:
-        if vscommontools_env not in repository_ctx.os.environ:
+        path = _get_path_env_var(repository_ctx, vscommontools_env)
+        if path == None:
             continue
-        script = _get_path_env_var(repository_ctx, vscommontools_env) + "\\" + script
+        script = path + "\\" + script
         if not repository_ctx.path(script).exists:
             continue
         repository_ctx.file(
             "get_vc_dir.bat",
             "@echo off\n" +
-            "call \"" + script + "\"\n" +
+            "call \"" + script + "\" > NUL\n" +
             "echo %VCINSTALLDIR%",
             True,
         )
@@ -167,9 +215,8 @@
         auto_configure_warning_maybe(repository_ctx, "Visual C++ build tools found at %s" % vc_dir)
         return vc_dir
 
-    # 3. User might have purged all environment variables. If so, look for Visual C++ in registry.
+    # 4. User might have purged all environment variables. If so, look for Visual C++ in registry.
     # Works for Visual Studio 2017 and older. (Does not work for Visual Studio 2019 Preview.)
-    # TODO(laszlocsomor): check if "16.0" also has this registry key, after VS 2019 is released.
     auto_configure_warning_maybe(repository_ctx, "Looking for Visual C++ through registry")
     reg_binary = _get_system_root(repository_ctx) + "\\system32\\reg.exe"
     vc_dir = None
@@ -189,25 +236,13 @@
         auto_configure_warning_maybe(repository_ctx, "Visual C++ build tools found at %s" % vc_dir)
         return vc_dir
 
-    # 4. Check default directories for VC installation
+    # 5. Check default directories for VC installation
     auto_configure_warning_maybe(repository_ctx, "Looking for default Visual C++ installation directory")
-    program_files_dir = _get_path_env_var(repository_ctx, "PROGRAMFILES(X86)")
-    if not program_files_dir:
-        program_files_dir = "C:\\Program Files (x86)"
-        auto_configure_warning_maybe(
-            repository_ctx,
-            "'PROGRAMFILES(X86)' environment variable is not set, using '%s' as default" % program_files_dir,
-        )
     for path in [
-        "Microsoft Visual Studio\\2019\\Preview\\VC",
-        "Microsoft Visual Studio\\2019\\BuildTools\\VC",
-        "Microsoft Visual Studio\\2019\\Community\\VC",
-        "Microsoft Visual Studio\\2019\\Professional\\VC",
-        "Microsoft Visual Studio\\2019\\Enterprise\\VC",
-        "Microsoft Visual Studio\\2017\\BuildTools\\VC",
-        "Microsoft Visual Studio\\2017\\Community\\VC",
-        "Microsoft Visual Studio\\2017\\Professional\\VC",
-        "Microsoft Visual Studio\\2017\\Enterprise\\VC",
+        "Microsoft Visual Studio\\%s\\%s\\VC" % (year, edition)
+        for year in (2022, 2019, 2017)
+        for edition in ("Preview", "BuildTools", "Community", "Professional", "Enterprise")
+    ] + [
         "Microsoft Visual Studio 14.0\\VC",
     ]:
         path = program_files_dir + "\\" + path
@@ -221,18 +256,22 @@
     auto_configure_warning_maybe(repository_ctx, "Visual C++ build tools found at %s" % vc_dir)
     return vc_dir
 
-def _is_vs_2017_or_2019(vc_path):
-    """Check if the installed VS version is Visual Studio 2017."""
+def _is_vs_2017_or_newer(repository_ctx, vc_path):
+    """Check if the installed VS version is Visual Studio 2017 or newer."""
 
-    # In VS 2017 and 2019, the location of VC is like:
-    # C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\
-    # In VS 2015 or older version, it is like:
-    # C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\
-    return vc_path.find("2017") != -1 or vc_path.find("2019") != -1
+    # For VS 2017 and later, a `Tools` directory should exist under `BAZEL_VC`
+    return repository_ctx.path(vc_path).get_child("Tools").exists
+
+def _is_msbuildtools(vc_path):
+    """Check if the installed VC version is from MSBuildTools."""
+
+    # In MSBuildTools (usually container setup), the location of VC is like:
+    # C:\BuildTools\MSBuild\Microsoft\VC
+    return vc_path.find("BuildTools") != -1 and vc_path.find("MSBuild") != -1
 
 def _find_vcvars_bat_script(repository_ctx, vc_path):
     """Find batch script to set up environment variables for VC. Doesn't %-escape the result."""
-    if _is_vs_2017_or_2019(vc_path):
+    if _is_vs_2017_or_newer(repository_ctx, vc_path):
         vcvars_script = vc_path + "\\Auxiliary\\Build\\VCVARSALL.BAT"
     else:
         vcvars_script = vc_path + "\\VCVARSALL.BAT"
@@ -250,17 +289,49 @@
 
 def _is_support_winsdk_selection(repository_ctx, vc_path):
     """Windows SDK selection is supported with VC 2017 / 2019 or with full VS 2015 installation."""
-    if _is_vs_2017_or_2019(vc_path):
+    if _is_vs_2017_or_newer(repository_ctx, vc_path):
         return True
 
     # By checking the source code of VCVARSALL.BAT in VC 2015, we know that
     # when devenv.exe or wdexpress.exe exists, VCVARSALL.BAT supports Windows SDK selection.
-    vc_common_ide = repository_ctx.path(vc_path).dirname.get_child("Common7").get_child("IDE")
+    vc_common_ide = repository_ctx.path(vc_path).dirname.get_child("Common7", "IDE")
     for tool in ["devenv.exe", "wdexpress.exe"]:
         if vc_common_ide.get_child(tool).exists:
             return True
     return False
 
+def _get_vc_env_vars(repository_ctx, vc_path, msvc_vars_x64, target_arch):
+    """Derive the environment variables set of a given target architecture from the environment variables of the x64 target.
+
+       This is done to avoid running VCVARSALL.BAT script for every target architecture.
+
+    Args:
+        repository_ctx: the repository_ctx object
+        vc_path: Visual C++ root directory
+        msvc_vars_x64: values of MSVC toolchain including the environment variables for x64 target architecture
+        target_arch: the target architecture to get its environment variables
+
+    Returns:
+        dictionary of envvars
+    """
+    env = {}
+    if _is_vs_2017_or_newer(repository_ctx, vc_path):
+        lib = msvc_vars_x64["%{msvc_env_lib_x64}"]
+        full_version = _get_vc_full_version(repository_ctx, vc_path)
+        tools_path = "%s\\Tools\\MSVC\\%s\\bin\\HostX64\\%s" % (vc_path, full_version, target_arch)
+
+        # For native windows(10) on arm64 builds host toolchain runs in an emulated x86 environment
+        if not repository_ctx.path(tools_path).exists:
+            tools_path = "%s\\Tools\\MSVC\\%s\\bin\\HostX86\\%s" % (vc_path, full_version, target_arch)
+    else:
+        lib = msvc_vars_x64["%{msvc_env_lib_x64}"].replace("amd64", _targets_lib_folder[target_arch])
+        tools_path = vc_path + "\\bin\\" + _targets_archs[target_arch]
+
+    env["INCLUDE"] = msvc_vars_x64["%{msvc_env_include_x64}"]
+    env["LIB"] = lib.replace("x64", target_arch)
+    env["PATH"] = escape_string(tools_path.replace("\\", "\\\\")) + ";" + msvc_vars_x64["%{msvc_env_path_x64}"]
+    return env
+
 def setup_vc_env_vars(repository_ctx, vc_path, envvars = [], allow_empty = False, escape = True):
     """Get environment variables set by VCVARSALL.BAT script. Doesn't %-escape the result!
 
@@ -292,7 +363,7 @@
 
     # Get VC version set by user. Only supports VC 2017 & 2019.
     vcvars_ver = ""
-    if _is_vs_2017_or_2019(vc_path):
+    if _is_vs_2017_or_newer(repository_ctx, vc_path):
         full_version = _get_vc_full_version(repository_ctx, vc_path)
 
         # Because VCVARSALL.BAT is from the latest VC installed, so we check if the latest
@@ -314,6 +385,7 @@
     for env in envs:
         key, value = env.split("=", 1)
         env_map[key] = escape_string(value.replace("\\", "\\\\")) if escape else value
+
     if not allow_empty:
         _check_env_vars(env_map, cmd, expected = envvars)
     return env_map
@@ -347,48 +419,84 @@
     version_list = sorted(version_list)
     latest_version = version_list[-1][1]
 
-    auto_configure_warning_maybe(repository_ctx, "Found the following VC verisons:\n%s\n\nChoosing the latest version = %s" % ("\n".join(versions), latest_version))
+    auto_configure_warning_maybe(repository_ctx, "Found the following VC versions:\n%s\n\nChoosing the latest version = %s" % ("\n".join(versions), latest_version))
     return latest_version
 
 def _get_vc_full_version(repository_ctx, vc_path):
     """Return the value of BAZEL_VC_FULL_VERSION if defined, otherwise the latest version."""
-    if "BAZEL_VC_FULL_VERSION" in repository_ctx.os.environ:
-        return repository_ctx.os.environ["BAZEL_VC_FULL_VERSION"]
+    version = _get_env_var(repository_ctx, "BAZEL_VC_FULL_VERSION")
+    if version != None:
+        return version
     return _get_latest_subversion(repository_ctx, vc_path)
 
 def _get_winsdk_full_version(repository_ctx):
     """Return the value of BAZEL_WINSDK_FULL_VERSION if defined, otherwise an empty string."""
-    return repository_ctx.os.environ.get("BAZEL_WINSDK_FULL_VERSION", default = "")
+    return _get_env_var(repository_ctx, "BAZEL_WINSDK_FULL_VERSION", default = "")
 
-def _find_msvc_tool(repository_ctx, vc_path, tool):
-    """Find the exact path of a specific build tool in MSVC. Doesn't %-escape the result."""
+def _find_msvc_tools(repository_ctx, vc_path, target_arch = "x64"):
+    """Find the exact paths of the build tools in MSVC for the given target. Doesn't %-escape the result."""
+    build_tools_paths = {}
+    tools = _get_target_tools(target_arch)
+    for tool_name in tools:
+        build_tools_paths[tool_name] = find_msvc_tool(repository_ctx, vc_path, tools[tool_name], target_arch)
+    return build_tools_paths
+
+def find_msvc_tool(repository_ctx, vc_path, tool, target_arch = "x64"):
+    """Find the exact path of a specific build tool in MSVC. Doesn't %-escape the result.
+
+    Args:
+        repository_ctx: The repository context.
+        vc_path: Visual C++ root directory.
+        tool: The name of the tool to find.
+        target_arch: The target architecture (default is "x64").
+
+    Returns:
+        The exact path of the specified build tool in MSVC, or None if not found.
+    """
     tool_path = None
-    if _is_vs_2017_or_2019(vc_path):
+    if _is_vs_2017_or_newer(repository_ctx, vc_path) or _is_msbuildtools(vc_path):
         full_version = _get_vc_full_version(repository_ctx, vc_path)
         if full_version:
-            tool_path = "%s\\Tools\\MSVC\\%s\\bin\\HostX64\\x64\\%s" % (vc_path, full_version, tool)
+            tool_path = "%s\\Tools\\MSVC\\%s\\bin\\HostX64\\%s\\%s" % (vc_path, full_version, target_arch, tool)
+
+            # For native windows(10) on arm64 builds host toolchain runs in an emulated x86 environment
+            if not repository_ctx.path(tool_path).exists:
+                tool_path = "%s\\Tools\\MSVC\\%s\\bin\\HostX86\\%s\\%s" % (vc_path, full_version, target_arch, tool)
     else:
         # For VS 2015 and older version, the tools are under:
         # C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64
-        tool_path = vc_path + "\\bin\\amd64\\" + tool
+        tool_path = vc_path + "\\bin\\" + _targets_archs[target_arch] + "\\" + tool
 
     if not tool_path or not repository_ctx.path(tool_path).exists:
         return None
 
     return tool_path.replace("\\", "/")
 
-def _find_missing_vc_tools(repository_ctx, vc_path):
-    """Check if any required tool is missing under given VC path."""
+def _find_missing_vc_tools(repository_ctx, vc_path, target_arch = "x64"):
+    """Check if any required tool for the given target architecture is missing under given VC path."""
     missing_tools = []
     if not _find_vcvars_bat_script(repository_ctx, vc_path):
         missing_tools.append("VCVARSALL.BAT")
 
-    for tool in ["cl.exe", "link.exe", "lib.exe", "ml64.exe"]:
-        if not _find_msvc_tool(repository_ctx, vc_path, tool):
-            missing_tools.append(tool)
-
+    tools = _get_target_tools(target_arch)
+    for tool_name in tools:
+        if not find_msvc_tool(repository_ctx, vc_path, tools[tool_name], target_arch):
+            missing_tools.append(tools[tool_name])
     return missing_tools
 
+def _get_target_tools(target):
+    """Return a list of required tools names and their filenames for a certain target."""
+    tools = {
+        "arm": {"CL": "cl.exe", "DUMPBIN": "dumpbin.exe", "LIB": "lib.exe", "LINK": "link.exe"},
+        "arm64": {"CL": "cl.exe", "DUMPBIN": "dumpbin.exe", "LIB": "lib.exe", "LINK": "link.exe"},
+        "x64": {"CL": "cl.exe", "DUMPBIN": "dumpbin.exe", "LIB": "lib.exe", "LINK": "link.exe", "ML": "ml64.exe"},
+        "x86": {"CL": "cl.exe", "DUMPBIN": "dumpbin.exe", "LIB": "lib.exe", "LINK": "link.exe", "ML": "ml.exe"},
+    }
+    if tools.get(target) == None:
+        auto_configure_fail("Target architecture %s is not recognized" % target)
+
+    return tools.get(target)
+
 def _is_support_debug_fastlink(repository_ctx, linker):
     """Run linker alone to see if it supports /DEBUG:FASTLINK."""
     if _use_clang_cl(repository_ctx):
@@ -397,8 +505,37 @@
     result = execute(repository_ctx, [linker], expect_failure = True)
     return result.find("/DEBUG[:{FASTLINK|FULL|NONE}]") != -1
 
-def _find_llvm_path(repository_ctx):
-    """Find LLVM install path."""
+def _is_support_parse_showincludes(repository_ctx, cl, env):
+    repository_ctx.file(
+        "main.cpp",
+        "#include \"bazel_showincludes.h\"\nint main(){}\n",
+    )
+    repository_ctx.file(
+        "bazel_showincludes.h",
+        "\n",
+    )
+    result = execute(
+        repository_ctx,
+        [cl, "/nologo", "/showIncludes", "/c", "main.cpp", "/out", "main.exe", "/Fo", "main.obj"],
+        # Attempt to force English language. This may fail if the language pack isn't installed.
+        environment = env | {"VSLANG": "1033"},
+    )
+    for file in ["main.cpp", "bazel_showincludes.h", "main.exe", "main.obj"]:
+        execute(repository_ctx, ["cmd", "/C", "del", file], expect_empty_output = True)
+    return any([
+        line.startswith("Note: including file:") and line.endswith("bazel_showincludes.h")
+        for line in result.split("\n")
+    ])
+
+def find_llvm_path(repository_ctx):
+    """Find LLVM install path.
+
+    Args:
+        repository_ctx: The repository context.
+
+    Returns:
+        The path to the LLVM installation, or None if not found.
+    """
 
     # 1. Check if BAZEL_LLVM is already set by user.
     bazel_llvm = _get_path_env_var(repository_ctx, "BAZEL_LLVM")
@@ -443,8 +580,17 @@
     auto_configure_warning_maybe(repository_ctx, "LLVM installation found at %s" % llvm_dir)
     return llvm_dir
 
-def _find_llvm_tool(repository_ctx, llvm_path, tool):
-    """Find the exact path of a specific build tool in LLVM. Doesn't %-escape the result."""
+def find_llvm_tool(repository_ctx, llvm_path, tool):
+    """Find the exact path of a specific build tool in LLVM. Doesn't %-escape the result.
+
+    Args:
+        repository_ctx: The repository context.
+        llvm_path: The path to the LLVM installation.
+        tool: The name of the tool to find.
+
+    Returns:
+        The exact path of the specified build tool in LLVM, or None if not found.
+    """
     tool_path = llvm_path + "\\bin\\" + tool
 
     if not repository_ctx.path(tool_path).exists:
@@ -454,24 +600,37 @@
 
 def _use_clang_cl(repository_ctx):
     """Returns True if USE_CLANG_CL is set to 1."""
-    return repository_ctx.os.environ.get("USE_CLANG_CL", default = "0") == "1"
+    return _get_env_var(repository_ctx, "USE_CLANG_CL", default = "0") == "1"
 
 def _find_missing_llvm_tools(repository_ctx, llvm_path):
     """Check if any required tool is missing under given LLVM path."""
     missing_tools = []
     for tool in ["clang-cl.exe", "lld-link.exe", "llvm-lib.exe"]:
-        if not _find_llvm_tool(repository_ctx, llvm_path, tool):
+        if not find_llvm_tool(repository_ctx, llvm_path, tool):
             missing_tools.append(tool)
 
     return missing_tools
 
 def _get_clang_version(repository_ctx, clang_cl):
     result = repository_ctx.execute([clang_cl, "-v"])
-    if result.return_code != 0:
-        auto_configure_fail("Failed to get clang version by running \"%s -v\"" % clang_cl)
+    first_line = result.stderr.strip().splitlines()[0].strip()
 
-    # Stderr should look like "clang version X.X.X ..."
-    return result.stderr.splitlines()[0].split(" ")[2]
+    # The first line of stderr should look like "[vendor ]clang version X.X.X"
+    if result.return_code != 0 or first_line.find("clang version ") == -1:
+        auto_configure_fail("Failed to get clang version by running \"%s -v\"" % clang_cl)
+    return first_line.split(" ")[-1]
+
+def _get_clang_dir(repository_ctx, llvm_path, clang_version):
+    """Get the clang installation directory."""
+
+    # The clang_version string format is "X.X.X"
+    clang_dir = llvm_path + "\\lib\\clang\\" + clang_version
+    if repository_ctx.path(clang_dir).exists:
+        return clang_dir
+
+    # Clang 16 changed the install path to use just the major number.
+    clang_major_version = clang_version.split(".")[0]
+    return llvm_path + "\\lib\\clang\\" + clang_major_version
 
 def _get_msys_mingw_vars(repository_ctx):
     """Get the variables we need to populate the msys/mingw toolchains."""
@@ -488,29 +647,31 @@
     }
     return msys_mingw_vars
 
-def _get_msvc_vars(repository_ctx, paths):
+def _get_msvc_vars(repository_ctx, paths, target_arch = "x64", msvc_vars_x64 = None):
     """Get the variables we need to populate the MSVC toolchains."""
     msvc_vars = dict()
-    vc_path = _find_vc_path(repository_ctx)
+    vc_path = find_vc_path(repository_ctx)
     missing_tools = None
+
     if not vc_path:
         repository_ctx.template(
-            "vc_installation_error.bat",
+            "vc_installation_error_" + target_arch + ".bat",
             paths["@rules_cc//cc/private/toolchain:vc_installation_error.bat.tpl"],
             {"%{vc_error_message}": ""},
         )
     else:
-        missing_tools = _find_missing_vc_tools(repository_ctx, vc_path)
+        missing_tools = _find_missing_vc_tools(repository_ctx, vc_path, target_arch)
         if missing_tools:
             message = "\r\n".join([
                 "echo. 1>&2",
                 "echo Visual C++ build tools seems to be installed at %s 1>&2" % vc_path,
                 "echo But Bazel can't find the following tools: 1>&2",
                 "echo     %s 1>&2" % ", ".join(missing_tools),
+                "echo for %s target architecture 1>&2" % target_arch,
                 "echo. 1>&2",
             ])
             repository_ctx.template(
-                "vc_installation_error.bat",
+                "vc_installation_error_" + target_arch + ".bat",
                 paths["@rules_cc//cc/private/toolchain:vc_installation_error.bat.tpl"],
                 {"%{vc_error_message}": message},
             )
@@ -518,82 +679,92 @@
     if not vc_path or missing_tools:
         write_builtin_include_directory_paths(repository_ctx, "msvc", [], file_suffix = "_msvc")
         msvc_vars = {
-            "%{dbg_mode_debug_flag}": "/DEBUG",
-            "%{fastbuild_mode_debug_flag}": "/DEBUG",
-            "%{msvc_cl_path}": "vc_installation_error.bat",
-            "%{msvc_cxx_builtin_include_directories}": "",
-            "%{msvc_env_include}": "msvc_not_found",
-            "%{msvc_env_lib}": "msvc_not_found",
-            "%{msvc_env_path}": "msvc_not_found",
-            "%{msvc_env_tmp}": "msvc_not_found",
-            "%{msvc_lib_path}": "vc_installation_error.bat",
-            "%{msvc_link_path}": "vc_installation_error.bat",
-            "%{msvc_ml_path}": "vc_installation_error.bat",
+            "%{msvc_env_tmp_" + target_arch + "}": "msvc_not_found",
+            "%{msvc_env_include_" + target_arch + "}": "msvc_not_found",
+            "%{msvc_cxx_builtin_include_directories_" + target_arch + "}": "",
+            "%{msvc_env_path_" + target_arch + "}": "msvc_not_found",
+            "%{msvc_env_lib_" + target_arch + "}": "msvc_not_found",
+            "%{msvc_cl_path_" + target_arch + "}": "vc_installation_error_" + target_arch + ".bat",
+            "%{msvc_ml_path_" + target_arch + "}": "vc_installation_error_" + target_arch + ".bat",
+            "%{msvc_link_path_" + target_arch + "}": "vc_installation_error_" + target_arch + ".bat",
+            "%{msvc_lib_path_" + target_arch + "}": "vc_installation_error_" + target_arch + ".bat",
+            "%{dbg_mode_debug_flag_" + target_arch + "}": "/DEBUG",
+            "%{fastbuild_mode_debug_flag_" + target_arch + "}": "/DEBUG",
+            "%{msvc_parse_showincludes_" + target_arch + "}": repr(False),
         }
         return msvc_vars
 
-    env = setup_vc_env_vars(repository_ctx, vc_path)
-    escaped_paths = escape_string(env["PATH"])
-    escaped_include_paths = escape_string(env["INCLUDE"])
-    escaped_lib_paths = escape_string(env["LIB"])
+    if msvc_vars_x64:
+        env = _get_vc_env_vars(repository_ctx, vc_path, msvc_vars_x64, target_arch)
+    else:
+        env = setup_vc_env_vars(repository_ctx, vc_path)
     escaped_tmp_dir = escape_string(_get_temp_env(repository_ctx).replace("\\", "\\\\"))
+    escaped_include_paths = escape_string(env["INCLUDE"])
 
+    build_tools = {}
     llvm_path = ""
     if _use_clang_cl(repository_ctx):
-        llvm_path = _find_llvm_path(repository_ctx)
+        llvm_path = find_llvm_path(repository_ctx)
         if not llvm_path:
             auto_configure_fail("\nUSE_CLANG_CL is set to 1, but Bazel cannot find Clang installation on your system.\n" +
                                 "Please install Clang via http://releases.llvm.org/download.html\n")
-        cl_path = _find_llvm_tool(repository_ctx, llvm_path, "clang-cl.exe")
-        link_path = _find_llvm_tool(repository_ctx, llvm_path, "lld-link.exe")
-        if not link_path:
-            link_path = _find_msvc_tool(repository_ctx, vc_path, "link.exe")
-        lib_path = _find_llvm_tool(repository_ctx, llvm_path, "llvm-lib.exe")
-        if not lib_path:
-            lib_path = _find_msvc_tool(repository_ctx, vc_path, "lib.exe")
+
+        build_tools["CL"] = find_llvm_tool(repository_ctx, llvm_path, "clang-cl.exe")
+        build_tools["ML"] = find_msvc_tool(repository_ctx, vc_path, "ml64.exe", "x64")
+        build_tools["LINK"] = find_llvm_tool(repository_ctx, llvm_path, "lld-link.exe")
+        if not build_tools["LINK"]:
+            build_tools["LINK"] = find_msvc_tool(repository_ctx, vc_path, "link.exe", "x64")
+        build_tools["LIB"] = find_llvm_tool(repository_ctx, llvm_path, "llvm-lib.exe")
+        if not build_tools["LIB"]:
+            build_tools["LIB"] = find_msvc_tool(repository_ctx, vc_path, "lib.exe", "x64")
     else:
-        cl_path = _find_msvc_tool(repository_ctx, vc_path, "cl.exe")
-        link_path = _find_msvc_tool(repository_ctx, vc_path, "link.exe")
-        lib_path = _find_msvc_tool(repository_ctx, vc_path, "lib.exe")
+        build_tools = _find_msvc_tools(repository_ctx, vc_path, target_arch)
 
-    msvc_ml_path = _find_msvc_tool(repository_ctx, vc_path, "ml64.exe")
     escaped_cxx_include_directories = []
-
     for path in escaped_include_paths.split(";"):
         if path:
             escaped_cxx_include_directories.append("\"%s\"" % path)
     if llvm_path:
-        clang_version = _get_clang_version(repository_ctx, cl_path)
-        clang_dir = llvm_path + "\\lib\\clang\\" + clang_version
+        clang_version = _get_clang_version(repository_ctx, build_tools["CL"])
+        clang_dir = _get_clang_dir(repository_ctx, llvm_path, clang_version)
         clang_include_path = (clang_dir + "\\include").replace("\\", "\\\\")
         escaped_cxx_include_directories.append("\"%s\"" % clang_include_path)
         clang_lib_path = (clang_dir + "\\lib\\windows").replace("\\", "\\\\")
-        escaped_lib_paths = escaped_lib_paths + ";" + clang_lib_path
+        env["LIB"] = escape_string(env["LIB"]) + ";" + clang_lib_path
 
-    support_debug_fastlink = _is_support_debug_fastlink(repository_ctx, link_path)
-
+    support_debug_fastlink = _is_support_debug_fastlink(repository_ctx, build_tools["LINK"])
     write_builtin_include_directory_paths(repository_ctx, "msvc", escaped_cxx_include_directories, file_suffix = "_msvc")
+
+    support_parse_showincludes = _is_support_parse_showincludes(repository_ctx, build_tools["CL"], env)
+    if not support_parse_showincludes:
+        auto_configure_warning("""
+Header pruning has been disabled since Bazel failed to recognize the output of /showIncludes.
+This can result in unnecessary recompilation.
+Fix this by installing the English language pack for the Visual Studio installation at {} and run 'bazel sync --configure'.""".format(vc_path))
+
     msvc_vars = {
-        "%{dbg_mode_debug_flag}": "/DEBUG:FULL" if support_debug_fastlink else "/DEBUG",
-        "%{fastbuild_mode_debug_flag}": "/DEBUG:FASTLINK" if support_debug_fastlink else "/DEBUG",
-        "%{msvc_cl_path}": cl_path,
-        "%{msvc_cxx_builtin_include_directories}": "        " + ",\n        ".join(escaped_cxx_include_directories),
-        "%{msvc_env_include}": escaped_include_paths,
-        "%{msvc_env_lib}": escaped_lib_paths,
-        "%{msvc_env_path}": escaped_paths,
-        "%{msvc_env_tmp}": escaped_tmp_dir,
-        "%{msvc_lib_path}": lib_path,
-        "%{msvc_link_path}": link_path,
-        "%{msvc_ml_path}": msvc_ml_path,
+        "%{msvc_env_tmp_" + target_arch + "}": escaped_tmp_dir,
+        "%{msvc_env_include_" + target_arch + "}": escaped_include_paths,
+        "%{msvc_cxx_builtin_include_directories_" + target_arch + "}": "        " + ",\n        ".join(escaped_cxx_include_directories),
+        "%{msvc_env_path_" + target_arch + "}": escape_string(env["PATH"]),
+        "%{msvc_env_lib_" + target_arch + "}": escape_string(env["LIB"]),
+        "%{msvc_cl_path_" + target_arch + "}": build_tools["CL"],
+        "%{msvc_ml_path_" + target_arch + "}": build_tools.get("ML", "msvc_arm_toolchain_does_not_support_ml"),
+        "%{msvc_link_path_" + target_arch + "}": build_tools["LINK"],
+        "%{msvc_lib_path_" + target_arch + "}": build_tools["LIB"],
+        "%{msvc_dumpbin_path_" + target_arch + "}": build_tools["DUMPBIN"],
+        "%{msvc_parse_showincludes_" + target_arch + "}": repr(support_parse_showincludes),
+        "%{dbg_mode_debug_flag_" + target_arch + "}": "/DEBUG:FULL" if support_debug_fastlink else "/DEBUG",
+        "%{fastbuild_mode_debug_flag_" + target_arch + "}": "/DEBUG:FASTLINK" if support_debug_fastlink else "/DEBUG",
     }
     return msvc_vars
 
-def _get_clang_cl_vars(repository_ctx, paths, msvc_vars):
+def _get_clang_cl_vars(repository_ctx, paths, msvc_vars, target_arch):
     """Get the variables we need to populate the clang-cl toolchains."""
-    llvm_path = _find_llvm_path(repository_ctx)
+    llvm_path = find_llvm_path(repository_ctx)
     error_script = None
-    if msvc_vars["%{msvc_cl_path}"] == "vc_installation_error.bat":
-        error_script = "vc_installation_error.bat"
+    if msvc_vars["%{msvc_cl_path_" + target_arch + "}"] == "vc_installation_error_{}.bat".format(target_arch):
+        error_script = "vc_installation_error_{}.bat".format(target_arch)
     elif not llvm_path:
         repository_ctx.template(
             "clang_installation_error.bat",
@@ -621,52 +792,69 @@
     if error_script:
         write_builtin_include_directory_paths(repository_ctx, "clang-cl", [], file_suffix = "_clangcl")
         clang_cl_vars = {
-            "%{clang_cl_cl_path}": error_script,
-            "%{clang_cl_cxx_builtin_include_directories}": "",
-            "%{clang_cl_dbg_mode_debug_flag}": "/DEBUG",
-            "%{clang_cl_env_include}": "clang_cl_not_found",
-            "%{clang_cl_env_lib}": "clang_cl_not_found",
-            "%{clang_cl_env_path}": "clang_cl_not_found",
-            "%{clang_cl_env_tmp}": "clang_cl_not_found",
-            "%{clang_cl_fastbuild_mode_debug_flag}": "/DEBUG",
-            "%{clang_cl_lib_path}": error_script,
-            "%{clang_cl_link_path}": error_script,
-            "%{clang_cl_ml_path}": error_script,
+            "%{clang_cl_env_tmp_" + target_arch + "}": "clang_cl_not_found",
+            "%{clang_cl_env_path_" + target_arch + "}": "clang_cl_not_found",
+            "%{clang_cl_env_include_" + target_arch + "}": "clang_cl_not_found",
+            "%{clang_cl_env_lib_" + target_arch + "}": "clang_cl_not_found",
+            "%{clang_cl_cl_path_" + target_arch + "}": error_script,
+            "%{clang_cl_link_path_" + target_arch + "}": error_script,
+            "%{clang_cl_lib_path_" + target_arch + "}": error_script,
+            "%{clang_cl_ml_path_" + target_arch + "}": error_script,
+            "%{clang_cl_dbg_mode_debug_flag_" + target_arch + "}": "/DEBUG",
+            "%{clang_cl_fastbuild_mode_debug_flag_" + target_arch + "}": "/DEBUG",
+            "%{clang_cl_cxx_builtin_include_directories_" + target_arch + "}": "",
+            "%{clang_cl_parse_showincludes_" + target_arch + "}": repr(False),
         }
         return clang_cl_vars
 
-    clang_cl_path = _find_llvm_tool(repository_ctx, llvm_path, "clang-cl.exe")
-    lld_link_path = _find_llvm_tool(repository_ctx, llvm_path, "lld-link.exe")
-    llvm_lib_path = _find_llvm_tool(repository_ctx, llvm_path, "llvm-lib.exe")
+    clang_cl_path = find_llvm_tool(repository_ctx, llvm_path, "clang-cl.exe")
+    lld_link_path = find_llvm_tool(repository_ctx, llvm_path, "lld-link.exe")
+    llvm_lib_path = find_llvm_tool(repository_ctx, llvm_path, "llvm-lib.exe")
 
     clang_version = _get_clang_version(repository_ctx, clang_cl_path)
-    clang_dir = llvm_path + "\\lib\\clang\\" + clang_version
+    clang_dir = _get_clang_dir(repository_ctx, llvm_path, clang_version)
     clang_include_path = (clang_dir + "\\include").replace("\\", "\\\\")
     clang_lib_path = (clang_dir + "\\lib\\windows").replace("\\", "\\\\")
 
-    clang_cl_include_directories = msvc_vars["%{msvc_cxx_builtin_include_directories}"] + (",\n        \"%s\"" % clang_include_path)
+    clang_cl_include_directories = msvc_vars["%{msvc_cxx_builtin_include_directories_" + target_arch + "}"] + (",\n        \"%s\"" % clang_include_path)
     write_builtin_include_directory_paths(repository_ctx, "clang-cl", [clang_cl_include_directories], file_suffix = "_clangcl")
     clang_cl_vars = {
-        "%{clang_cl_cl_path}": clang_cl_path,
-        "%{clang_cl_cxx_builtin_include_directories}": clang_cl_include_directories,
+        "%{clang_cl_env_tmp_" + target_arch + "}": msvc_vars["%{msvc_env_tmp_" + target_arch + "}"],
+        "%{clang_cl_env_path_" + target_arch + "}": msvc_vars["%{msvc_env_path_" + target_arch + "}"],
+        "%{clang_cl_env_include_" + target_arch + "}": msvc_vars["%{msvc_env_include_" + target_arch + "}"] + ";" + clang_include_path,
+        "%{clang_cl_env_lib_" + target_arch + "}": msvc_vars["%{msvc_env_lib_" + target_arch + "}"] + ";" + clang_lib_path,
+        "%{clang_cl_cxx_builtin_include_directories_" + target_arch + "}": clang_cl_include_directories,
+        "%{clang_cl_cl_path_" + target_arch + "}": clang_cl_path,
+        "%{clang_cl_link_path_" + target_arch + "}": lld_link_path,
+        "%{clang_cl_lib_path_" + target_arch + "}": llvm_lib_path,
+        # clang-cl does not support assembly files as input.
+        "%{clang_cl_ml_path_" + target_arch + "}": msvc_vars["%{msvc_ml_path_" + target_arch + "}"],
         # LLVM's lld-link.exe doesn't support /DEBUG:FASTLINK.
-        "%{clang_cl_dbg_mode_debug_flag}": "/DEBUG",
-        "%{clang_cl_env_include}": msvc_vars["%{msvc_env_include}"] + ";" + clang_include_path,
-        "%{clang_cl_env_lib}": msvc_vars["%{msvc_env_lib}"] + ";" + clang_lib_path,
-        "%{clang_cl_env_path}": msvc_vars["%{msvc_env_path}"],
-        "%{clang_cl_env_tmp}": msvc_vars["%{msvc_env_tmp}"],
-        "%{clang_cl_fastbuild_mode_debug_flag}": "/DEBUG",
-        "%{clang_cl_lib_path}": llvm_lib_path,
-        "%{clang_cl_link_path}": lld_link_path,
-        "%{clang_cl_ml_path}": msvc_vars["%{msvc_ml_path}"],
+        "%{clang_cl_dbg_mode_debug_flag_" + target_arch + "}": "/DEBUG",
+        "%{clang_cl_fastbuild_mode_debug_flag_" + target_arch + "}": "/DEBUG",
+        # clang-cl always emits the English language version of the /showIncludes prefix.
+        "%{clang_cl_parse_showincludes_" + target_arch + "}": repr(True),
     }
     return clang_cl_vars
 
+def _get_msvc_deps_scanner_vars(repository_ctx, paths, template_vars, target_arch = "x64"):
+    repository_ctx.template(
+        "msvc_deps_scanner_wrapper_" + target_arch + ".bat",
+        paths["@rules_cc//cc/private/toolchain:msvc_deps_scanner_wrapper.bat.tpl"],
+        {
+            "%{cc}": template_vars["%{msvc_cl_path_" + target_arch + "}"],
+        },
+    )
+
+    return {
+        "%{msvc_deps_scanner_wrapper_path_" + target_arch + "}": "msvc_deps_scanner_wrapper_" + target_arch + ".bat",
+    }
+
 def configure_windows_toolchain(repository_ctx):
     """Configure C++ toolchain on Windows.
 
     Args:
-      repository_ctx: The repository context.
+        repository_ctx: The repository context.
     """
     paths = resolve_labels(repository_ctx, [
         "@rules_cc//cc/private/toolchain:BUILD.windows.tpl",
@@ -675,6 +863,7 @@
         "@rules_cc//cc/private/toolchain:vc_installation_error.bat.tpl",
         "@rules_cc//cc/private/toolchain:msys_gcc_installation_error.bat",
         "@rules_cc//cc/private/toolchain:clang_installation_error.bat.tpl",
+        "@rules_cc//cc/private/toolchain:msvc_deps_scanner_wrapper.bat.tpl",
     ])
 
     repository_ctx.symlink(
@@ -691,11 +880,20 @@
     )
 
     template_vars = dict()
-    msvc_vars = _get_msvc_vars(repository_ctx, paths)
-    template_vars.update(msvc_vars)
-    template_vars.update(_get_clang_cl_vars(repository_ctx, paths, msvc_vars))
+    msvc_vars_x64 = _get_msvc_vars(repository_ctx, paths, "x64")
+    template_vars.update(msvc_vars_x64)
+    template_vars.update(_get_clang_cl_vars(repository_ctx, paths, msvc_vars_x64, "x64"))
     template_vars.update(_get_msys_mingw_vars(repository_ctx))
+    template_vars.update(_get_msvc_vars(repository_ctx, paths, "x86", msvc_vars_x64))
+    template_vars.update(_get_msvc_vars(repository_ctx, paths, "arm", msvc_vars_x64))
+    msvc_vars_arm64 = _get_msvc_vars(repository_ctx, paths, "arm64", msvc_vars_x64)
+    template_vars.update(msvc_vars_arm64)
+    template_vars.update(_get_clang_cl_vars(repository_ctx, paths, msvc_vars_arm64, "arm64"))
 
+    template_vars.update(_get_msvc_deps_scanner_vars(repository_ctx, paths, template_vars, "x64"))
+    template_vars.update(_get_msvc_deps_scanner_vars(repository_ctx, paths, template_vars, "x86"))
+    template_vars.update(_get_msvc_deps_scanner_vars(repository_ctx, paths, template_vars, "arm"))
+    template_vars.update(_get_msvc_deps_scanner_vars(repository_ctx, paths, template_vars, "arm64"))
     repository_ctx.template(
         "BUILD",
         paths["@rules_cc//cc/private/toolchain:BUILD.windows.tpl"],
diff --git a/cc/private/toolchain/windows_cc_toolchain_config.bzl b/cc/private/toolchain/windows_cc_toolchain_config.bzl
index 7fa2978..76cd586 100644
--- a/cc/private/toolchain/windows_cc_toolchain_config.bzl
+++ b/cc/private/toolchain/windows_cc_toolchain_config.bzl
@@ -22,9 +22,9 @@
     "env_entry",
     "env_set",
     "feature",
-    "feature_set",
     "flag_group",
     "flag_set",
+    "make_variable",
     "tool",
     "tool_path",
     "variable_with_value",
@@ -40,6 +40,9 @@
     ACTION_NAMES.cpp_header_parsing,
     ACTION_NAMES.cpp_module_compile,
     ACTION_NAMES.cpp_module_codegen,
+    ACTION_NAMES.cpp_module_deps_scanning,
+    ACTION_NAMES.cpp20_module_compile,
+    ACTION_NAMES.cpp20_module_codegen,
     ACTION_NAMES.clif_match,
     ACTION_NAMES.lto_backend,
 ]
@@ -50,6 +53,9 @@
     ACTION_NAMES.cpp_header_parsing,
     ACTION_NAMES.cpp_module_compile,
     ACTION_NAMES.cpp_module_codegen,
+    ACTION_NAMES.cpp_module_deps_scanning,
+    ACTION_NAMES.cpp20_module_compile,
+    ACTION_NAMES.cpp20_module_codegen,
     ACTION_NAMES.clif_match,
 ]
 
@@ -60,6 +66,8 @@
     ACTION_NAMES.preprocess_assemble,
     ACTION_NAMES.cpp_header_parsing,
     ACTION_NAMES.cpp_module_compile,
+    ACTION_NAMES.cpp_module_deps_scanning,
+    ACTION_NAMES.cpp20_module_compile,
     ACTION_NAMES.clif_match,
 ]
 
@@ -70,6 +78,7 @@
     ACTION_NAMES.assemble,
     ACTION_NAMES.preprocess_assemble,
     ACTION_NAMES.cpp_module_codegen,
+    ACTION_NAMES.cpp20_module_codegen,
     ACTION_NAMES.lto_backend,
 ]
 
@@ -80,7 +89,7 @@
 ]
 
 def _use_msvc_toolchain(ctx):
-    return ctx.attr.cpu == "x64_windows" and (ctx.attr.compiler == "msvc-cl" or ctx.attr.compiler == "clang-cl")
+    return ctx.attr.cpu in ["x64_windows", "arm64_windows"] and (ctx.attr.compiler == "msvc-cl" or ctx.attr.compiler == "clang-cl")
 
 def _impl(ctx):
     if _use_msvc_toolchain(ctx):
@@ -135,7 +144,6 @@
                 "output_execpath_flags",
                 "input_param_flags",
                 "user_link_flags",
-                "default_link_flags",
                 "linker_subsystem_flag",
                 "linker_param_file",
                 "msvc_env",
@@ -187,10 +195,22 @@
             implies = [
                 "compiler_input_flags",
                 "compiler_output_flags",
+                "nologo",
+                "msvc_env",
+                "user_compile_flags",
+                "sysroot",
+            ],
+            tools = [tool(path = ctx.attr.msvc_cl_path)],
+        )
+
+        linkstamp_compile_action = action_config(
+            action_name = ACTION_NAMES.linkstamp_compile,
+            implies = [
+                "compiler_input_flags",
+                "compiler_output_flags",
                 "default_compile_flags",
                 "nologo",
                 "msvc_env",
-                "parse_showincludes",
                 "user_compile_flags",
                 "sysroot",
                 "unfiltered_compile_flags",
@@ -203,13 +223,10 @@
             implies = [
                 "compiler_input_flags",
                 "compiler_output_flags",
-                "default_compile_flags",
                 "nologo",
                 "msvc_env",
-                "parse_showincludes",
                 "user_compile_flags",
                 "sysroot",
-                "unfiltered_compile_flags",
             ],
             tools = [tool(path = ctx.attr.msvc_cl_path)],
         )
@@ -222,7 +239,6 @@
                 "output_execpath_flags",
                 "input_param_flags",
                 "user_link_flags",
-                "default_link_flags",
                 "linker_subsystem_flag",
                 "linker_param_file",
                 "msvc_env",
@@ -240,7 +256,6 @@
                 "output_execpath_flags",
                 "input_param_flags",
                 "user_link_flags",
-                "default_link_flags",
                 "linker_subsystem_flag",
                 "linker_param_file",
                 "msvc_env",
@@ -251,15 +266,84 @@
             tools = [tool(path = ctx.attr.msvc_link_path)],
         )
 
+        deps_scanner = "cpp-module-deps-scanner_not_found"
+        if "cpp-module-deps-scanner" in ctx.attr.tool_paths:
+            deps_scanner = ctx.attr.tool_paths["cpp-module-deps-scanner"]
+        cpp_module_scan_deps = action_config(
+            action_name = ACTION_NAMES.cpp_module_deps_scanning,
+            tools = [
+                tool(
+                    path = deps_scanner,
+                ),
+            ],
+            implies = [
+                "compiler_input_flags",
+                "compiler_output_flags",
+                "nologo",
+                "msvc_env",
+                "user_compile_flags",
+                "sysroot",
+            ],
+        )
+
+        cpp20_module_compile = action_config(
+            action_name = ACTION_NAMES.cpp20_module_compile,
+            tools = [
+                tool(
+                    path = ctx.attr.msvc_cl_path,
+                ),
+            ],
+            flag_sets = [
+                flag_set(
+                    flag_groups = [
+                        flag_group(
+                            flags = [
+                                "/TP",
+                                "/interface",
+                            ],
+                        ),
+                    ],
+                ),
+            ],
+            implies = [
+                "compiler_input_flags",
+                "compiler_output_flags",
+                "nologo",
+                "msvc_env",
+                "user_compile_flags",
+                "sysroot",
+            ],
+        )
+
+        cpp20_module_codegen = action_config(
+            action_name = ACTION_NAMES.cpp20_module_codegen,
+            tools = [
+                tool(
+                    path = ctx.attr.msvc_cl_path,
+                ),
+            ],
+            implies = [
+                "compiler_input_flags",
+                "compiler_output_flags",
+                "nologo",
+                "msvc_env",
+                "user_compile_flags",
+                "sysroot",
+            ],
+        )
         action_configs = [
             assemble_action,
             preprocess_assemble_action,
             c_compile_action,
+            linkstamp_compile_action,
             cpp_compile_action,
             cpp_link_executable_action,
             cpp_link_dynamic_library_action,
             cpp_link_nodeps_dynamic_library_action,
             cpp_link_static_library_action,
+            cpp_module_scan_deps,
+            cpp20_module_compile,
+            cpp20_module_codegen,
         ]
     else:
         action_configs = []
@@ -317,10 +401,14 @@
                         ACTION_NAMES.assemble,
                         ACTION_NAMES.preprocess_assemble,
                         ACTION_NAMES.c_compile,
+                        ACTION_NAMES.linkstamp_compile,
                         ACTION_NAMES.cpp_compile,
                         ACTION_NAMES.cpp_header_parsing,
                         ACTION_NAMES.cpp_module_compile,
                         ACTION_NAMES.cpp_module_codegen,
+                        ACTION_NAMES.cpp_module_deps_scanning,
+                        ACTION_NAMES.cpp20_module_compile,
+                        ACTION_NAMES.cpp20_module_codegen,
                         ACTION_NAMES.cpp_link_executable,
                         ACTION_NAMES.cpp_link_dynamic_library,
                         ACTION_NAMES.cpp_link_nodeps_dynamic_library,
@@ -338,15 +426,20 @@
 
         unfiltered_compile_flags_feature = feature(
             name = "unfiltered_compile_flags",
+            enabled = True,
             flag_sets = [
                 flag_set(
                     actions = [
                         ACTION_NAMES.preprocess_assemble,
                         ACTION_NAMES.c_compile,
+                        ACTION_NAMES.linkstamp_compile,
                         ACTION_NAMES.cpp_compile,
                         ACTION_NAMES.cpp_header_parsing,
                         ACTION_NAMES.cpp_module_compile,
                         ACTION_NAMES.cpp_module_codegen,
+                        ACTION_NAMES.cpp_module_deps_scanning,
+                        ACTION_NAMES.cpp20_module_compile,
+                        ACTION_NAMES.cpp20_module_codegen,
                     ],
                     flag_groups = [
                         flag_group(
@@ -359,8 +452,14 @@
             ],
         )
 
+        archive_param_file_feature = feature(
+            name = "archive_param_file",
+            enabled = True,
+        )
+
         compiler_param_file_feature = feature(
             name = "compiler_param_file",
+            enabled = True,
         )
 
         copy_dynamic_libraries_to_binary_feature = feature(
@@ -471,10 +570,14 @@
                     actions = [
                         ACTION_NAMES.preprocess_assemble,
                         ACTION_NAMES.c_compile,
+                        ACTION_NAMES.linkstamp_compile,
                         ACTION_NAMES.cpp_compile,
                         ACTION_NAMES.cpp_header_parsing,
                         ACTION_NAMES.cpp_module_compile,
                         ACTION_NAMES.cpp_module_codegen,
+                        ACTION_NAMES.cpp_module_deps_scanning,
+                        ACTION_NAMES.cpp20_module_compile,
+                        ACTION_NAMES.cpp20_module_codegen,
                     ],
                     flag_groups = [
                         flag_group(
@@ -498,7 +601,12 @@
                             expand_if_available = "output_execpath",
                         ),
                         flag_group(
-                            flags = ["/MACHINE:X64"],
+                            flags = ["%{user_archiver_flags}"],
+                            iterate_over = "user_archiver_flags",
+                            expand_if_available = "user_archiver_flags",
+                        ),
+                        flag_group(
+                            flags = ctx.attr.archiver_flags,
                         ),
                     ],
                 ),
@@ -516,21 +624,57 @@
             ],
         )
 
-        static_link_msvcrt_feature = feature(name = "static_link_msvcrt")
-
-        dynamic_link_msvcrt_debug_feature = feature(
-            name = "dynamic_link_msvcrt_debug",
+        static_link_msvcrt_feature = feature(
+            name = "static_link_msvcrt",
             flag_sets = [
                 flag_set(
                     actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile],
+                    flag_groups = [flag_group(flags = ["/MT"])],
+                    with_features = [with_feature_set(not_features = ["dbg"])],
+                ),
+                flag_set(
+                    actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile],
+                    flag_groups = [flag_group(flags = ["/MTd"])],
+                    with_features = [with_feature_set(features = ["dbg"])],
+                ),
+                flag_set(
+                    actions = all_link_actions,
+                    flag_groups = [flag_group(flags = ["/DEFAULTLIB:libcmt.lib"])],
+                    with_features = [with_feature_set(not_features = ["dbg"])],
+                ),
+                flag_set(
+                    actions = all_link_actions,
+                    flag_groups = [flag_group(flags = ["/DEFAULTLIB:libcmtd.lib"])],
+                    with_features = [with_feature_set(features = ["dbg"])],
+                ),
+            ],
+        )
+
+        dynamic_link_msvcrt_feature = feature(
+            name = "dynamic_link_msvcrt",
+            enabled = True,
+            flag_sets = [
+                flag_set(
+                    actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile],
+                    flag_groups = [flag_group(flags = ["/MD"])],
+                    with_features = [with_feature_set(not_features = ["dbg", "static_link_msvcrt"])],
+                ),
+                flag_set(
+                    actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile],
                     flag_groups = [flag_group(flags = ["/MDd"])],
+                    with_features = [with_feature_set(features = ["dbg"], not_features = ["static_link_msvcrt"])],
+                ),
+                flag_set(
+                    actions = all_link_actions,
+                    flag_groups = [flag_group(flags = ["/DEFAULTLIB:msvcrt.lib"])],
+                    with_features = [with_feature_set(not_features = ["dbg", "static_link_msvcrt"])],
                 ),
                 flag_set(
                     actions = all_link_actions,
                     flag_groups = [flag_group(flags = ["/DEFAULTLIB:msvcrtd.lib"])],
+                    with_features = [with_feature_set(features = ["dbg"], not_features = ["static_link_msvcrt"])],
                 ),
             ],
-            requires = [feature_set(features = ["dbg"])],
         )
 
         dbg_feature = feature(
@@ -598,6 +742,9 @@
                         ACTION_NAMES.cpp_header_parsing,
                         ACTION_NAMES.cpp_module_compile,
                         ACTION_NAMES.cpp_module_codegen,
+                        ACTION_NAMES.cpp_module_deps_scanning,
+                        ACTION_NAMES.cpp20_module_compile,
+                        ACTION_NAMES.cpp20_module_codegen,
                         ACTION_NAMES.lto_backend,
                         ACTION_NAMES.clif_match,
                     ],
@@ -629,10 +776,14 @@
                 env_set(
                     actions = [
                         ACTION_NAMES.c_compile,
+                        ACTION_NAMES.linkstamp_compile,
                         ACTION_NAMES.cpp_compile,
                         ACTION_NAMES.cpp_module_compile,
                         ACTION_NAMES.cpp_module_codegen,
                         ACTION_NAMES.cpp_header_parsing,
+                        ACTION_NAMES.cpp_module_deps_scanning,
+                        ACTION_NAMES.cpp20_module_compile,
+                        ACTION_NAMES.cpp20_module_codegen,
                         ACTION_NAMES.assemble,
                         ACTION_NAMES.preprocess_assemble,
                     ],
@@ -650,9 +801,12 @@
                         ACTION_NAMES.assemble,
                         ACTION_NAMES.preprocess_assemble,
                         ACTION_NAMES.c_compile,
+                        ACTION_NAMES.linkstamp_compile,
                         ACTION_NAMES.cpp_compile,
                         ACTION_NAMES.cpp_header_parsing,
                         ACTION_NAMES.cpp_module_compile,
+                        ACTION_NAMES.cpp_module_deps_scanning,
+                        ACTION_NAMES.cpp20_module_compile,
                     ],
                     flag_groups = [
                         flag_group(
@@ -668,6 +822,25 @@
             name = "generate_pdb_file",
         )
 
+        generate_linkmap_feature = feature(
+            name = "generate_linkmap",
+            flag_sets = [
+                flag_set(
+                    actions = [
+                        ACTION_NAMES.cpp_link_executable,
+                    ],
+                    flag_groups = [
+                        flag_group(
+                            flags = [
+                                "/MAP:%{output_execpath}.map",
+                            ],
+                            expand_if_available = "output_execpath",
+                        ),
+                    ],
+                ),
+            ],
+        )
+
         output_execpath_flags_feature = feature(
             name = "output_execpath_flags",
             flag_sets = [
@@ -683,24 +856,6 @@
             ],
         )
 
-        dynamic_link_msvcrt_no_debug_feature = feature(
-            name = "dynamic_link_msvcrt_no_debug",
-            flag_sets = [
-                flag_set(
-                    actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile],
-                    flag_groups = [flag_group(flags = ["/MD"])],
-                ),
-                flag_set(
-                    actions = all_link_actions,
-                    flag_groups = [flag_group(flags = ["/DEFAULTLIB:msvcrt.lib"])],
-                ),
-            ],
-            requires = [
-                feature_set(features = ["fastbuild"]),
-                feature_set(features = ["opt"]),
-            ],
-        )
-
         disable_assertions_feature = feature(
             name = "disable_assertions",
             enabled = True,
@@ -750,43 +905,50 @@
 
         parse_showincludes_feature = feature(
             name = "parse_showincludes",
+            enabled = ctx.attr.supports_parse_showincludes,
             flag_sets = [
                 flag_set(
                     actions = [
                         ACTION_NAMES.preprocess_assemble,
                         ACTION_NAMES.c_compile,
+                        ACTION_NAMES.linkstamp_compile,
                         ACTION_NAMES.cpp_compile,
                         ACTION_NAMES.cpp_module_compile,
                         ACTION_NAMES.cpp_header_parsing,
+                        ACTION_NAMES.cpp_module_deps_scanning,
+                        ACTION_NAMES.cpp20_module_compile,
                     ],
                     flag_groups = [flag_group(flags = ["/showIncludes"])],
                 ),
             ],
+            env_sets = [
+                env_set(
+                    actions = [
+                        ACTION_NAMES.preprocess_assemble,
+                        ACTION_NAMES.c_compile,
+                        ACTION_NAMES.linkstamp_compile,
+                        ACTION_NAMES.cpp_compile,
+                        ACTION_NAMES.cpp_module_compile,
+                        ACTION_NAMES.cpp_header_parsing,
+                    ],
+                    # Force English (and thus a consistent locale) output so that Bazel can parse
+                    # the /showIncludes output without having to guess the encoding.
+                    env_entries = [env_entry(key = "VSLANG", value = "1033")],
+                ),
+            ],
         )
 
-        static_link_msvcrt_no_debug_feature = feature(
-            name = "static_link_msvcrt_no_debug",
-            flag_sets = [
-                flag_set(
-                    actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile],
-                    flag_groups = [flag_group(flags = ["/MT"])],
-                ),
-                flag_set(
-                    actions = all_link_actions,
-                    flag_groups = [flag_group(flags = ["/DEFAULTLIB:libcmt.lib"])],
-                ),
-            ],
-            requires = [
-                feature_set(features = ["fastbuild"]),
-                feature_set(features = ["opt"]),
-            ],
+        # MSVC does not emit .d files.
+        no_dotd_file_feature = feature(
+            name = "no_dotd_file",
+            enabled = True,
         )
 
         treat_warnings_as_errors_feature = feature(
             name = "treat_warnings_as_errors",
             flag_sets = [
                 flag_set(
-                    actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile],
+                    actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile] + all_link_actions,
                     flag_groups = [flag_group(flags = ["/WX"])],
                 ),
             ],
@@ -805,6 +967,7 @@
                         ACTION_NAMES.assemble,
                         ACTION_NAMES.preprocess_assemble,
                         ACTION_NAMES.c_compile,
+                        ACTION_NAMES.linkstamp_compile,
                         ACTION_NAMES.cpp_compile,
                         ACTION_NAMES.cpp_header_parsing,
                         ACTION_NAMES.cpp_module_compile,
@@ -827,6 +990,34 @@
             ],
         )
 
+        external_include_paths_feature = feature(
+            name = "external_include_paths",
+            flag_sets = [
+                flag_set(
+                    actions = [
+                        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_deps_scanning,
+                        ACTION_NAMES.cpp20_module_compile,
+                        ACTION_NAMES.clif_match,
+                        ACTION_NAMES.objc_compile,
+                        ACTION_NAMES.objcpp_compile,
+                    ],
+                    flag_groups = [
+                        flag_group(
+                            flags = ["/external:I%{external_include_paths}"],
+                            iterate_over = "external_include_paths",
+                            expand_if_available = "external_include_paths",
+                        ),
+                    ],
+                ),
+            ],
+        )
+
         linkstamps_feature = feature(
             name = "linkstamps",
             flag_sets = [
@@ -859,21 +1050,6 @@
             ],
         )
 
-        static_link_msvcrt_debug_feature = feature(
-            name = "static_link_msvcrt_debug",
-            flag_sets = [
-                flag_set(
-                    actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile],
-                    flag_groups = [flag_group(flags = ["/MTd"])],
-                ),
-                flag_set(
-                    actions = all_link_actions,
-                    flag_groups = [flag_group(flags = ["/DEFAULTLIB:libcmtd.lib"])],
-                ),
-            ],
-            requires = [feature_set(features = ["dbg"])],
-        )
-
         frame_pointer_feature = feature(
             name = "frame_pointer",
             flag_sets = [
@@ -906,10 +1082,14 @@
                     actions = [
                         ACTION_NAMES.preprocess_assemble,
                         ACTION_NAMES.c_compile,
+                        ACTION_NAMES.linkstamp_compile,
                         ACTION_NAMES.cpp_compile,
                         ACTION_NAMES.cpp_header_parsing,
                         ACTION_NAMES.cpp_module_compile,
                         ACTION_NAMES.cpp_module_codegen,
+                        ACTION_NAMES.cpp_module_deps_scanning,
+                        ACTION_NAMES.cpp20_module_compile,
+                        ACTION_NAMES.cpp20_module_codegen,
                     ],
                     flag_groups = [
                         flag_group(
@@ -951,10 +1131,14 @@
                 flag_set(
                     actions = [
                         ACTION_NAMES.c_compile,
+                        ACTION_NAMES.linkstamp_compile,
                         ACTION_NAMES.cpp_compile,
                         ACTION_NAMES.cpp_module_compile,
                         ACTION_NAMES.cpp_module_codegen,
                         ACTION_NAMES.cpp_header_parsing,
+                        ACTION_NAMES.cpp_module_deps_scanning,
+                        ACTION_NAMES.cpp20_module_compile,
+                        ACTION_NAMES.cpp20_module_codegen,
                         ACTION_NAMES.assemble,
                         ACTION_NAMES.preprocess_assemble,
                         ACTION_NAMES.cpp_link_executable,
@@ -984,6 +1168,17 @@
             ],
         )
 
+        remove_unreferenced_code_feature = feature(
+            name = "remove_unreferenced_code",
+            enabled = True,
+            flag_sets = [
+                flag_set(
+                    actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile],
+                    flag_groups = [flag_group(flags = ["/Zc:inline"])],
+                ),
+            ],
+        )
+
         compiler_input_flags_feature = feature(
             name = "compiler_input_flags",
             flag_sets = [
@@ -992,10 +1187,14 @@
                         ACTION_NAMES.assemble,
                         ACTION_NAMES.preprocess_assemble,
                         ACTION_NAMES.c_compile,
+                        ACTION_NAMES.linkstamp_compile,
                         ACTION_NAMES.cpp_compile,
                         ACTION_NAMES.cpp_header_parsing,
                         ACTION_NAMES.cpp_module_compile,
                         ACTION_NAMES.cpp_module_codegen,
+                        ACTION_NAMES.cpp_module_deps_scanning,
+                        ACTION_NAMES.cpp20_module_compile,
+                        ACTION_NAMES.cpp20_module_codegen,
                     ],
                     flag_groups = [
                         flag_group(
@@ -1028,10 +1227,14 @@
                 env_set(
                     actions = [
                         ACTION_NAMES.c_compile,
+                        ACTION_NAMES.linkstamp_compile,
                         ACTION_NAMES.cpp_compile,
                         ACTION_NAMES.cpp_module_compile,
                         ACTION_NAMES.cpp_module_codegen,
                         ACTION_NAMES.cpp_header_parsing,
+                        ACTION_NAMES.cpp_module_deps_scanning,
+                        ACTION_NAMES.cpp20_module_compile,
+                        ACTION_NAMES.cpp20_module_codegen,
                         ACTION_NAMES.assemble,
                         ACTION_NAMES.preprocess_assemble,
                         ACTION_NAMES.cpp_link_executable,
@@ -1048,6 +1251,17 @@
             ],
             implies = ["msvc_compile_env", "msvc_link_env"],
         )
+
+        symbol_check_feature = feature(
+            name = "symbol_check",
+            flag_sets = [
+                flag_set(
+                    actions = [ACTION_NAMES.cpp_link_static_library],
+                    flag_groups = [flag_group(flags = ["/WX:4006"])],
+                ),
+            ],
+        )
+
         features = [
             no_legacy_features_feature,
             nologo_feature,
@@ -1060,9 +1274,12 @@
             msvc_compile_env_feature,
             msvc_link_env_feature,
             include_paths_feature,
+            external_include_paths_feature,
             preprocessor_defines_feature,
             parse_showincludes_feature,
+            no_dotd_file_feature,
             generate_pdb_file_feature,
+            generate_linkmap_feature,
             shared_flag_feature,
             linkstamps_feature,
             output_execpath_flags_feature,
@@ -1073,10 +1290,7 @@
             default_link_flags_feature,
             linker_param_file_feature,
             static_link_msvcrt_feature,
-            static_link_msvcrt_no_debug_feature,
-            dynamic_link_msvcrt_no_debug_feature,
-            static_link_msvcrt_debug_feature,
-            dynamic_link_msvcrt_debug_feature,
+            dynamic_link_msvcrt_feature,
             dbg_feature,
             fastbuild_feature,
             opt_feature,
@@ -1085,10 +1299,12 @@
             determinism_feature,
             treat_warnings_as_errors_feature,
             smaller_binary_feature,
+            remove_unreferenced_code_feature,
             ignore_noisy_warnings_feature,
             user_compile_flags_feature,
             sysroot_feature,
             unfiltered_compile_flags_feature,
+            archive_param_file_feature,
             compiler_param_file_feature,
             compiler_output_flags_feature,
             compiler_input_flags_feature,
@@ -1097,6 +1313,7 @@
             no_windows_export_all_symbols_feature,
             supports_dynamic_linker_feature,
             supports_interface_shared_libraries_feature,
+            symbol_check_feature,
         ]
     else:
         targets_windows_feature = feature(
@@ -1114,10 +1331,14 @@
                 env_set(
                     actions = [
                         ACTION_NAMES.c_compile,
+                        ACTION_NAMES.linkstamp_compile,
                         ACTION_NAMES.cpp_compile,
                         ACTION_NAMES.cpp_module_compile,
                         ACTION_NAMES.cpp_module_codegen,
                         ACTION_NAMES.cpp_header_parsing,
+                        ACTION_NAMES.cpp_module_deps_scanning,
+                        ACTION_NAMES.cpp20_module_compile,
+                        ACTION_NAMES.cpp20_module_codegen,
                         ACTION_NAMES.assemble,
                         ACTION_NAMES.preprocess_assemble,
                         ACTION_NAMES.cpp_link_executable,
@@ -1143,10 +1364,13 @@
                         ACTION_NAMES.cpp_header_parsing,
                         ACTION_NAMES.cpp_module_compile,
                         ACTION_NAMES.cpp_module_codegen,
+                        ACTION_NAMES.cpp_module_deps_scanning,
+                        ACTION_NAMES.cpp20_module_compile,
+                        ACTION_NAMES.cpp20_module_codegen,
                         ACTION_NAMES.lto_backend,
                         ACTION_NAMES.clif_match,
                     ],
-                    flag_groups = [flag_group(flags = ["-std=gnu++0x"])],
+                    flag_groups = [flag_group(flags = ["-std=gnu++14"] + ctx.attr.default_compile_flags)],
                 ),
             ],
         )
@@ -1157,7 +1381,7 @@
             flag_sets = [
                 flag_set(
                     actions = all_link_actions,
-                    flag_groups = [flag_group(flags = ["-lstdc++"])],
+                    flag_groups = [flag_group(flags = ["-lstdc++"] + ctx.attr.default_link_flags)],
                 ),
             ],
         )
@@ -1167,7 +1391,42 @@
             enabled = True,
         )
 
+        dbg_feature = feature(
+            name = "dbg",
+            flag_sets = [
+                flag_set(
+                    actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile],
+                    flag_groups = [flag_group(flags = ["-g", "-Og"])],
+                ),
+            ],
+        )
+
+        opt_feature = feature(
+            name = "opt",
+            flag_sets = [
+                flag_set(
+                    actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile],
+                    flag_groups = [flag_group(flags = [
+                        "-g0",
+                        "-O3",
+                        "-DNDEBUG",
+                        "-ffunction-sections",
+                        "-fdata-sections",
+                    ])],
+                ),
+                flag_set(
+                    actions = all_link_actions,
+                    flag_groups = [flag_group(flags = ["-Wl,--gc-sections"])],
+                ),
+            ],
+        )
+
         if ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "mingw-gcc":
+            archive_param_file_feature = feature(
+                name = "archive_param_file",
+                enabled = True,
+            )
+
             compiler_param_file_feature = feature(
                 name = "compiler_param_file",
             )
@@ -1177,23 +1436,18 @@
                 copy_dynamic_libraries_to_binary_feature,
                 gcc_env_feature,
                 default_compile_flags_feature,
+                archive_param_file_feature,
                 compiler_param_file_feature,
                 default_link_flags_feature,
                 supports_dynamic_linker_feature,
+                dbg_feature,
+                opt_feature,
             ]
         else:
             supports_pic_feature = feature(
                 name = "supports_pic",
                 enabled = True,
             )
-            supports_start_end_lib_feature = feature(
-                name = "supports_start_end_lib",
-                enabled = True,
-            )
-
-            dbg_feature = feature(name = "dbg")
-
-            opt_feature = feature(name = "opt")
 
             sysroot_feature = feature(
                 name = "sysroot",
@@ -1208,6 +1462,9 @@
                             ACTION_NAMES.cpp_header_parsing,
                             ACTION_NAMES.cpp_module_compile,
                             ACTION_NAMES.cpp_module_codegen,
+                            ACTION_NAMES.cpp_module_deps_scanning,
+                            ACTION_NAMES.cpp20_module_compile,
+                            ACTION_NAMES.cpp20_module_codegen,
                             ACTION_NAMES.lto_backend,
                             ACTION_NAMES.clif_match,
                             ACTION_NAMES.cpp_link_executable,
@@ -1243,6 +1500,20 @@
                 provides = ["profile"],
             )
 
+            treat_warnings_as_errors_feature = feature(
+                name = "treat_warnings_as_errors",
+                flag_sets = [
+                    flag_set(
+                        actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile],
+                        flag_groups = [flag_group(flags = ["-Werror"])],
+                    ),
+                    flag_set(
+                        actions = all_link_actions,
+                        flag_groups = [flag_group(flags = ["-Wl,-fatal-warnings"])],
+                    ),
+                ],
+            )
+
             user_compile_flags_feature = feature(
                 name = "user_compile_flags",
                 enabled = True,
@@ -1257,6 +1528,9 @@
                             ACTION_NAMES.cpp_header_parsing,
                             ACTION_NAMES.cpp_module_compile,
                             ACTION_NAMES.cpp_module_codegen,
+                            ACTION_NAMES.cpp_module_deps_scanning,
+                            ACTION_NAMES.cpp20_module_compile,
+                            ACTION_NAMES.cpp20_module_codegen,
                             ACTION_NAMES.lto_backend,
                             ACTION_NAMES.clif_match,
                         ],
@@ -1276,7 +1550,6 @@
                 copy_dynamic_libraries_to_binary_feature,
                 gcc_env_feature,
                 supports_pic_feature,
-                supports_start_end_lib_feature,
                 default_compile_flags_feature,
                 default_link_flags_feature,
                 fdo_optimize_feature,
@@ -1284,6 +1557,7 @@
                 dbg_feature,
                 opt_feature,
                 user_compile_flags_feature,
+                treat_warnings_as_errors_feature,
                 sysroot_feature,
             ]
 
@@ -1292,9 +1566,61 @@
         for name, path in ctx.attr.tool_paths.items()
     ]
 
+    make_variables = []
+
+    # dumpbin.exe is not available in MSYS toolchain
+    if "dumpbin" in ctx.attr.tool_paths:
+        make_variables.append(make_variable(name = "DUMPBIN", value = ctx.attr.tool_paths["dumpbin"]))
+
+    # Tell bazel we support C++ modules now
+    cpp_modules_feature = feature(
+        name = "cpp_modules",
+        # set default value to False
+        # to enable the feature
+        # use --features=cpp_modules
+        # or add cpp_modules to features attr
+        enabled = False,
+    )
+
+    cpp_module_modmap_file_feature = feature(
+        name = "cpp_module_modmap_file",
+        flag_sets = [
+            flag_set(
+                actions = [
+                    ACTION_NAMES.cpp_compile,
+                    ACTION_NAMES.cpp20_module_compile,
+                    ACTION_NAMES.cpp20_module_codegen,
+                ],
+                flag_groups = [
+                    flag_group(
+                        flags = ["@%{cpp_module_modmap_file}"],
+                        expand_if_available = "cpp_module_modmap_file",
+                    ),
+                ],
+            ),
+        ],
+        enabled = True,
+    )
+    cpp20_module_compile_flags_feature = feature(
+        name = "cpp20_module_compile_flags",
+        flag_sets = [
+            flag_set(
+                actions = [
+                    ACTION_NAMES.cpp20_module_compile,
+                ],
+                flag_groups = [
+                    flag_group(
+                        flags = ["/ifcOutput%{cpp_module_output_file}"],
+                        expand_if_available = "cpp_module_output_file",
+                    ),
+                ],
+            ),
+        ],
+        enabled = True,
+    )
     return cc_common.create_cc_toolchain_config_info(
         ctx = ctx,
-        features = features,
+        features = features + [cpp_modules_feature, cpp_module_modmap_file_feature, cpp20_module_compile_flags_feature],
         action_configs = action_configs,
         artifact_name_patterns = artifact_name_patterns,
         cxx_builtin_include_directories = ctx.attr.cxx_builtin_include_directories,
@@ -1307,6 +1633,7 @@
         abi_version = ctx.attr.abi_version,
         abi_libc_version = ctx.attr.abi_libc_version,
         tool_paths = tool_paths,
+        make_variables = make_variables,
     )
 
 cc_toolchain_config = rule(
@@ -1314,12 +1641,14 @@
     attrs = {
         "abi_libc_version": attr.string(),
         "abi_version": attr.string(),
+        "archiver_flags": attr.string_list(default = []),
         "compiler": attr.string(),
         "cpu": attr.string(mandatory = True),
         "cxx_builtin_include_directories": attr.string_list(),
-        "dbg_mode_debug_flag": attr.string(),
+        "dbg_mode_debug_flag": attr.string(default = ""),
+        "default_compile_flags": attr.string_list(default = []),
         "default_link_flags": attr.string_list(default = []),
-        "fastbuild_mode_debug_flag": attr.string(),
+        "fastbuild_mode_debug_flag": attr.string(default = ""),
         "host_system_name": attr.string(),
         "msvc_cl_path": attr.string(default = "vc_installation_error.bat"),
         "msvc_env_include": attr.string(default = "msvc_not_found"),
@@ -1329,6 +1658,7 @@
         "msvc_lib_path": attr.string(default = "vc_installation_error.bat"),
         "msvc_link_path": attr.string(default = "vc_installation_error.bat"),
         "msvc_ml_path": attr.string(default = "vc_installation_error.bat"),
+        "supports_parse_showincludes": attr.bool(),
         "target_libc": attr.string(),
         "target_system_name": attr.string(),
         "tool_bin_path": attr.string(default = "not_found"),
diff --git a/cc/toolchains/BUILD b/cc/toolchains/BUILD
index 6c876ba..98fe2cf 100644
--- a/cc/toolchains/BUILD
+++ b/cc/toolchains/BUILD
@@ -14,7 +14,10 @@
 
 load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
 load("@bazel_skylib//rules:diff_test.bzl", "diff_test")
+load("@bazel_skylib//rules:expand_template.bzl", "expand_template")
 load("@stardoc//stardoc:stardoc.bzl", "stardoc")
+load("//cc/toolchains/impl:documented_api.bzl", "DOCUMENTED_TOOLCHAIN_RULES")
+load("//cc/toolchains/impl:markdown_helpers.bzl", "xref_substitutions")
 
 bzl_library(
     name = "toolchain_rules",
@@ -42,11 +45,30 @@
 
 stardoc(
     name = "toolchain_api",
-    out = "generated_toolchain_api.md",
+    out = "raw_generated_toolchain_api.md",
     input = "//cc/toolchains/impl:documented_api.bzl",
     deps = [":toolchain_rules"],
 )
 
+expand_template(
+    name = "toolchain_api_md",
+    out = "generated_toolchain_api.md",
+    # Dictionary order 100% matters here!
+    # buildifier: disable=unsorted-dict-items
+    substitutions = {
+        # Strip @rules_cc to prevent instances of @rules_cc@rules_cc//cc.
+        "@rules_cc//cc": "//cc",
+        # In GitHub, we prefer to clarify all the labels that come from
+        # rules_cc.
+        "//cc": "@rules_cc//cc",
+    } | xref_substitutions({
+        "`{}`".format(rule_name): "#{}".format(rule_name)
+        for rule_name in DOCUMENTED_TOOLCHAIN_RULES
+    }),
+    # buildifier: enable=unsorted-dict-items
+    template = ":raw_generated_toolchain_api.md",
+)
+
 diff_test(
     name = "toolchain_api_diff_test",
     file1 = ":generated_toolchain_api.md",
diff --git a/cc/toolchains/actions.bzl b/cc/toolchains/actions.bzl
index fc91787..3193b7d 100644
--- a/cc/toolchains/actions.bzl
+++ b/cc/toolchains/actions.bzl
@@ -37,14 +37,26 @@
     },
     doc = """A type of action (eg. c_compile, assemble, strip).
 
-Example:
+`cc_action_type` rules are used to associate arguments and tools together to
+perform a specific action. Bazel prescribes a set of known action types that are used to drive
+typical C/C++/ObjC actions like compiling, linking, and archiving. The set of well-known action
+types can be found in [//third_party/bazel_rules/rules_cc/cc/toolchains/actions:BUILD](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/actions/BUILD).
 
-load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES")
+It's possible to create project-specific action types for use in toolchains. Be careful when
+doing this, because every toolchain that encounters the action will need to be configured to
+support the custom action type. If your project is a library, avoid creating new action types as
+it will reduce compatibility with existing toolchains and increase setup complexity for users.
+
+Example:
+```
+load("//cc:action_names.bzl", "ACTION_NAMES")
+load("//cc/toolchains:actions.bzl", "cc_action_type")
 
 cc_action_type(
-  name = "cpp_compile",
-  action_name =  = ACTION_NAMES.cpp_compile,
+    name = "cpp_compile",
+    action_name =  = ACTION_NAMES.cpp_compile,
 )
+```
 """,
     provides = [ActionTypeInfo, ActionTypeSetInfo],
 )
@@ -60,15 +72,21 @@
 cc_action_type_set = rule(
     doc = """Represents a set of actions.
 
+This is a convenience rule to allow for more compact representation of a group of action types.
+Use this anywhere a `cc_action_type` is accepted.
+
 Example:
+```
+load("//cc/toolchains:actions.bzl", "cc_action_type_set")
 
 cc_action_type_set(
     name = "link_executable_actions",
     actions = [
-        ":cpp_link_executable",
-        ":lto_index_for_executable",
+        "//cc/toolchains/actions:cpp_link_executable",
+        "//cc/toolchains/actions:lto_index_for_executable",
     ],
 )
+```
 """,
     implementation = _cc_action_type_set_impl,
     attrs = {
diff --git a/cc/toolchains/actions/BUILD b/cc/toolchains/actions/BUILD
index 164a336..9eb0ce7 100644
--- a/cc/toolchains/actions/BUILD
+++ b/cc/toolchains/actions/BUILD
@@ -54,6 +54,21 @@
 )
 
 cc_action_type(
+    name = "cpp_module_deps_scanning",
+    action_name = ACTION_NAMES.cpp_module_deps_scanning,
+)
+
+cc_action_type(
+    name = "cpp20_module_compile",
+    action_name = ACTION_NAMES.cpp20_module_compile,
+)
+
+cc_action_type(
+    name = "cpp20_module_codegen",
+    action_name = ACTION_NAMES.cpp20_module_codegen,
+)
+
+cc_action_type(
     name = "cpp_module_compile",
     action_name = ACTION_NAMES.cpp_module_compile,
 )
@@ -69,6 +84,11 @@
 )
 
 cc_action_type(
+    name = "llvm_cov",
+    action_name = ACTION_NAMES.llvm_cov,
+)
+
+cc_action_type(
     name = "lto_indexing",
     action_name = ACTION_NAMES.lto_indexing,
 )
@@ -120,7 +140,12 @@
 
 cc_action_type(
     name = "objcopy_embed_data",
-    action_name = "objcopy_embed_data",
+    action_name = ACTION_NAMES.objcopy_embed_data,
+)
+
+cc_action_type(
+    name = "validate_static_library",
+    action_name = ACTION_NAMES.validate_static_library,
 )
 
 # ld_embed_data is only available within google.
@@ -210,6 +235,8 @@
         ":cpp_compile_actions",
         ":c_compile_actions",
         ":assembly_actions",
+        ":objc_compile",
+        ":objcpp_compile",
     ],
 )
 
@@ -266,9 +293,13 @@
         ":cpp_module_codegen",
         ":cpp_header_analysis",
         ":cpp_header_parsing",
+        ":cpp_module_deps_scanning",
+        ":cpp20_module_compile",
+        ":cpp20_module_codegen",
         ":cpp_module_compile",
         ":assemble",
         ":preprocess_assemble",
+        ":llvm_cov",
         ":lto_indexing",
         ":lto_backend",
         ":lto_index_for_executable",
@@ -287,5 +318,6 @@
         ":objcpp_compile",
         ":objcpp_executable",
         ":clif_match",
+        ":validate_static_library",
     ],
 )
diff --git a/cc/toolchains/args.bzl b/cc/toolchains/args.bzl
index eb3833e..bdcf7ce 100644
--- a/cc/toolchains/args.bzl
+++ b/cc/toolchains/args.bzl
@@ -139,9 +139,10 @@
 
     This rule is the fundamental building building block for every toolchain tool invocation. Each
     argument expressed in a toolchain tool invocation (e.g. `gcc`, `llvm-ar`) is declared in a
-    `cc_args` rule that applies an ordered list of arguments to a set of toolchain actions.
-    `cc_args` rules can be added unconditionally to a `cc_toolchain`, conditionally via `select()`
-    statements, or dynamically via an intermediate `cc_feature`.
+    `cc_args` rule that applies an ordered list of arguments to a set of toolchain
+    actions. `cc_args` rules can be added unconditionally to a
+    `cc_toolchain`, conditionally via `select()` statements, or dynamically via an
+    intermediate `cc_feature`.
 
     Conceptually, this is similar to the old `CFLAGS`, `CPPFLAGS`, etc. environment variables that
     many build systems use to determine which flags to use for a given action. The significant
@@ -208,49 +209,62 @@
 
     Args:
         name: (str) The name of the target.
-        actions: (List[Label]) A list of labels of `cc_action_type` or `cc_action_type_set` rules
-            that dictate which actions these arguments should be applied to.
+        actions: (List[Label]) A list of labels of `cc_action_type` or
+            `cc_action_type_set` rules that dictate which actions these
+            arguments should be applied to.
         allowlist_include_directories: (List[Label]) A list of include paths that are implied by
             using this rule. These must point to a skylib
-            [directory](https://github.com/bazelbuild/bazel-skylib/blob/main/docs/directory_doc.md#directory)
-            or [subdirectory](https://github.com/bazelbuild/bazel-skylib/blob/main/docs/directory_subdirectory_doc.md#subdirectory) rule.
+            [directory](https://github.com/bazelbuild/bazel-skylib/tree/main/doc/directory_doc.md#directory)
+            or [subdirectory](https://github.com/bazelbuild/bazel-skylib/tree/main/doc/directory_subdirectory_doc.md#subdirectory) rule.
             Some flags (e.g. --sysroot) imply certain include paths are available despite
             not explicitly specifying a normal include path flag (`-I`, `-isystem`, etc.).
             Bazel checks that all included headers are properly provided by a dependency or
             allowlisted through this mechanism.
+
+            As a rule of thumb, only use this if Bazel is complaining about absolute paths in
+            your toolchain and you've ensured that the toolchain is compiling with the
+            `-no-canonical-prefixes` and/or `-fno-canonical-system-headers` arguments.
+
+            This can help work around errors like:
+            `the source file 'main.c' includes the following non-builtin files with absolute paths
+            (if these are builtin files, make sure these paths are in your toolchain)`.
         args: (List[str]) The command-line arguments that are applied by using this rule. This is
             mutually exclusive with [nested](#cc_args-nested).
         data: (List[Label]) A list of runtime data dependencies that are required for these
             arguments to work as intended.
         env: (Dict[str, str]) Environment variables that should be set when the tool is invoked.
         format: (Dict[str, Label]) A mapping of format strings to the label of the corresponding
-            `cc_variable` that the value should be pulled from. All instances of `{variable_name}`
-            will be replaced with the expanded value of `variable_name` in this dictionary. The
-            complete list of possible variables can be found in
-            https://github.com/bazelbuild/rules_cc/blob/main/cc/toolchains/variables/BUILD. it is
-            not possible to declare custom variables--these are inherent to Bazel itself.
+            `cc_variable` that the value should be pulled from. All instances of
+            `{variable_name}` will be replaced with the expanded value of `variable_name` in this
+            dictionary. The complete list of possible variables can be found in
+            https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/variables/BUILD.
+            It is not possible to declare custom variables--these are inherent to Bazel itself.
         iterate_over: (Label) The label of a `cc_variable` that should be iterated over. This is
             intended for use with built-in variables that are lists.
-        nested: (List[Label]) A list of [cc_nested_args](#cc_nested_args) rules that should be
+        nested: (List[Label]) A list of `cc_nested_args` rules that should be
             expanded to command-line arguments when this rule is used. This is mutually exclusive
             with [args](#cc_args-args).
-        requires_not_none: (Label) The label of a `cc_variable` that should be checked for
-            existence before expanding this rule. If the variable is None, this rule will be
+        requires_not_none: (Label) The label of a `cc_variable` that should be checked
+            for existence before expanding this rule. If the variable is None, this rule will be
             ignored.
-        requires_none: (Label) The label of a `cc_variable` that should be checked for non-existence
-            before expanding this rule. If the variable is not None, this rule will be ignored.
-        requires_true: (Label) The label of a `cc_variable` that should be checked for truthiness
-            before expanding this rule. If the variable is false, this rule will be ignored.
-        requires_false: (Label) The label of a `cc_variable` that should be checked for falsiness
-            before expanding this rule. If the variable is true, this rule will be ignored.
-        requires_equal: (Label) The label of a `cc_variable` that should be checked for equality
-            before expanding this rule. If the variable is not equal to
+        requires_none: (Label) The label of a `cc_variable` that should be checked for
+            non-existence before expanding this rule. If the variable is not None, this rule will be
+            ignored.
+        requires_true: (Label) The label of a `cc_variable` that should be checked for
+            truthiness before expanding this rule. If the variable is false, this rule will be
+            ignored.
+        requires_false: (Label) The label of a `cc_variable` that should be checked
+            for falsiness before expanding this rule. If the variable is true, this rule will be
+            ignored.
+        requires_equal: (Label) The label of a `cc_variable` that should be checked
+            for equality before expanding this rule. If the variable is not equal to
             (requires_equal_value)[#cc_args-requires_equal_value], this rule will be ignored.
         requires_equal_value: (str) The value to compare (requires_equal)[#cc_args-requires_equal]
             against.
         requires_any_of: (List[Label]) These arguments will be used
-            in a tool invocation when at least one of the `cc_feature_constraint` entries in this
-            list are satisfied. If omitted, this flag set will be enabled unconditionally.
+            in a tool invocation when at least one of the [cc_feature_constraint](#cc_feature_constraint)
+            entries in this list are satisfied. If omitted, this flag set will be enabled
+            unconditionally.
         **kwargs: [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule.
     """
     return _cc_args(
diff --git a/cc/toolchains/args_list.bzl b/cc/toolchains/args_list.bzl
index 1f93a84..0747acb 100644
--- a/cc/toolchains/args_list.bzl
+++ b/cc/toolchains/args_list.bzl
@@ -26,7 +26,7 @@
     implementation = _cc_args_list_impl,
     doc = """An ordered list of cc_args.
 
-    This is a convenience rule to allow you to group a set of multiple [cc_args](#cc_args) into a
+    This is a convenience rule to allow you to group a set of multiple `cc_args` into a
     single list. This particularly useful for toolchain behaviors that require different flags for
     different actions.
 
diff --git a/cc/toolchains/capabilities/BUILD b/cc/toolchains/capabilities/BUILD
new file mode 100644
index 0000000..8c55804
--- /dev/null
+++ b/cc/toolchains/capabilities/BUILD
@@ -0,0 +1,19 @@
+load("//cc/toolchains:tool_capability.bzl", "cc_tool_capability")
+
+package(default_visibility = ["//visibility:public"])
+
+cc_tool_capability(
+    name = "supports_start_end_lib",
+)
+
+cc_tool_capability(
+    name = "supports_interface_shared_libraries",
+)
+
+cc_tool_capability(
+    name = "supports_dynamic_linker",
+)
+
+cc_tool_capability(
+    name = "supports_pic",
+)
diff --git a/cc/toolchains/cc_flags_supplier.bzl b/cc/toolchains/cc_flags_supplier.bzl
index 363575f..17adbad 100644
--- a/cc/toolchains/cc_flags_supplier.bzl
+++ b/cc/toolchains/cc_flags_supplier.bzl
@@ -28,7 +28,7 @@
 cc_flags_supplier = rule(
     implementation = _cc_flags_supplier_impl,
     attrs = {
-        "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")),
+        "_cc_toolchain": attr.label(default = Label("@rules_cc//cc:current_cc_toolchain")),
     },
     toolchains = use_cc_toolchain(),
     fragments = ["cpp"],
diff --git a/cc/toolchains/cc_toolchain_info.bzl b/cc/toolchains/cc_toolchain_info.bzl
index 2325ddb..17881a8 100644
--- a/cc/toolchains/cc_toolchain_info.bzl
+++ b/cc/toolchains/cc_toolchain_info.bzl
@@ -156,6 +156,16 @@
         "runfiles": "(runfiles) The files required to run the tool",
         "execution_requirements": "(Sequence[str]) A set of execution requirements of the tool",
         "allowlist_include_directories": "(depset[DirectoryInfo]) Built-in include directories implied by this tool that should be allowlisted in Bazel's include checker",
+        "capabilities": "(Sequence[ToolCapabilityInfo]) Capabilities supported by the tool.",
+    },
+)
+
+ToolCapabilityInfo = provider(
+    doc = "A capability associated with a tool (eg. supports_pic).",
+    # @unsorted-dict-items
+    fields = {
+        "label": "(Label) The label defining this provider. Place in error messages to simplify debugging",
+        "feature": "(FeatureInfo) The feature this capability defines",
     },
 )
 
diff --git a/cc/toolchains/compiler_flag.bzl b/cc/toolchains/compiler_flag.bzl
index ac943df..502efe7 100644
--- a/cc/toolchains/compiler_flag.bzl
+++ b/cc/toolchains/compiler_flag.bzl
@@ -23,7 +23,7 @@
 compiler_flag = rule(
     implementation = _compiler_flag_impl,
     attrs = {
-        "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")),
+        "_cc_toolchain": attr.label(default = Label("@rules_cc//cc:current_cc_toolchain")),
     },
     toolchains = use_cc_toolchain(),
 )
diff --git a/cc/toolchains/feature.bzl b/cc/toolchains/feature.bzl
index a282762..f0acbfe 100644
--- a/cc/toolchains/feature.bzl
+++ b/cc/toolchains/feature.bzl
@@ -110,22 +110,23 @@
 toolchain, they can happily live alongside each other in the same BUILD file.
 
 Example:
+```
+cc_feature(
+    name = "sysroot_macos",
+    feature_name = "sysroot",
+    ...
+)
 
-    cc_feature(
-        name = "sysroot_macos",
-        feature_name = "sysroot",
-        ...
-    )
-
-    cc_feature(
-        name = "sysroot_linux",
-        feature_name = "sysroot",
-        ...
-    )
+cc_feature(
+    name = "sysroot_linux",
+    feature_name = "sysroot",
+    ...
+)
+```
 """,
         ),
         "args": attr.label_list(
-            doc = """Args that, when expanded, implement this feature.""",
+            doc = """A list of `cc_args` or `cc_args_list` labels that are expanded when this feature is enabled.""",
             providers = [ArgsListInfo],
         ),
         "requires_any_of": attr.label_list(
@@ -152,7 +153,7 @@
         ),
         "mutually_exclusive": attr.label_list(
             providers = [MutuallyExclusiveCategoryInfo],
-            doc = """A list of things that this is mutually exclusive with.
+            doc = """A list of things that this feature is mutually exclusive with.
 
 It can be either:
 * A feature, in which case the two features are mutually exclusive.
@@ -171,14 +172,16 @@
 that the feature "opt" was defined twice.
 
 Example:
+```
+load("//cc/toolchains:feature.bzl", "cc_feature")
 
-    cc_feature(
-      name = "opt",
-      feature_name = "opt",
-      ...
-      overrides = "@toolchain//features/well_known:opt",
-    )
-
+cc_feature(
+    name = "opt",
+    feature_name = "opt",
+    args = [":size_optimized"],
+    overrides = "//cc/toolchains/features:opt",
+)
+```
 """,
         ),
     },
@@ -188,53 +191,58 @@
         FeatureConstraintInfo,
         MutuallyExclusiveCategoryInfo,
     ],
-    doc = """Defines the implemented behavior of a C/C++ toolchain feature.
+    doc = """A dynamic set of toolchain flags that create a singular [feature](https://bazel.build/docs/cc-toolchain-config-reference#features) definition.
 
-A feature is basically a toggleable list of args. There are a variety of
-dependencies and compatibility requirements that must be satisfied for the
-listed args to be applied.
+A feature is basically a dynamically toggleable `cc_args_list`. There are a variety of
+dependencies and compatibility requirements that must be satisfied to enable a
+`cc_feature`. Once those conditions are met, the arguments in [`cc_feature.args`](#cc_feature-args)
+are expanded and added to the command-line.
 
 A feature may be enabled or disabled through the following mechanisms:
-* Via command-line flags, or a `.bazelrc`.
-* Through inter-feature relationships (enabling one feature may implicitly
-  enable another).
-* Individual rules may elect to manually enable or disable features through the
-  builtin `features` attribute.
+* Via command-line flags, or a `.bazelrc` file via the
+  [`--features` flag](https://bazel.build/reference/command-line-reference#flag--features)
+* Through inter-feature relationships (via [`cc_feature.implies`](#cc_feature-implies)) where one
+  feature may implicitly enable another.
+* Individual rules (e.g. `cc_library`) or `package` definitions may elect to manually enable or
+  disable features through the
+  [`features` attribute](https://bazel.build/reference/be/common-definitions#common.features).
 
-Because of the toggleable nature of toolchain features, it's generally best to
-avoid defining features as part of your toolchain with the following exceptions:
-* You want build files to be able to configure compiler flags. For example, a
+Note that a feature may alternate between enabled and disabled dynamically over the course of a
+build. Because of their toggleable nature, it's generally best to avoid adding arguments to a
+`cc_toolchain` as a `cc_feature` unless strictly necessary. Instead, prefer to express arguments
+via [`cc_toolchain.args`](#cc_toolchain-args) whenever possible.
+
+You should use a `cc_feature` when any of the following apply:
+* You need the flags to be dynamically toggled over the course of a build.
+* You want build files to be able to configure the flags in question. For example, a
   binary might specify `features = ["optimize_for_size"]` to create a small
   binary instead of optimizing for performance.
 * You need to carry forward Starlark toolchain behaviors. If you're migrating a
   complex Starlark-based toolchain definition to these rules, many of the
-  workflows and flags were likely based on features. This rule exists to support
-  those existing structures.
+  workflows and flags were likely based on features.
 
-If you want to be able to configure flags via the bazel command-line, instead
-consider making a bool_flag, and then making your `cc_args` `select` on those
-flags.
+If you only need to configure flags via the Bazel command-line, instead
+consider adding a
+[`bool_flag`](https://github.com/bazelbuild/bazel-skylib/tree/main/doc/common_settings_doc.md#bool_flag)
+paired with a [`config_setting`](https://bazel.build/reference/be/general#config_setting)
+and then make your `cc_args` rule `select` on the `config_setting`.
 
 For more details about how Bazel handles features, see the official Bazel
 documentation at
 https://bazel.build/docs/cc-toolchain-config-reference#features.
 
-Examples:
+Example:
+```
+load("//cc/toolchains:feature.bzl", "cc_feature")
 
-    # A feature that can be easily toggled to optimize for size
-    cc_feature(
-        name = "optimize_for_size",
-        feature_name = "optimize_for_size",
-        args = [":optimize_for_size_args"],
-    )
-
-    # This feature signals a capability, and doesn't have associated flags.
-    #
-    # For a list of well-known features, see:
-    #    https://bazel.build/docs/cc-toolchain-config-reference#wellknown-features
-    cc_feature(
-        name = "supports_pic",
-        overrides = "//cc/toolchains/features:supports_pic
-    )
+# A feature that enables LTO, which may be incompatible when doing interop with various
+# languages (e.g. rust, go), or may need to be disabled for particular `cc_binary` rules
+# for various reasons.
+cc_feature(
+    name = "lto",
+    feature_name = "lto",
+    args = [":lto_args"],
+)
+```
 """,
 )
diff --git a/cc/toolchains/feature_constraint.bzl b/cc/toolchains/feature_constraint.bzl
index c6ae44a..8a3d60f 100644
--- a/cc/toolchains/feature_constraint.bzl
+++ b/cc/toolchains/feature_constraint.bzl
@@ -47,8 +47,26 @@
         ),
     },
     provides = [FeatureConstraintInfo],
-    doc = """Defines a constraint on features.
+    doc = """Defines a compound relationship between features.
 
-Can be used with require_any_of to specify that something is only enabled when
-a constraint is met.""",
+This rule can be used with [`cc_args.require_any_of`](#cc_args-require_any_of) to specify that a set
+of arguments are only enabled when a constraint is met. Both `all_of` and `none_of` must be
+satisfied simultaneously.
+
+This is basically a `cc_feature_set` that supports `none_of` expressions. This extra flexibility
+is why this rule may only be used by [`cc_args.require_any_of`](#cc_args-require_any_of).
+
+Example:
+```
+load("//cc/toolchains:feature_constraint.bzl", "cc_feature_constraint")
+
+# A constraint that requires a `linker_supports_thinlto` feature to be enabled,
+# AND a `no_optimization` to be disabled.
+cc_feature_constraint(
+    name = "thinlto_constraint",
+    all_of = [":linker_supports_thinlto"],
+    none_of = [":no_optimization"],
+)
+```
+""",
 )
diff --git a/cc/toolchains/feature_set.bzl b/cc/toolchains/feature_set.bzl
index 07af6d1..5fcdae4 100644
--- a/cc/toolchains/feature_set.bzl
+++ b/cc/toolchains/feature_set.bzl
@@ -44,14 +44,20 @@
     provides = [FeatureSetInfo],
     doc = """Defines a set of features.
 
-Example:
+This may be used by both `cc_feature` and `cc_args` rules, and is effectively a way to express
+a logical `AND` operation across multiple requred features.
 
-    cc_feature_set(
-        name = "thin_lto_requirements",
-        all_of = [
-            ":thin_lto",
-            ":opt",
-        ],
-    )
+Example:
+```
+load("//cc/toolchains:feature_set.bzl", "cc_feature_set")
+
+cc_feature_set(
+    name = "thin_lto_requirements",
+    all_of = [
+        ":thin_lto",
+        ":opt",
+    ],
+)
+```
 """,
 )
diff --git a/cc/toolchains/features/BUILD b/cc/toolchains/features/BUILD
index 6c6088b..22c3519 100644
--- a/cc/toolchains/features/BUILD
+++ b/cc/toolchains/features/BUILD
@@ -42,35 +42,11 @@
 )
 
 cc_external_feature(
-    name = "supports_start_end_lib",
-    feature_name = "supports_start_end_lib",
-    overridable = True,
-)
-
-cc_external_feature(
-    name = "supports_interface_shared_libraries",
-    feature_name = "supports_interface_shared_libraries",
-    overridable = True,
-)
-
-cc_external_feature(
-    name = "supports_dynamic_linker",
-    feature_name = "supports_dynamic_linker",
-    overridable = True,
-)
-
-cc_external_feature(
     name = "static_link_cpp_runtimes",
     feature_name = "static_link_cpp_runtimes",
     overridable = True,
 )
 
-cc_external_feature(
-    name = "supports_pic",
-    feature_name = "supports_pic",
-    overridable = True,
-)
-
 cc_feature_set(
     name = "all_non_legacy_builtin_features",
     all_of = [
@@ -80,11 +56,7 @@
         ":static_linking_mode",
         ":dynamic_linking_mode",
         ":per_object_debug_info",
-        ":supports_start_end_lib",
-        ":supports_interface_shared_libraries",
-        ":supports_dynamic_linker",
         ":static_link_cpp_runtimes",
-        ":supports_pic",
     ],
     visibility = ["//visibility:private"],
 )
diff --git a/cc/toolchains/impl/collect.bzl b/cc/toolchains/impl/collect.bzl
index f41aa7d..e242d91 100644
--- a/cc/toolchains/impl/collect.bzl
+++ b/cc/toolchains/impl/collect.bzl
@@ -107,6 +107,7 @@
                 runfiles = collect_data(ctx, [target]),
                 execution_requirements = tuple(),
                 allowlist_include_directories = depset(),
+                capabilities = tuple(),
             ))
         else:
             fail("Expected %s to be a cc_tool or a binary rule" % target.label)
diff --git a/cc/toolchains/impl/documented_api.bzl b/cc/toolchains/impl/documented_api.bzl
index b2ca091..f1f634e 100644
--- a/cc/toolchains/impl/documented_api.bzl
+++ b/cc/toolchains/impl/documented_api.bzl
@@ -13,12 +13,51 @@
 # limitations under the License.
 """This is a list of rules/macros that should be exported as documentation."""
 
+load("//cc/toolchains:actions.bzl", _cc_action_type = "cc_action_type", _cc_action_type_set = "cc_action_type_set")
 load("//cc/toolchains:args.bzl", _cc_args = "cc_args")
 load("//cc/toolchains:args_list.bzl", _cc_args_list = "cc_args_list")
+load("//cc/toolchains:feature.bzl", _cc_feature = "cc_feature")
+load("//cc/toolchains:feature_constraint.bzl", _cc_feature_constraint = "cc_feature_constraint")
+load("//cc/toolchains:feature_set.bzl", _cc_feature_set = "cc_feature_set")
+load("//cc/toolchains:mutually_exclusive_category.bzl", _cc_mutually_exclusive_category = "cc_mutually_exclusive_category")
 load("//cc/toolchains:nested_args.bzl", _cc_nested_args = "cc_nested_args")
+load("//cc/toolchains:tool.bzl", _cc_tool = "cc_tool")
+load("//cc/toolchains:tool_capability.bzl", _cc_tool_capability = "cc_tool_capability")
 load("//cc/toolchains:tool_map.bzl", _cc_tool_map = "cc_tool_map")
+load("//cc/toolchains/impl:external_feature.bzl", _cc_external_feature = "cc_external_feature")
+load("//cc/toolchains/impl:variables.bzl", _cc_variable = "cc_variable")
 
 cc_tool_map = _cc_tool_map
+cc_tool = _cc_tool
+cc_tool_capability = _cc_tool_capability
 cc_args = _cc_args
 cc_nested_args = _cc_nested_args
 cc_args_list = _cc_args_list
+cc_action_type = _cc_action_type
+cc_action_type_set = _cc_action_type_set
+cc_variable = _cc_variable
+cc_feature = _cc_feature
+cc_feature_constraint = _cc_feature_constraint
+cc_feature_set = _cc_feature_set
+cc_mutually_exclusive_category = _cc_mutually_exclusive_category
+cc_external_feature = _cc_external_feature
+
+# This list is used to automatically remap instances of `foo` to [`foo`](#foo)
+# links in the generated documentation so that maintainers don't need to manually
+# ensure every reference to a rule is properly linked.
+DOCUMENTED_TOOLCHAIN_RULES = [
+    "cc_tool_map",
+    "cc_tool",
+    "cc_tool_capability",
+    "cc_args",
+    "cc_nested_args",
+    "cc_args_list",
+    "cc_action_type",
+    "cc_action_type_set",
+    "cc_variable",
+    "cc_feature",
+    "cc_feature_constraint",
+    "cc_feature_set",
+    "cc_mutually_exclusive_category",
+    "cc_external_feature",
+]
diff --git a/cc/toolchains/impl/external_feature.bzl b/cc/toolchains/impl/external_feature.bzl
index 1e11bc9..027738f 100644
--- a/cc/toolchains/impl/external_feature.bzl
+++ b/cc/toolchains/impl/external_feature.bzl
@@ -69,5 +69,26 @@
         ),
     },
     provides = [FeatureInfo, FeatureSetInfo, FeatureConstraintInfo],
-    doc = "A declaration that a feature with this name is defined elsewhere.",
+    doc = """A declaration that a [feature](https://bazel.build/docs/cc-toolchain-config-reference#features) with this name is defined elsewhere.
+
+This rule communicates that a feature has been defined externally to make it possible to reference
+features that live outside the rule-based cc toolchain ecosystem. This allows various toolchain
+rules to reference the external feature without accidentally re-defining said feature.
+
+This rule is currently considered a private API of the toolchain rules to encourage the Bazel
+ecosystem to migrate to properly defining their features as rules.
+
+Example:
+```
+load("//cc/toolchains:external_feature.bzl", "cc_external_feature")
+
+# rules_rust defines a feature that is disabled whenever rust artifacts are being linked using
+# the cc toolchain to signal that incompatible flags should be disabled as well.
+cc_external_feature(
+    name = "rules_rust_unsupported_feature",
+    feature_name = "rules_rust_unsupported_feature",
+    overridable = False,
+)
+```
+""",
 )
diff --git a/cc/toolchains/impl/legacy_converter.bzl b/cc/toolchains/impl/legacy_converter.bzl
index 7197716..64fea95 100644
--- a/cc/toolchains/impl/legacy_converter.bzl
+++ b/cc/toolchains/impl/legacy_converter.bzl
@@ -131,16 +131,30 @@
         with_features = [],
     )
 
+def convert_capability(capability):
+    return legacy_feature(
+        name = capability.name,
+        enabled = False,
+    )
+
 def _convert_tool_map(tool_map):
-    return [
-        legacy_action_config(
+    action_configs = []
+    caps = {}
+    for action_type, tool in tool_map.configs.items():
+        action_configs.append(legacy_action_config(
             action_name = action_type.name,
             enabled = True,
-            tools = [convert_tool(tool_map.configs[action_type])],
-            implies = [],
-        )
-        for action_type in tool_map.configs.keys()
+            tools = [convert_tool(tool)],
+            implies = [cap.feature.name for cap in tool.capabilities],
+        ))
+        for cap in tool.capabilities:
+            caps[cap] = None
+
+    cap_features = [
+        legacy_feature(name = cap.feature.name, enabled = False)
+        for cap in caps
     ]
+    return action_configs, cap_features
 
 def convert_toolchain(toolchain):
     """Converts a rule-based toolchain into the legacy providers.
@@ -155,6 +169,8 @@
         convert_feature(feature, enabled = feature in toolchain.enabled_features)
         for feature in toolchain.features
     ]
+    action_configs, cap_features = _convert_tool_map(toolchain.tool_map)
+    features.extend(cap_features)
     features.append(convert_feature(FeatureInfo(
         # We reserve names starting with implied_by. This ensures we don't
         # conflict with the name of a feature the user creates.
@@ -167,7 +183,6 @@
         external = False,
         allowlist_include_directories = depset(),
     )))
-    action_configs = _convert_tool_map(toolchain.tool_map)
 
     cxx_builtin_include_directories = [
         d.path
diff --git a/cc/toolchains/impl/markdown_helpers.bzl b/cc/toolchains/impl/markdown_helpers.bzl
new file mode 100644
index 0000000..1ae401f
--- /dev/null
+++ b/cc/toolchains/impl/markdown_helpers.bzl
@@ -0,0 +1,53 @@
+# Copyright 2024 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""A few small helpers for working with Markdown."""
+
+def markdown_link(link_text, href):
+    """Creates a markdown link.
+
+    Args:
+      link_text: The text to display for the link.
+      href: The href for the link.
+
+    Returns:
+      A markdown link.
+    """
+    return "[" + link_text + "](" + href + ")"
+
+def xref_substitutions(match_text_patterns):
+    """Creates a dictionary of substitutions for use for linkification of text.
+
+    Example:
+    ```
+    # Produces a dictionary containing:
+    #   {
+    #     "foo": "[foo](http://foo.com)"
+    #     "bar": "[bar](http://bar.com)"
+    #   }
+    substitutions = xref_substitutions({
+        "foo": "http://foo.com",
+        "bar": "http://bar.com",
+    })
+    ```
+
+    Args:
+      match_text_patterns: A dictionary mapping string literals to the links they should point to.
+
+    Returns:
+      A dictionary of string literals mapped to their linkified substitutions.
+    """
+    return {
+        match_text: markdown_link(match_text, href)
+        for match_text, href in match_text_patterns.items()
+    }
diff --git a/cc/toolchains/impl/toolchain_config_info.bzl b/cc/toolchains/impl/toolchain_config_info.bzl
index 7e68b15..0fa499d 100644
--- a/cc/toolchains/impl/toolchain_config_info.bzl
+++ b/cc/toolchains/impl/toolchain_config_info.bzl
@@ -54,9 +54,9 @@
     # This should be sufficiently unique.
     return (feature.label, feature.name)
 
-def _get_known_features(features, fail):
+def _get_known_features(features, capability_features, fail):
     feature_names = {}
-    for ft in features:
+    for ft in capability_features + features:
         if ft.name in feature_names:
             other = feature_names[ft.name]
             if other.overrides != ft and ft.overrides != other:
@@ -113,7 +113,10 @@
     _validate_implies(self, known_features, fail = fail)
 
 def _validate_toolchain(self, fail = fail):
-    known_features = _get_known_features(self.features, fail = fail)
+    capabilities = []
+    for tool in self.tool_map.configs.values():
+        capabilities.extend([cap.feature for cap in tool.capabilities])
+    known_features = _get_known_features(self.features, capabilities, fail = fail)
 
     for feature in self.features:
         _validate_feature(feature, known_features, fail = fail)
diff --git a/cc/toolchains/impl/variables.bzl b/cc/toolchains/impl/variables.bzl
index c2820f3..35cc84a 100644
--- a/cc/toolchains/impl/variables.bzl
+++ b/cc/toolchains/impl/variables.bzl
@@ -67,19 +67,32 @@
 )
 
 def cc_variable(name, type, **kwargs):
-    """Defines a variable for both the specified variable, and all nested ones.
+    """Exposes a toolchain variable to use in toolchain argument expansions.
 
-    Eg. cc_variable(
-      name = "foo",
-      type = types.list(types.struct(bar = types.string))
+    This internal rule exposes [toolchain variables](https://bazel.build/docs/cc-toolchain-config-reference#cctoolchainconfiginfo-build-variables)
+    that may be expanded in `cc_args` or `cc_nested_args`
+    rules. Because these varaibles merely expose variables inherrent to Bazel,
+    it's not possible to declare custom variables.
+
+    For a full list of available variables, see
+    [//third_party/bazel_rules/rules_cc/cc/toolchains/varaibles:BUILD](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/variables/BUILD).
+
+    Example:
+    ```
+    load("//cc/toolchains/impl:variables.bzl", "cc_variable")
+
+    # Defines two targets, ":foo" and ":foo.bar"
+    cc_variable(
+        name = "foo",
+        type = types.list(types.struct(bar = types.string)),
     )
-
-    would define two targets, ":foo" and ":foo.bar"
+    ```
 
     Args:
         name: (str) The name of the outer variable, and the rule.
-        type: The type of the variable, constructed using types above.
-        **kwargs: kwargs to pass to _cc_variable.
+        type: The type of the variable, constructed using `types` factory in
+            [//third_party/bazel_rules/rules_cc/cc/toolchains/impl:variables.bzl](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/impl/variables.bzl).
+        **kwargs: [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule.
     """
     _cc_variable(name = name, type = json.encode(type), **kwargs)
 
diff --git a/cc/toolchains/mutually_exclusive_category.bzl b/cc/toolchains/mutually_exclusive_category.bzl
index 9920290..f83b554 100644
--- a/cc/toolchains/mutually_exclusive_category.bzl
+++ b/cc/toolchains/mutually_exclusive_category.bzl
@@ -23,7 +23,40 @@
 
 cc_mutually_exclusive_category = rule(
     implementation = _cc_mutually_exclusive_category_impl,
-    doc = "A category of features, for which only one can be enabled",
+    doc = """A rule used to categorize `cc_feature` definitions for which only one can be enabled.
+
+This is used by [`cc_feature.mutually_exclusive`](#cc_feature-mutually_exclusive) to express groups
+of `cc_feature` definitions that are inherently incompatible with each other and must be treated as
+mutually exclusive.
+
+Warning: These groups are keyed by name, so two `cc_mutually_exclusive_category` definitions of the
+same name in different packages will resolve to the same logical group.
+
+Example:
+```
+load("//cc/toolchains:feature.bzl", "cc_feature")
+load("//cc/toolchains:mutually_exclusive_category.bzl", "cc_mutually_exclusive_category")
+
+cc_mutually_exclusive_category(
+    name = "opt_level",
+)
+
+cc_feature(
+    name = "speed_optimized",
+    mutually_exclusive = [":opt_level"],
+)
+
+cc_feature(
+    name = "size_optimized",
+    mutually_exclusive = [":opt_level"],
+)
+
+cc_feature(
+    name = "unoptimized",
+    mutually_exclusive = [":opt_level"],
+)
+```
+""",
     attrs = {},
     provides = [MutuallyExclusiveCategoryInfo],
 )
diff --git a/cc/toolchains/nested_args.bzl b/cc/toolchains/nested_args.bzl
index 0f27a0f..d81dd99 100644
--- a/cc/toolchains/nested_args.bzl
+++ b/cc/toolchains/nested_args.bzl
@@ -56,19 +56,19 @@
         requires_equal = None,
         requires_equal_value = None,
         **kwargs):
-    """Nested arguments for use in more complex cc_args expansions.
+    """Nested arguments for use in more complex `cc_args` expansions.
 
-    While this rule is very similar in shape to [cc_args](#cc_args), it is intended to be used as a
-    dependency of [cc_args](#cc_args) to provide additional arguments that should be applied to the
-    same actions as defined by the parent [cc_args](#cc_args) rule. The key motivation for this rule
+    While this rule is very similar in shape to `cc_args`, it is intended to be used as a
+    dependency of `cc_args` to provide additional arguments that should be applied to the
+    same actions as defined by the parent `cc_args` rule. The key motivation for this rule
     is to allow for more complex variable-based argument expensions.
 
-    Prefer expressing collections of arguments as [cc_args](#cc_args) and
-    [cc_args_list](#cc_args_list) rules when possible.
+    Prefer expressing collections of arguments as `cc_args` and
+    `cc_args_list` rules when possible.
 
     For living examples of how this rule is used, see the usages here:
-        https://github.com/bazelbuild/rules_cc/blob/main/cc/toolchains/args/runtime_library_search_directories/BUILD
-        https://github.com/bazelbuild/rules_cc/blob/main/cc/toolchains/args/libraries_to_link/BUILD
+        https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/args/runtime_library_search_directories/BUILD
+        https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/args/libraries_to_link/BUILD
 
     Note: These examples are non-trivial, but they illustrate when it is absolutely necessary to
     use this rule.
@@ -80,27 +80,30 @@
         data: (List[Label]) A list of runtime data dependencies that are required for these
             arguments to work as intended.
         format: (Dict[str, Label]) A mapping of format strings to the label of the corresponding
-            `cc_variable` that the value should be pulled from. All instances of `{variable_name}`
-            will be replaced with the expanded value of `variable_name` in this dictionary. The
-            complete list of possible variables can be found in
-            https://github.com/bazelbuild/rules_cc/blob/main/cc/toolchains/variables/BUILD. it is
-            not possible to declare custom variables--these are inherent to Bazel itself.
-        iterate_over: (Label) The label of a `cc_variable` that should be iterated over. This is
-            intended for use with built-in variables that are lists.
-        nested: (List[Label]) A list of [cc_nested_args](#cc_nested_args) rules that should be
+            `cc_variable` that the value should be pulled from. All instances of
+            `{variable_name}` will be replaced with the expanded value of `variable_name` in this
+            dictionary. The complete list of possible variables can be found in
+            https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/variables/BUILD.
+            It is not possible to declare custom variables--these are inherent to Bazel itself.
+        iterate_over: (Label) The label of a `cc_variable` that should be iterated
+            over. This is intended for use with built-in variables that are lists.
+        nested: (List[Label]) A list of `cc_nested_args` rules that should be
             expanded to command-line arguments when this rule is used. This is mutually exclusive
             with [args](#cc_nested_args-args).
-        requires_not_none: (Label) The label of a `cc_variable` that should be checked for
-            existence before expanding this rule. If the variable is None, this rule will be
+        requires_not_none: (Label) The label of a `cc_variable` that should be checked
+            for existence before expanding this rule. If the variable is None, this rule will be
             ignored.
-        requires_none: (Label) The label of a `cc_variable` that should be checked for non-existence
-            before expanding this rule. If the variable is not None, this rule will be ignored.
-        requires_true: (Label) The label of a `cc_variable` that should be checked for truthiness
-            before expanding this rule. If the variable is false, this rule will be ignored.
-        requires_false: (Label) The label of a `cc_variable` that should be checked for falsiness
-            before expanding this rule. If the variable is true, this rule will be ignored.
-        requires_equal: (Label) The label of a `cc_variable` that should be checked for equality
-            before expanding this rule. If the variable is not equal to
+        requires_none: (Label) The label of a `cc_variable` that should be checked for
+            non-existence before expanding this rule. If the variable is not None, this rule will be
+            ignored.
+        requires_true: (Label) The label of a `cc_variable` that should be checked for
+            truthiness before expanding this rule. If the variable is false, this rule will be
+            ignored.
+        requires_false: (Label) The label of a `cc_variable` that should be checked
+            for falsiness before expanding this rule. If the variable is true, this rule will be
+            ignored.
+        requires_equal: (Label) The label of a `cc_variable` that should be checked
+            for equality before expanding this rule. If the variable is not equal to
             (requires_equal_value)[#cc_nested_args-requires_equal_value], this rule will be ignored.
         requires_equal_value: (str) The value to compare
             (requires_equal)[#cc_nested_args-requires_equal] against.
diff --git a/cc/toolchains/tool.bzl b/cc/toolchains/tool.bzl
index 159a9d6..9bef3b1 100644
--- a/cc/toolchains/tool.bzl
+++ b/cc/toolchains/tool.bzl
@@ -14,9 +14,10 @@
 """Implementation of cc_tool"""
 
 load("@bazel_skylib//rules/directory:providers.bzl", "DirectoryInfo")
-load("//cc/toolchains/impl:collect.bzl", "collect_data")
+load("//cc/toolchains/impl:collect.bzl", "collect_data", "collect_provider")
 load(
     ":cc_toolchain_info.bzl",
+    "ToolCapabilityInfo",
     "ToolInfo",
 )
 
@@ -38,6 +39,7 @@
         allowlist_include_directories = depset(
             direct = [d[DirectoryInfo] for d in ctx.attr.allowlist_include_directories],
         ),
+        capabilities = tuple(collect_provider(ctx.attr.capabilities, ToolCapabilityInfo)),
     )
 
     link = ctx.actions.declare_file(ctx.label.name)
@@ -66,13 +68,17 @@
             cfg = "exec",
             doc = """The underlying binary that this tool represents.
 
-Usually just a single prebuilt (eg. @sysroot//:bin/clang), but may be any
+Usually just a single prebuilt (eg. @toolchain//:bin/clang), but may be any
 executable label.
 """,
         ),
         "data": attr.label_list(
             allow_files = True,
-            doc = "Additional files that are required for this tool to run.",
+            doc = """Additional files that are required for this tool to run.
+
+Frequently, clang and gcc require additional files to execute as they often shell out to
+other binaries (e.g. `cc1`).
+""",
         ),
         "allowlist_include_directories": attr.label_list(
             providers = [DirectoryInfo],
@@ -82,23 +88,48 @@
 unless flags like `-nostdinc` are provided. Bazel checks that all included
 headers are properly provided by a dependency or allowlisted through this
 mechanism.
+
+As a rule of thumb, only use this if Bazel is complaining about absolute paths in your
+toolchain and you've ensured that the toolchain is compiling with the `-no-canonical-prefixes`
+and/or `-fno-canonical-system-headers` arguments.
+
+This can help work around errors like:
+`the source file 'main.c' includes the following non-builtin files with absolute paths
+(if these are builtin files, make sure these paths are in your toolchain)`.
+""",
+        ),
+        "capabilities": attr.label_list(
+            providers = [ToolCapabilityInfo],
+            doc = """Declares that a tool is capable of doing something.
+
+For example, `//third_party/bazel_rules/rules_cc/cc/toolchains/capabilities:supports_pic`.
 """,
         ),
     },
     provides = [ToolInfo],
-    doc = """Declares a tool that can be bound to action configs.
+    doc = """Declares a tool for use by toolchain actions.
 
-A tool is a binary with extra metadata for the action config rule to consume
-(eg. execution_requirements).
+`cc_tool` rules are used in a `cc_tool_map` rule to ensure all files and
+metadata required to run a tool are available when constructing a `cc_toolchain`.
+
+In general, include all files that are always required to run a tool (e.g. libexec/** and
+cross-referenced tools in bin/*) in the [data](#cc_tool-data) attribute. If some files are only
+required when certain flags are passed to the tool, consider using a `cc_args` rule to
+bind the files to the flags that require them. This reduces the overhead required to properly
+enumerate a sandbox with all the files required to run a tool, and ensures that there isn't
+unintentional leakage across configurations and actions.
 
 Example:
 ```
+load("//cc/toolchains:tool.bzl", "cc_tool")
+
 cc_tool(
     name = "clang_tool",
     executable = "@llvm_toolchain//:bin/clang",
     # Suppose clang needs libc to run.
     data = ["@llvm_toolchain//:lib/x86_64-linux-gnu/libc.so.6"]
     tags = ["requires-network"],
+    capabilities = ["//cc/toolchains/capabilities:supports_pic"],
 )
 ```
 """,
diff --git a/cc/toolchains/tool_capability.bzl b/cc/toolchains/tool_capability.bzl
new file mode 100644
index 0000000..60b0f59
--- /dev/null
+++ b/cc/toolchains/tool_capability.bzl
@@ -0,0 +1,85 @@
+# Copyright 2024 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Implementation of the cc_tool_capability rule."""
+
+load(
+    ":cc_toolchain_info.bzl",
+    "ArgsListInfo",
+    "FeatureConstraintInfo",
+    "FeatureInfo",
+    "ToolCapabilityInfo",
+)
+
+def _cc_tool_capability_impl(ctx):
+    ft = FeatureInfo(
+        name = ctx.attr.feature_name or ctx.label.name,
+        label = ctx.label,
+        enabled = False,
+        args = ArgsListInfo(
+            label = ctx.label,
+            args = (),
+            files = depset(),
+            by_action = (),
+            allowlist_include_directories = depset(),
+        ),
+        implies = depset(),
+        requires_any_of = (),
+        mutually_exclusive = (),
+        # Mark it as external so that it doesn't complain if we say
+        # "requires" on a constraint that was never referenced elsewhere
+        # in the toolchain.
+        external = True,
+        overridable = True,
+        overrides = None,
+        allowlist_include_directories = depset(),
+    )
+    return [
+        ToolCapabilityInfo(label = ctx.label, feature = ft),
+        # Only give it a feature constraint info and not a feature info.
+        # This way you can't imply it - you can only require it.
+        FeatureConstraintInfo(label = ctx.label, all_of = depset([ft])),
+    ]
+
+cc_tool_capability = rule(
+    implementation = _cc_tool_capability_impl,
+    provides = [ToolCapabilityInfo, FeatureConstraintInfo],
+    doc = """A capability is an optional feature that a tool supports.
+
+For example, not all compilers support PIC, so to handle this, we write:
+
+```
+cc_tool(
+    name = "clang",
+    src = "@host_tools/bin/clang",
+    capabilities = [
+        "//cc/toolchains/capabilities:supports_pic",
+    ],
+)
+
+cc_args(
+    name = "pic",
+    requires = [
+        "//cc/toolchains/capabilities:supports_pic"
+    ],
+    args = ["-fPIC"],
+)
+```
+
+This ensures that `-fPIC` is added to the command-line only when we are using a
+tool that supports PIC.
+""",
+    attrs = {
+        "feature_name": attr.string(doc = "The name of the feature to generate for this capability"),
+    },
+)
diff --git a/cc/toolchains/tool_map.bzl b/cc/toolchains/tool_map.bzl
index 62e94e6..53866a8 100644
--- a/cc/toolchains/tool_map.bzl
+++ b/cc/toolchains/tool_map.bzl
@@ -70,11 +70,12 @@
 def cc_tool_map(name, tools, **kwargs):
     """A toolchain configuration rule that maps toolchain actions to tools.
 
-    A cc_tool_map aggregates all the tools that may be used for a given toolchain and maps them to
-    their corresponding actions. Conceptually, this is similar to the `CXX=/path/to/clang++`
-    environment variables that most build systems use to determine which tools to use for a given
-    action. To simplify usage, some actions have been grouped together (for example,
-    //cc/toolchains/actions:cpp_compile_actions) to
+    A `cc_tool_map` aggregates all the tools that may be used for a given toolchain
+    and maps them to their corresponding actions. Conceptually, this is similar to the
+    `CXX=/path/to/clang++` environment variables that most build systems use to determine which
+    tools to use for a given action. To simplify usage, some actions have been grouped together (for
+    example,
+    [//third_party/bazel_rules/rules_cc/cc/toolchains/actions:cpp_compile_actions](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/actions/BUILD)) to
     logically express "all the C++ compile actions".
 
     In Bazel, there is a little more granularity to the mapping, so the mapping doesn't follow the
@@ -106,7 +107,8 @@
 
     Args:
         name: (str) The name of the target.
-        tools: (Dict[target providing ActionTypeSetInfo, Executable target]) A mapping between `cc_action_type` targets
+        tools: (Dict[Label, Label]) A mapping between
+            `cc_action_type`/`cc_action_type_set` targets
             and the `cc_tool` or executable target that implements that action.
         **kwargs: [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule.
     """
diff --git a/cc/toolchains/toolchain_api.md b/cc/toolchains/toolchain_api.md
index ae92f14..d5b3be1 100644
--- a/cc/toolchains/toolchain_api.md
+++ b/cc/toolchains/toolchain_api.md
@@ -2,6 +2,82 @@
 
 This is a list of rules/macros that should be exported as documentation.
 
+<a id="cc_action_type"></a>
+
+## cc_action_type
+
+<pre>
+cc_action_type(<a href="#cc_action_type-name">name</a>, <a href="#cc_action_type-action_name">action_name</a>)
+</pre>
+
+A type of action (eg. c_compile, assemble, strip).
+
+[`cc_action_type`](#cc_action_type) rules are used to associate arguments and tools together to
+perform a specific action. Bazel prescribes a set of known action types that are used to drive
+typical C/C++/ObjC actions like compiling, linking, and archiving. The set of well-known action
+types can be found in [@rules_cc//cc/toolchains/actions:BUILD](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/actions/BUILD).
+
+It's possible to create project-specific action types for use in toolchains. Be careful when
+doing this, because every toolchain that encounters the action will need to be configured to
+support the custom action type. If your project is a library, avoid creating new action types as
+it will reduce compatibility with existing toolchains and increase setup complexity for users.
+
+Example:
+```
+load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES")
+load("@rules_cc//cc/toolchains:actions.bzl", "cc_action_type")
+
+cc_action_type(
+    name = "cpp_compile",
+    action_name =  = ACTION_NAMES.cpp_compile,
+)
+```
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :------------- | :------------- | :------------- | :------------- | :------------- |
+| <a id="cc_action_type-name"></a>name |  A unique name for this target.   | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required |  |
+| <a id="cc_action_type-action_name"></a>action_name |  -   | String | required |  |
+
+
+<a id="cc_action_type_set"></a>
+
+## cc_action_type_set
+
+<pre>
+cc_action_type_set(<a href="#cc_action_type_set-name">name</a>, <a href="#cc_action_type_set-actions">actions</a>, <a href="#cc_action_type_set-allow_empty">allow_empty</a>)
+</pre>
+
+Represents a set of actions.
+
+This is a convenience rule to allow for more compact representation of a group of action types.
+Use this anywhere a [`cc_action_type`](#cc_action_type) is accepted.
+
+Example:
+```
+load("@rules_cc//cc/toolchains:actions.bzl", "cc_action_type_set")
+
+cc_action_type_set(
+    name = "link_executable_actions",
+    actions = [
+        "@rules_cc//cc/toolchains/actions:cpp_link_executable",
+        "@rules_cc//cc/toolchains/actions:lto_index_for_executable",
+    ],
+)
+```
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :------------- | :------------- | :------------- | :------------- | :------------- |
+| <a id="cc_action_type_set-name"></a>name |  A unique name for this target.   | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required |  |
+| <a id="cc_action_type_set-actions"></a>actions |  A list of cc_action_type or cc_action_type_set   | <a href="https://bazel.build/concepts/labels">List of labels</a> | required |  |
+| <a id="cc_action_type_set-allow_empty"></a>allow_empty |  -   | Boolean | optional |  `False`  |
+
+
 <a id="cc_args_list"></a>
 
 ## cc_args_list
@@ -12,7 +88,7 @@
 
 An ordered list of cc_args.
 
-This is a convenience rule to allow you to group a set of multiple [cc_args](#cc_args) into a
+This is a convenience rule to allow you to group a set of multiple [`cc_args`](#cc_args) into a
 single list. This particularly useful for toolchain behaviors that require different flags for
 different actions.
 
@@ -20,13 +96,13 @@
 
 Example usage:
 ```
-load("//third_party/bazel_rules/rules_cc/cc/toolchains:cc_args.bzl", "cc_args")
-load("//third_party/bazel_rules/rules_cc/cc/toolchains:args_list.bzl", "cc_args_list")
+load("@rules_cc//cc/toolchains:cc_args.bzl", "cc_args")
+load("@rules_cc//cc/toolchains:args_list.bzl", "cc_args_list")
 
 cc_args(
     name = "gc_sections",
     actions = [
-        "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:link_actions",
+        "@rules_cc//cc/toolchains/actions:link_actions",
     ],
     args = ["-Wl,--gc-sections"],
 )
@@ -34,8 +110,8 @@
 cc_args(
     name = "function_sections",
     actions = [
-        "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:compile_actions",
-        "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:link_actions",
+        "@rules_cc//cc/toolchains/actions:compile_actions",
+        "@rules_cc//cc/toolchains/actions:link_actions",
     ],
     args = ["-ffunction-sections"],
 )
@@ -58,6 +134,335 @@
 | <a id="cc_args_list-args"></a>args |  (ordered) cc_args to include in this list.   | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional |  `[]`  |
 
 
+<a id="cc_external_feature"></a>
+
+## cc_external_feature
+
+<pre>
+cc_external_feature(<a href="#cc_external_feature-name">name</a>, <a href="#cc_external_feature-feature_name">feature_name</a>, <a href="#cc_external_feature-overridable">overridable</a>)
+</pre>
+
+A declaration that a [feature](https://bazel.build/docs/cc-toolchain-config-reference#features) with this name is defined elsewhere.
+
+This rule communicates that a feature has been defined externally to make it possible to reference
+features that live outside the rule-based cc toolchain ecosystem. This allows various toolchain
+rules to reference the external feature without accidentally re-defining said feature.
+
+This rule is currently considered a private API of the toolchain rules to encourage the Bazel
+ecosystem to migrate to properly defining their features as rules.
+
+Example:
+```
+load("@rules_cc//cc/toolchains:external_feature.bzl", "cc_external_feature")
+
+# rules_rust defines a feature that is disabled whenever rust artifacts are being linked using
+# the cc toolchain to signal that incompatible flags should be disabled as well.
+cc_external_feature(
+    name = "rules_rust_unsupported_feature",
+    feature_name = "rules_rust_unsupported_feature",
+    overridable = False,
+)
+```
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :------------- | :------------- | :------------- | :------------- | :------------- |
+| <a id="cc_external_feature-name"></a>name |  A unique name for this target.   | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required |  |
+| <a id="cc_external_feature-feature_name"></a>feature_name |  The name of the feature   | String | required |  |
+| <a id="cc_external_feature-overridable"></a>overridable |  Whether the feature can be overridden   | Boolean | required |  |
+
+
+<a id="cc_feature"></a>
+
+## cc_feature
+
+<pre>
+cc_feature(<a href="#cc_feature-name">name</a>, <a href="#cc_feature-args">args</a>, <a href="#cc_feature-feature_name">feature_name</a>, <a href="#cc_feature-implies">implies</a>, <a href="#cc_feature-mutually_exclusive">mutually_exclusive</a>, <a href="#cc_feature-overrides">overrides</a>, <a href="#cc_feature-requires_any_of">requires_any_of</a>)
+</pre>
+
+A dynamic set of toolchain flags that create a singular [feature](https://bazel.build/docs/cc-toolchain-config-reference#features) definition.
+
+A feature is basically a dynamically toggleable [`cc_args_list`](#cc_args_list). There are a variety of
+dependencies and compatibility requirements that must be satisfied to enable a
+[`cc_feature`](#cc_feature). Once those conditions are met, the arguments in [`cc_feature.args`](#cc_feature-args)
+are expanded and added to the command-line.
+
+A feature may be enabled or disabled through the following mechanisms:
+* Via command-line flags, or a `.bazelrc` file via the
+  [`--features` flag](https://bazel.build/reference/command-line-reference#flag--features)
+* Through inter-feature relationships (via [`cc_feature.implies`](#cc_feature-implies)) where one
+  feature may implicitly enable another.
+* Individual rules (e.g. `cc_library`) or `package` definitions may elect to manually enable or
+  disable features through the
+  [`features` attribute](https://bazel.build/reference/be/common-definitions#common.features).
+
+Note that a feature may alternate between enabled and disabled dynamically over the course of a
+build. Because of their toggleable nature, it's generally best to avoid adding arguments to a
+`cc_toolchain` as a [`cc_feature`](#cc_feature) unless strictly necessary. Instead, prefer to express arguments
+via [`cc_toolchain.args`](#cc_toolchain-args) whenever possible.
+
+You should use a [`cc_feature`](#cc_feature) when any of the following apply:
+* You need the flags to be dynamically toggled over the course of a build.
+* You want build files to be able to configure the flags in question. For example, a
+  binary might specify `features = ["optimize_for_size"]` to create a small
+  binary instead of optimizing for performance.
+* You need to carry forward Starlark toolchain behaviors. If you're migrating a
+  complex Starlark-based toolchain definition to these rules, many of the
+  workflows and flags were likely based on features.
+
+If you only need to configure flags via the Bazel command-line, instead
+consider adding a
+[`bool_flag`](https://github.com/bazelbuild/bazel-skylib/tree/main/doc/common_settings_doc.md#bool_flag)
+paired with a [`config_setting`](https://bazel.build/reference/be/general#config_setting)
+and then make your [`cc_args`](#cc_args) rule `select` on the `config_setting`.
+
+For more details about how Bazel handles features, see the official Bazel
+documentation at
+https://bazel.build/docs/cc-toolchain-config-reference#features.
+
+Example:
+```
+load("@rules_cc//cc/toolchains:feature.bzl", "cc_feature")
+
+# A feature that enables LTO, which may be incompatible when doing interop with various
+# languages (e.g. rust, go), or may need to be disabled for particular `cc_binary` rules
+# for various reasons.
+cc_feature(
+    name = "lto",
+    feature_name = "lto",
+    args = [":lto_args"],
+)
+```
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :------------- | :------------- | :------------- | :------------- | :------------- |
+| <a id="cc_feature-name"></a>name |  A unique name for this target.   | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required |  |
+| <a id="cc_feature-args"></a>args |  A list of [`cc_args`](#cc_args) or [`cc_args_list`](#cc_args_list) labels that are expanded when this feature is enabled.   | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional |  `[]`  |
+| <a id="cc_feature-feature_name"></a>feature_name |  The name of the feature that this rule implements.<br><br>The feature name is a string that will be used in the `features` attribute of rules to enable them (eg. `cc_binary(..., features = ["opt"])`.<br><br>While two features with the same `feature_name` may not be bound to the same toolchain, they can happily live alongside each other in the same BUILD file.<br><br>Example: <pre><code>cc_feature(&#10;    name = "sysroot_macos",&#10;    feature_name = "sysroot",&#10;    ...&#10;)&#10;&#10;cc_feature(&#10;    name = "sysroot_linux",&#10;    feature_name = "sysroot",&#10;    ...&#10;)</code></pre>   | String | optional |  `""`  |
+| <a id="cc_feature-implies"></a>implies |  List of features enabled along with this feature.<br><br>Warning: If any of the features cannot be enabled, this feature is silently disabled.   | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional |  `[]`  |
+| <a id="cc_feature-mutually_exclusive"></a>mutually_exclusive |  A list of things that this feature is mutually exclusive with.<br><br>It can be either: * A feature, in which case the two features are mutually exclusive. * A [`cc_mutually_exclusive_category`](#cc_mutually_exclusive_category), in which case all features that write     `mutually_exclusive = [":category"]` are mutually exclusive with each other.<br><br>If this feature has a side-effect of implementing another feature, it can be useful to list that feature here to ensure they aren't enabled at the same time.   | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional |  `[]`  |
+| <a id="cc_feature-overrides"></a>overrides |  A declaration that this feature overrides a known feature.<br><br>In the example below, if you missed the "overrides" attribute, it would complain that the feature "opt" was defined twice.<br><br>Example: <pre><code>load("@rules_cc//cc/toolchains:feature.bzl", "cc_feature")&#10;&#10;cc_feature(&#10;    name = "opt",&#10;    feature_name = "opt",&#10;    args = [":size_optimized"],&#10;    overrides = "@rules_cc//cc/toolchains/features:opt",&#10;)</code></pre>   | <a href="https://bazel.build/concepts/labels">Label</a> | optional |  `None`  |
+| <a id="cc_feature-requires_any_of"></a>requires_any_of |  A list of feature sets that define toolchain compatibility.<br><br>If *at least one* of the listed [`cc_feature_set`](#cc_feature_set)s are fully satisfied (all features exist in the toolchain AND are currently enabled), this feature is deemed compatible and may be enabled.<br><br>Note: Even if `cc_feature.requires_any_of` is satisfied, a feature is not enabled unless another mechanism (e.g. command-line flags, `cc_feature.implies`, `cc_toolchain_config.enabled_features`) signals that the feature should actually be enabled.   | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional |  `[]`  |
+
+
+<a id="cc_feature_constraint"></a>
+
+## cc_feature_constraint
+
+<pre>
+cc_feature_constraint(<a href="#cc_feature_constraint-name">name</a>, <a href="#cc_feature_constraint-all_of">all_of</a>, <a href="#cc_feature_constraint-none_of">none_of</a>)
+</pre>
+
+Defines a compound relationship between features.
+
+This rule can be used with [`cc_args.require_any_of`](#cc_args-require_any_of) to specify that a set
+of arguments are only enabled when a constraint is met. Both `all_of` and `none_of` must be
+satisfied simultaneously.
+
+This is basically a [`cc_feature_set`](#cc_feature_set) that supports `none_of` expressions. This extra flexibility
+is why this rule may only be used by [`cc_args.require_any_of`](#cc_args-require_any_of).
+
+Example:
+```
+load("@rules_cc//cc/toolchains:feature_constraint.bzl", "cc_feature_constraint")
+
+# A constraint that requires a `linker_supports_thinlto` feature to be enabled,
+# AND a `no_optimization` to be disabled.
+cc_feature_constraint(
+    name = "thinlto_constraint",
+    all_of = [":linker_supports_thinlto"],
+    none_of = [":no_optimization"],
+)
+```
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :------------- | :------------- | :------------- | :------------- | :------------- |
+| <a id="cc_feature_constraint-name"></a>name |  A unique name for this target.   | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required |  |
+| <a id="cc_feature_constraint-all_of"></a>all_of |  -   | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional |  `[]`  |
+| <a id="cc_feature_constraint-none_of"></a>none_of |  -   | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional |  `[]`  |
+
+
+<a id="cc_feature_set"></a>
+
+## cc_feature_set
+
+<pre>
+cc_feature_set(<a href="#cc_feature_set-name">name</a>, <a href="#cc_feature_set-all_of">all_of</a>)
+</pre>
+
+Defines a set of features.
+
+This may be used by both [`cc_feature`](#cc_feature) and [`cc_args`](#cc_args) rules, and is effectively a way to express
+a logical `AND` operation across multiple requred features.
+
+Example:
+```
+load("@rules_cc//cc/toolchains:feature_set.bzl", "cc_feature_set")
+
+cc_feature_set(
+    name = "thin_lto_requirements",
+    all_of = [
+        ":thin_lto",
+        ":opt",
+    ],
+)
+```
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :------------- | :------------- | :------------- | :------------- | :------------- |
+| <a id="cc_feature_set-name"></a>name |  A unique name for this target.   | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required |  |
+| <a id="cc_feature_set-all_of"></a>all_of |  A set of features   | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional |  `[]`  |
+
+
+<a id="cc_mutually_exclusive_category"></a>
+
+## cc_mutually_exclusive_category
+
+<pre>
+cc_mutually_exclusive_category(<a href="#cc_mutually_exclusive_category-name">name</a>)
+</pre>
+
+A rule used to categorize [`cc_feature`](#cc_feature) definitions for which only one can be enabled.
+
+This is used by [`cc_feature.mutually_exclusive`](#cc_feature-mutually_exclusive) to express groups
+of [`cc_feature`](#cc_feature) definitions that are inherently incompatible with each other and must be treated as
+mutually exclusive.
+
+Warning: These groups are keyed by name, so two [`cc_mutually_exclusive_category`](#cc_mutually_exclusive_category) definitions of the
+same name in different packages will resolve to the same logical group.
+
+Example:
+```
+load("@rules_cc//cc/toolchains:feature.bzl", "cc_feature")
+load("@rules_cc//cc/toolchains:mutually_exclusive_category.bzl", "cc_mutually_exclusive_category")
+
+cc_mutually_exclusive_category(
+    name = "opt_level",
+)
+
+cc_feature(
+    name = "speed_optimized",
+    mutually_exclusive = [":opt_level"],
+)
+
+cc_feature(
+    name = "size_optimized",
+    mutually_exclusive = [":opt_level"],
+)
+
+cc_feature(
+    name = "unoptimized",
+    mutually_exclusive = [":opt_level"],
+)
+```
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :------------- | :------------- | :------------- | :------------- | :------------- |
+| <a id="cc_mutually_exclusive_category-name"></a>name |  A unique name for this target.   | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required |  |
+
+
+<a id="cc_tool"></a>
+
+## cc_tool
+
+<pre>
+cc_tool(<a href="#cc_tool-name">name</a>, <a href="#cc_tool-src">src</a>, <a href="#cc_tool-data">data</a>, <a href="#cc_tool-allowlist_include_directories">allowlist_include_directories</a>, <a href="#cc_tool-capabilities">capabilities</a>)
+</pre>
+
+Declares a tool for use by toolchain actions.
+
+[`cc_tool`](#cc_tool) rules are used in a [`cc_tool_map`](#cc_tool_map) rule to ensure all files and
+metadata required to run a tool are available when constructing a `cc_toolchain`.
+
+In general, include all files that are always required to run a tool (e.g. libexec/** and
+cross-referenced tools in bin/*) in the [data](#cc_tool-data) attribute. If some files are only
+required when certain flags are passed to the tool, consider using a [`cc_args`](#cc_args) rule to
+bind the files to the flags that require them. This reduces the overhead required to properly
+enumerate a sandbox with all the files required to run a tool, and ensures that there isn't
+unintentional leakage across configurations and actions.
+
+Example:
+```
+load("@rules_cc//cc/toolchains:tool.bzl", "cc_tool")
+
+cc_tool(
+    name = "clang_tool",
+    executable = "@llvm_toolchain//:bin/clang",
+    # Suppose clang needs libc to run.
+    data = ["@llvm_toolchain//:lib/x86_64-linux-gnu/libc.so.6"]
+    tags = ["requires-network"],
+    capabilities = ["@rules_cc//cc/toolchains/capabilities:supports_pic"],
+)
+```
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :------------- | :------------- | :------------- | :------------- | :------------- |
+| <a id="cc_tool-name"></a>name |  A unique name for this target.   | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required |  |
+| <a id="cc_tool-src"></a>src |  The underlying binary that this tool represents.<br><br>Usually just a single prebuilt (eg. @toolchain//:bin/clang), but may be any executable label.   | <a href="https://bazel.build/concepts/labels">Label</a> | optional |  `None`  |
+| <a id="cc_tool-data"></a>data |  Additional files that are required for this tool to run.<br><br>Frequently, clang and gcc require additional files to execute as they often shell out to other binaries (e.g. `cc1`).   | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional |  `[]`  |
+| <a id="cc_tool-allowlist_include_directories"></a>allowlist_include_directories |  Include paths implied by using this tool.<br><br>Compilers may include a set of built-in headers that are implicitly available unless flags like `-nostdinc` are provided. Bazel checks that all included headers are properly provided by a dependency or allowlisted through this mechanism.<br><br>As a rule of thumb, only use this if Bazel is complaining about absolute paths in your toolchain and you've ensured that the toolchain is compiling with the `-no-canonical-prefixes` and/or `-fno-canonical-system-headers` arguments.<br><br>This can help work around errors like: `the source file 'main.c' includes the following non-builtin files with absolute paths (if these are builtin files, make sure these paths are in your toolchain)`.   | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional |  `[]`  |
+| <a id="cc_tool-capabilities"></a>capabilities |  Declares that a tool is capable of doing something.<br><br>For example, `@rules_cc//cc/toolchains/capabilities:supports_pic`.   | <a href="https://bazel.build/concepts/labels">List of labels</a> | optional |  `[]`  |
+
+
+<a id="cc_tool_capability"></a>
+
+## cc_tool_capability
+
+<pre>
+cc_tool_capability(<a href="#cc_tool_capability-name">name</a>, <a href="#cc_tool_capability-feature_name">feature_name</a>)
+</pre>
+
+A capability is an optional feature that a tool supports.
+
+For example, not all compilers support PIC, so to handle this, we write:
+
+```
+cc_tool(
+    name = "clang",
+    src = "@host_tools/bin/clang",
+    capabilities = [
+        "@rules_cc//cc/toolchains/capabilities:supports_pic",
+    ],
+)
+
+cc_args(
+    name = "pic",
+    requires = [
+        "@rules_cc//cc/toolchains/capabilities:supports_pic"
+    ],
+    args = ["-fPIC"],
+)
+```
+
+This ensures that `-fPIC` is added to the command-line only when we are using a
+tool that supports PIC.
+
+**ATTRIBUTES**
+
+
+| Name  | Description | Type | Mandatory | Default |
+| :------------- | :------------- | :------------- | :------------- | :------------- |
+| <a id="cc_tool_capability-name"></a>name |  A unique name for this target.   | <a href="https://bazel.build/concepts/labels#target-names">Name</a> | required |  |
+| <a id="cc_tool_capability-feature_name"></a>feature_name |  The name of the feature to generate for this capability   | String | optional |  `""`  |
+
+
 <a id="cc_args"></a>
 
 ## cc_args
@@ -72,13 +477,14 @@
 
 This rule is the fundamental building building block for every toolchain tool invocation. Each
 argument expressed in a toolchain tool invocation (e.g. `gcc`, `llvm-ar`) is declared in a
-`cc_args` rule that applies an ordered list of arguments to a set of toolchain actions.
-`cc_args` rules can be added unconditionally to a `cc_toolchain`, conditionally via `select()`
-statements, or dynamically via an intermediate `cc_feature`.
+[`cc_args`](#cc_args) rule that applies an ordered list of arguments to a set of toolchain
+actions. [`cc_args`](#cc_args) rules can be added unconditionally to a
+`cc_toolchain`, conditionally via `select()` statements, or dynamically via an
+intermediate [`cc_feature`](#cc_feature).
 
 Conceptually, this is similar to the old `CFLAGS`, `CPPFLAGS`, etc. environment variables that
 many build systems use to determine which flags to use for a given action. The significant
-difference is that `cc_args` rules are declared in a structured way that allows for
+difference is that [`cc_args`](#cc_args) rules are declared in a structured way that allows for
 significantly more powerful and sharable toolchain configurations. Also, due to Bazel's more
 granular action types, it's possible to bind flags to very specific actions (e.g. LTO indexing
 for an executable vs a dynamic library) multiple different actions (e.g. C++ compile and link
@@ -86,16 +492,16 @@
 
 Example usage:
 ```
-load("//third_party/bazel_rules/rules_cc/cc/toolchains:args.bzl", "cc_args")
+load("@rules_cc//cc/toolchains:args.bzl", "cc_args")
 
 # Basic usage: a trivial flag.
 #
-# An example of expressing `-Werror` as a `cc_args` rule.
+# An example of expressing `-Werror` as a [`cc_args`](#cc_args) rule.
 cc_args(
     name = "warnings_as_errors",
     actions = [
         # Applies to all C/C++ compile actions.
-        "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:compile_actions",
+        "@rules_cc//cc/toolchains/actions:compile_actions",
     ],
     args = ["-Werror"],
 )
@@ -107,7 +513,7 @@
     name = "link_libcxx",
     actions = [
         # Applies to all link actions.
-        "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:link_actions",
+        "@rules_cc//cc/toolchains/actions:link_actions",
     ],
     # On tool invocation, this appears as `-Xlinker -lc++`. Nothing will ever end up between
     # the two flags.
@@ -125,13 +531,13 @@
 cc_args(
     name = "library_search_directories",
     actions = [
-        "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:link_actions",
+        "@rules_cc//cc/toolchains/actions:link_actions",
     ],
     args = ["-L{search_dir}"],
-    iterate_over = "//third_party/bazel_rules/rules_cc/cc/toolchains/variables:library_search_directories",
-    requires_not_none = "//third_party/bazel_rules/rules_cc/cc/toolchains/variables:library_search_directories",
+    iterate_over = "@rules_cc//cc/toolchains/variables:library_search_directories",
+    requires_not_none = "@rules_cc//cc/toolchains/variables:library_search_directories",
     format = {
-        "search_dir": "//third_party/bazel_rules/rules_cc/cc/toolchains/variables:library_search_directories",
+        "search_dir": "@rules_cc//cc/toolchains/variables:library_search_directories",
     },
 )
 ```
@@ -146,21 +552,21 @@
 | Name  | Description | Default Value |
 | :------------- | :------------- | :------------- |
 | <a id="cc_args-name"></a>name |  (str) The name of the target.   |  none |
-| <a id="cc_args-actions"></a>actions |  (List[Label]) A list of labels of `cc_action_type` or `cc_action_type_set` rules that dictate which actions these arguments should be applied to.   |  `None` |
-| <a id="cc_args-allowlist_include_directories"></a>allowlist_include_directories |  (List[Label]) A list of include paths that are implied by using this rule. These must point to a skylib [directory](https://github.com/bazelbuild/bazel-skylib/blob/main/docs/directory_doc.md#directory) or [subdirectory](https://github.com/bazelbuild/bazel-skylib/blob/main/docs/directory_subdirectory_doc.md#subdirectory) rule. Some flags (e.g. --sysroot) imply certain include paths are available despite not explicitly specifying a normal include path flag (`-I`, `-isystem`, etc.). Bazel checks that all included headers are properly provided by a dependency or allowlisted through this mechanism.   |  `None` |
+| <a id="cc_args-actions"></a>actions |  (List[Label]) A list of labels of [`cc_action_type`](#cc_action_type) or [`cc_action_type_set`](#cc_action_type_set) rules that dictate which actions these arguments should be applied to.   |  `None` |
+| <a id="cc_args-allowlist_include_directories"></a>allowlist_include_directories |  (List[Label]) A list of include paths that are implied by using this rule. These must point to a skylib [directory](https://github.com/bazelbuild/bazel-skylib/tree/main/doc/directory_doc.md#directory) or [subdirectory](https://github.com/bazelbuild/bazel-skylib/tree/main/doc/directory_subdirectory_doc.md#subdirectory) rule. Some flags (e.g. --sysroot) imply certain include paths are available despite not explicitly specifying a normal include path flag (`-I`, `-isystem`, etc.). Bazel checks that all included headers are properly provided by a dependency or allowlisted through this mechanism.<br><br>As a rule of thumb, only use this if Bazel is complaining about absolute paths in your toolchain and you've ensured that the toolchain is compiling with the `-no-canonical-prefixes` and/or `-fno-canonical-system-headers` arguments.<br><br>This can help work around errors like: `the source file 'main.c' includes the following non-builtin files with absolute paths (if these are builtin files, make sure these paths are in your toolchain)`.   |  `None` |
 | <a id="cc_args-args"></a>args |  (List[str]) The command-line arguments that are applied by using this rule. This is mutually exclusive with [nested](#cc_args-nested).   |  `None` |
 | <a id="cc_args-data"></a>data |  (List[Label]) A list of runtime data dependencies that are required for these arguments to work as intended.   |  `None` |
 | <a id="cc_args-env"></a>env |  (Dict[str, str]) Environment variables that should be set when the tool is invoked.   |  `None` |
-| <a id="cc_args-format"></a>format |  (Dict[str, Label]) A mapping of format strings to the label of the corresponding `cc_variable` that the value should be pulled from. All instances of `{variable_name}` will be replaced with the expanded value of `variable_name` in this dictionary. The complete list of possible variables can be found in https://github.com/bazelbuild/rules_cc/blob/main/cc/toolchains/variables/BUILD. it is not possible to declare custom variables--these are inherent to Bazel itself.   |  `{}` |
-| <a id="cc_args-iterate_over"></a>iterate_over |  (Label) The label of a `cc_variable` that should be iterated over. This is intended for use with built-in variables that are lists.   |  `None` |
-| <a id="cc_args-nested"></a>nested |  (List[Label]) A list of [cc_nested_args](#cc_nested_args) rules that should be expanded to command-line arguments when this rule is used. This is mutually exclusive with [args](#cc_args-args).   |  `None` |
-| <a id="cc_args-requires_not_none"></a>requires_not_none |  (Label) The label of a `cc_variable` that should be checked for existence before expanding this rule. If the variable is None, this rule will be ignored.   |  `None` |
-| <a id="cc_args-requires_none"></a>requires_none |  (Label) The label of a `cc_variable` that should be checked for non-existence before expanding this rule. If the variable is not None, this rule will be ignored.   |  `None` |
-| <a id="cc_args-requires_true"></a>requires_true |  (Label) The label of a `cc_variable` that should be checked for truthiness before expanding this rule. If the variable is false, this rule will be ignored.   |  `None` |
-| <a id="cc_args-requires_false"></a>requires_false |  (Label) The label of a `cc_variable` that should be checked for falsiness before expanding this rule. If the variable is true, this rule will be ignored.   |  `None` |
-| <a id="cc_args-requires_equal"></a>requires_equal |  (Label) The label of a `cc_variable` that should be checked for equality before expanding this rule. If the variable is not equal to (requires_equal_value)[#cc_args-requires_equal_value], this rule will be ignored.   |  `None` |
+| <a id="cc_args-format"></a>format |  (Dict[str, Label]) A mapping of format strings to the label of the corresponding [`cc_variable`](#cc_variable) that the value should be pulled from. All instances of `{variable_name}` will be replaced with the expanded value of `variable_name` in this dictionary. The complete list of possible variables can be found in https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/variables/BUILD. It is not possible to declare custom variables--these are inherent to Bazel itself.   |  `{}` |
+| <a id="cc_args-iterate_over"></a>iterate_over |  (Label) The label of a [`cc_variable`](#cc_variable) that should be iterated over. This is intended for use with built-in variables that are lists.   |  `None` |
+| <a id="cc_args-nested"></a>nested |  (List[Label]) A list of [`cc_nested_args`](#cc_nested_args) rules that should be expanded to command-line arguments when this rule is used. This is mutually exclusive with [args](#cc_args-args).   |  `None` |
+| <a id="cc_args-requires_not_none"></a>requires_not_none |  (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for existence before expanding this rule. If the variable is None, this rule will be ignored.   |  `None` |
+| <a id="cc_args-requires_none"></a>requires_none |  (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for non-existence before expanding this rule. If the variable is not None, this rule will be ignored.   |  `None` |
+| <a id="cc_args-requires_true"></a>requires_true |  (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for truthiness before expanding this rule. If the variable is false, this rule will be ignored.   |  `None` |
+| <a id="cc_args-requires_false"></a>requires_false |  (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for falsiness before expanding this rule. If the variable is true, this rule will be ignored.   |  `None` |
+| <a id="cc_args-requires_equal"></a>requires_equal |  (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for equality before expanding this rule. If the variable is not equal to (requires_equal_value)[#cc_args-requires_equal_value], this rule will be ignored.   |  `None` |
 | <a id="cc_args-requires_equal_value"></a>requires_equal_value |  (str) The value to compare (requires_equal)[#cc_args-requires_equal] against.   |  `None` |
-| <a id="cc_args-requires_any_of"></a>requires_any_of |  (List[Label]) These arguments will be used in a tool invocation when at least one of the `cc_feature_constraint` entries in this list are satisfied. If omitted, this flag set will be enabled unconditionally.   |  `None` |
+| <a id="cc_args-requires_any_of"></a>requires_any_of |  (List[Label]) These arguments will be used in a tool invocation when at least one of the [cc_feature_constraint](#cc_feature_constraint) entries in this list are satisfied. If omitted, this flag set will be enabled unconditionally.   |  `None` |
 | <a id="cc_args-kwargs"></a>kwargs |  [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule.   |  none |
 
 
@@ -173,19 +579,19 @@
                <a href="#cc_nested_args-requires_true">requires_true</a>, <a href="#cc_nested_args-requires_false">requires_false</a>, <a href="#cc_nested_args-requires_equal">requires_equal</a>, <a href="#cc_nested_args-requires_equal_value">requires_equal_value</a>, <a href="#cc_nested_args-kwargs">kwargs</a>)
 </pre>
 
-Nested arguments for use in more complex cc_args expansions.
+Nested arguments for use in more complex [`cc_args`](#cc_args) expansions.
 
-While this rule is very similar in shape to [cc_args](#cc_args), it is intended to be used as a
-dependency of [cc_args](#cc_args) to provide additional arguments that should be applied to the
-same actions as defined by the parent [cc_args](#cc_args) rule. The key motivation for this rule
+While this rule is very similar in shape to [`cc_args`](#cc_args), it is intended to be used as a
+dependency of [`cc_args`](#cc_args) to provide additional arguments that should be applied to the
+same actions as defined by the parent [`cc_args`](#cc_args) rule. The key motivation for this rule
 is to allow for more complex variable-based argument expensions.
 
-Prefer expressing collections of arguments as [cc_args](#cc_args) and
-[cc_args_list](#cc_args_list) rules when possible.
+Prefer expressing collections of arguments as [`cc_args`](#cc_args) and
+[`cc_args_list`](#cc_args_list) rules when possible.
 
 For living examples of how this rule is used, see the usages here:
-    https://github.com/bazelbuild/rules_cc/blob/main/cc/toolchains/args/runtime_library_search_directories/BUILD
-    https://github.com/bazelbuild/rules_cc/blob/main/cc/toolchains/args/libraries_to_link/BUILD
+    https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/args/runtime_library_search_directories/BUILD
+    https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/args/libraries_to_link/BUILD
 
 Note: These examples are non-trivial, but they illustrate when it is absolutely necessary to
 use this rule.
@@ -199,14 +605,14 @@
 | <a id="cc_nested_args-name"></a>name |  (str) The name of the target.   |  none |
 | <a id="cc_nested_args-args"></a>args |  (List[str]) The command-line arguments that are applied by using this rule. This is mutually exclusive with [nested](#cc_nested_args-nested).   |  `None` |
 | <a id="cc_nested_args-data"></a>data |  (List[Label]) A list of runtime data dependencies that are required for these arguments to work as intended.   |  `None` |
-| <a id="cc_nested_args-format"></a>format |  (Dict[str, Label]) A mapping of format strings to the label of the corresponding `cc_variable` that the value should be pulled from. All instances of `{variable_name}` will be replaced with the expanded value of `variable_name` in this dictionary. The complete list of possible variables can be found in https://github.com/bazelbuild/rules_cc/blob/main/cc/toolchains/variables/BUILD. it is not possible to declare custom variables--these are inherent to Bazel itself.   |  `{}` |
-| <a id="cc_nested_args-iterate_over"></a>iterate_over |  (Label) The label of a `cc_variable` that should be iterated over. This is intended for use with built-in variables that are lists.   |  `None` |
-| <a id="cc_nested_args-nested"></a>nested |  (List[Label]) A list of [cc_nested_args](#cc_nested_args) rules that should be expanded to command-line arguments when this rule is used. This is mutually exclusive with [args](#cc_nested_args-args).   |  `None` |
-| <a id="cc_nested_args-requires_not_none"></a>requires_not_none |  (Label) The label of a `cc_variable` that should be checked for existence before expanding this rule. If the variable is None, this rule will be ignored.   |  `None` |
-| <a id="cc_nested_args-requires_none"></a>requires_none |  (Label) The label of a `cc_variable` that should be checked for non-existence before expanding this rule. If the variable is not None, this rule will be ignored.   |  `None` |
-| <a id="cc_nested_args-requires_true"></a>requires_true |  (Label) The label of a `cc_variable` that should be checked for truthiness before expanding this rule. If the variable is false, this rule will be ignored.   |  `None` |
-| <a id="cc_nested_args-requires_false"></a>requires_false |  (Label) The label of a `cc_variable` that should be checked for falsiness before expanding this rule. If the variable is true, this rule will be ignored.   |  `None` |
-| <a id="cc_nested_args-requires_equal"></a>requires_equal |  (Label) The label of a `cc_variable` that should be checked for equality before expanding this rule. If the variable is not equal to (requires_equal_value)[#cc_nested_args-requires_equal_value], this rule will be ignored.   |  `None` |
+| <a id="cc_nested_args-format"></a>format |  (Dict[str, Label]) A mapping of format strings to the label of the corresponding [`cc_variable`](#cc_variable) that the value should be pulled from. All instances of `{variable_name}` will be replaced with the expanded value of `variable_name` in this dictionary. The complete list of possible variables can be found in https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/variables/BUILD. It is not possible to declare custom variables--these are inherent to Bazel itself.   |  `{}` |
+| <a id="cc_nested_args-iterate_over"></a>iterate_over |  (Label) The label of a [`cc_variable`](#cc_variable) that should be iterated over. This is intended for use with built-in variables that are lists.   |  `None` |
+| <a id="cc_nested_args-nested"></a>nested |  (List[Label]) A list of [`cc_nested_args`](#cc_nested_args) rules that should be expanded to command-line arguments when this rule is used. This is mutually exclusive with [args](#cc_nested_args-args).   |  `None` |
+| <a id="cc_nested_args-requires_not_none"></a>requires_not_none |  (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for existence before expanding this rule. If the variable is None, this rule will be ignored.   |  `None` |
+| <a id="cc_nested_args-requires_none"></a>requires_none |  (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for non-existence before expanding this rule. If the variable is not None, this rule will be ignored.   |  `None` |
+| <a id="cc_nested_args-requires_true"></a>requires_true |  (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for truthiness before expanding this rule. If the variable is false, this rule will be ignored.   |  `None` |
+| <a id="cc_nested_args-requires_false"></a>requires_false |  (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for falsiness before expanding this rule. If the variable is true, this rule will be ignored.   |  `None` |
+| <a id="cc_nested_args-requires_equal"></a>requires_equal |  (Label) The label of a [`cc_variable`](#cc_variable) that should be checked for equality before expanding this rule. If the variable is not equal to (requires_equal_value)[#cc_nested_args-requires_equal_value], this rule will be ignored.   |  `None` |
 | <a id="cc_nested_args-requires_equal_value"></a>requires_equal_value |  (str) The value to compare (requires_equal)[#cc_nested_args-requires_equal] against.   |  `None` |
 | <a id="cc_nested_args-kwargs"></a>kwargs |  [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule.   |  none |
 
@@ -221,31 +627,32 @@
 
 A toolchain configuration rule that maps toolchain actions to tools.
 
-A cc_tool_map aggregates all the tools that may be used for a given toolchain and maps them to
-their corresponding actions. Conceptually, this is similar to the `CXX=/path/to/clang++`
-environment variables that most build systems use to determine which tools to use for a given
-action. To simplify usage, some actions have been grouped together (for example,
-//third_party/bazel_rules/rules_cc/cc/toolchains/actions:cpp_compile_actions) to
+A [`cc_tool_map`](#cc_tool_map) aggregates all the tools that may be used for a given toolchain
+and maps them to their corresponding actions. Conceptually, this is similar to the
+`CXX=/path/to/clang++` environment variables that most build systems use to determine which
+tools to use for a given action. To simplify usage, some actions have been grouped together (for
+example,
+[@rules_cc//cc/toolchains/actions:cpp_compile_actions](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/actions/BUILD)) to
 logically express "all the C++ compile actions".
 
 In Bazel, there is a little more granularity to the mapping, so the mapping doesn't follow the
 traditional `CXX`, `AR`, etc. naming scheme. For a comprehensive list of all the well-known
-actions, see //third_party/bazel_rules/rules_cc/cc/toolchains/actions:BUILD.
+actions, see @rules_cc//cc/toolchains/actions:BUILD.
 
 Example usage:
 ```
-load("//third_party/bazel_rules/rules_cc/cc/toolchains:tool_map.bzl", "cc_tool_map")
+load("@rules_cc//cc/toolchains:tool_map.bzl", "cc_tool_map")
 
 cc_tool_map(
     name = "all_tools",
     tools = {
-        "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:assembly_actions": ":asm",
-        "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:c_compile": ":clang",
-        "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:cpp_compile_actions": ":clang++",
-        "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:link_actions": ":lld",
-        "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:objcopy_embed_data": ":llvm-objcopy",
-        "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:strip": ":llvm-strip",
-        "//third_party/bazel_rules/rules_cc/cc/toolchains/actions:ar_actions": ":llvm-ar",
+        "@rules_cc//cc/toolchains/actions:assembly_actions": ":asm",
+        "@rules_cc//cc/toolchains/actions:c_compile": ":clang",
+        "@rules_cc//cc/toolchains/actions:cpp_compile_actions": ":clang++",
+        "@rules_cc//cc/toolchains/actions:link_actions": ":lld",
+        "@rules_cc//cc/toolchains/actions:objcopy_embed_data": ":llvm-objcopy",
+        "@rules_cc//cc/toolchains/actions:strip": ":llvm-strip",
+        "@rules_cc//cc/toolchains/actions:ar_actions": ":llvm-ar",
     },
 )
 ```
@@ -262,7 +669,47 @@
 | Name  | Description | Default Value |
 | :------------- | :------------- | :------------- |
 | <a id="cc_tool_map-name"></a>name |  (str) The name of the target.   |  none |
-| <a id="cc_tool_map-tools"></a>tools |  (Dict[target providing ActionTypeSetInfo, Executable target]) A mapping between `cc_action_type` targets and the `cc_tool` or executable target that implements that action.   |  none |
+| <a id="cc_tool_map-tools"></a>tools |  (Dict[Label, Label]) A mapping between [`cc_action_type`](#cc_action_type)/[`cc_action_type_set`](#cc_action_type_set) targets and the [`cc_tool`](#cc_tool) or executable target that implements that action.   |  none |
 | <a id="cc_tool_map-kwargs"></a>kwargs |  [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule.   |  none |
 
 
+<a id="cc_variable"></a>
+
+## cc_variable
+
+<pre>
+cc_variable(<a href="#cc_variable-name">name</a>, <a href="#cc_variable-type">type</a>, <a href="#cc_variable-kwargs">kwargs</a>)
+</pre>
+
+Exposes a toolchain variable to use in toolchain argument expansions.
+
+This internal rule exposes [toolchain variables](https://bazel.build/docs/cc-toolchain-config-reference#cctoolchainconfiginfo-build-variables)
+that may be expanded in [`cc_args`](#cc_args) or [`cc_nested_args`](#cc_nested_args)
+rules. Because these varaibles merely expose variables inherrent to Bazel,
+it's not possible to declare custom variables.
+
+For a full list of available variables, see
+[@rules_cc//cc/toolchains/varaibles:BUILD](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/variables/BUILD).
+
+Example:
+```
+load("@rules_cc//cc/toolchains/impl:variables.bzl", "cc_variable")
+
+# Defines two targets, ":foo" and ":foo.bar"
+cc_variable(
+    name = "foo",
+    type = types.list(types.struct(bar = types.string)),
+)
+```
+
+
+**PARAMETERS**
+
+
+| Name  | Description | Default Value |
+| :------------- | :------------- | :------------- |
+| <a id="cc_variable-name"></a>name |  (str) The name of the outer variable, and the rule.   |  none |
+| <a id="cc_variable-type"></a>type |  The type of the variable, constructed using `types` factory in [@rules_cc//cc/toolchains/impl:variables.bzl](https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/impl/variables.bzl).   |  none |
+| <a id="cc_variable-kwargs"></a>kwargs |  [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule.   |  none |
+
+
diff --git a/cc/toolchains/toolchain_config_utils.bzl b/cc/toolchains/toolchain_config_utils.bzl
new file mode 100644
index 0000000..82b3ded
--- /dev/null
+++ b/cc/toolchains/toolchain_config_utils.bzl
@@ -0,0 +1,29 @@
+# Copyright 2024 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""Exposing some helper functions for configure cc toolchains."""
+
+load("//cc/private/toolchain:cc_configure.bzl", _MSVC_ENVVARS = "MSVC_ENVVARS")
+load("//cc/private/toolchain:lib_cc_configure.bzl", _escape_string = "escape_string")
+load("//cc/private/toolchain:windows_cc_configure.bzl", _find_vc_path = "find_vc_path", _setup_vc_env_vars = "setup_vc_env_vars")
+
+MSVC_ENVVARS = _MSVC_ENVVARS
+
+def find_vc_path(repository_ctx):
+    return _find_vc_path(repository_ctx)
+
+def setup_vc_env_vars(repository_ctx):
+    return _setup_vc_env_vars(repository_ctx)
+
+def escape_string(string):
+    return _escape_string(string)
diff --git a/examples/custom_toolchain/toolchain_config.bzl b/examples/custom_toolchain/toolchain_config.bzl
index e83162b..74b2280 100644
--- a/examples/custom_toolchain/toolchain_config.bzl
+++ b/examples/custom_toolchain/toolchain_config.bzl
@@ -12,7 +12,7 @@
 advanced usage.
 """
 
-load("@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", "tool_path")
+load("@rules_cc//cc:cc_toolchain_config_lib.bzl", "tool_path")  # buildifier: disable=deprecated-function
 
 def _impl(ctx):
     tool_paths = [
diff --git a/examples/my_c_archive/my_c_archive.bzl b/examples/my_c_archive/my_c_archive.bzl
index 314564f..84b34e5 100644
--- a/examples/my_c_archive/my_c_archive.bzl
+++ b/examples/my_c_archive/my_c_archive.bzl
@@ -14,8 +14,8 @@
 
 """Example showing how to create a rule that rules_cc can depend on."""
 
-load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain", "use_cpp_toolchain")
 load("@rules_cc//cc:action_names.bzl", "CPP_LINK_STATIC_LIBRARY_ACTION_NAME")
+load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cpp_toolchain", "use_cc_toolchain")
 load("//examples/my_c_compile:my_c_compile.bzl", "MyCCompileInfo")
 
 def _my_c_archive_impl(ctx):
@@ -92,8 +92,8 @@
     attrs = {
         "deps": attr.label_list(providers = [CcInfo]),
         "object": attr.label(mandatory = True, providers = [MyCCompileInfo]),
-        "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")),
+        "_cc_toolchain": attr.label(default = Label("@rules_cc//cc:current_cc_toolchain")),
     },
     fragments = ["cpp"],
-    toolchains = use_cpp_toolchain(),
+    toolchains = use_cc_toolchain(),
 )
diff --git a/examples/my_c_compile/my_c_compile.bzl b/examples/my_c_compile/my_c_compile.bzl
index d232f91..ac4fea9 100644
--- a/examples/my_c_compile/my_c_compile.bzl
+++ b/examples/my_c_compile/my_c_compile.bzl
@@ -14,8 +14,8 @@
 
 """Example showing how to create a rule that just compiles C sources."""
 
-load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain", "use_cpp_toolchain")
 load("@rules_cc//cc:action_names.bzl", "C_COMPILE_ACTION_NAME")
+load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cpp_toolchain", "use_cc_toolchain")
 
 MyCCompileInfo = provider(doc = "", fields = ["object"])
 
@@ -74,8 +74,8 @@
     implementation = _my_c_compile_impl,
     attrs = {
         "src": attr.label(mandatory = True, allow_single_file = True),
-        "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")),
+        "_cc_toolchain": attr.label(default = Label("@rules_cc//cc:current_cc_toolchain")),
     },
-    toolchains = use_cpp_toolchain(),
+    toolchains = use_cc_toolchain(),
     fragments = ["cpp"],
 )
diff --git a/examples/write_cc_toolchain_cpu/write_cc_toolchain_cpu.bzl b/examples/write_cc_toolchain_cpu/write_cc_toolchain_cpu.bzl
index 3e93b42..a3015c4 100644
--- a/examples/write_cc_toolchain_cpu/write_cc_toolchain_cpu.bzl
+++ b/examples/write_cc_toolchain_cpu/write_cc_toolchain_cpu.bzl
@@ -14,7 +14,7 @@
 
 """Example showing how to get CcToolchainInfo in a custom rule."""
 
-load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain", "use_cpp_toolchain")
+load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cpp_toolchain", "use_cc_toolchain")
 
 def _write_cc_toolchain_cpu_impl(ctx):
     cc_toolchain = find_cpp_toolchain(ctx)
@@ -26,7 +26,7 @@
 write_cc_toolchain_cpu = rule(
     implementation = _write_cc_toolchain_cpu_impl,
     attrs = {
-        "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")),
+        "_cc_toolchain": attr.label(default = Label("@rules_cc//cc:current_cc_toolchain")),
     },
-    toolchains = use_cpp_toolchain(),
+    toolchains = use_cc_toolchain(),
 )
diff --git a/tests/rule_based_toolchain/generate_factory.bzl b/tests/rule_based_toolchain/generate_factory.bzl
index c58bb51..ea9dc58 100644
--- a/tests/rule_based_toolchain/generate_factory.bzl
+++ b/tests/rule_based_toolchain/generate_factory.bzl
@@ -67,7 +67,7 @@
             meta.add_failure("Wanted a %s but got" % name, value)
         got_keys = sorted(structs.to_dict(value).keys())
         subjects.collection(got_keys, meta = meta.derive(details = [
-            "Value was not a %s - it has a different set of fields" % name,
+            "Value %r was not a %s - it has a different set of fields" % (value, name),
         ])).contains_exactly(want_keys).in_order()
 
     def type_factory(value, *, meta):
diff --git a/tests/rule_based_toolchain/subjects.bzl b/tests/rule_based_toolchain/subjects.bzl
index e741d67..be36b1c 100644
--- a/tests/rule_based_toolchain/subjects.bzl
+++ b/tests/rule_based_toolchain/subjects.bzl
@@ -26,6 +26,7 @@
     "FeatureSetInfo",
     "MutuallyExclusiveCategoryInfo",
     "NestedArgsInfo",
+    "ToolCapabilityInfo",
     "ToolConfigInfo",
     "ToolInfo",
     "ToolchainConfigInfo",
@@ -179,6 +180,15 @@
 )
 
 # buildifier: disable=name-conventions
+_ToolCapabilityFactory = generate_factory(
+    ToolCapabilityInfo,
+    "ToolCapabilityInfo",
+    dict(
+        name = _subjects.str,
+    ),
+)
+
+# buildifier: disable=name-conventions
 _ToolFactory = generate_factory(
     ToolInfo,
     "ToolInfo",
@@ -187,6 +197,7 @@
         runfiles = runfiles_subject,
         execution_requirements = _subjects.collection,
         allowlist_include_directories = _FakeDirectoryDepset,
+        capabilities = ProviderSequence(_ToolCapabilityFactory),
     ),
 )
 
diff --git a/tests/rule_based_toolchain/tool/BUILD b/tests/rule_based_toolchain/tool/BUILD
index 67ce625..daa617a 100644
--- a/tests/rule_based_toolchain/tool/BUILD
+++ b/tests/rule_based_toolchain/tool/BUILD
@@ -6,6 +6,7 @@
 cc_tool(
     name = "tool",
     src = "//tests/rule_based_toolchain/testdata:bin_wrapper.sh",
+    capabilities = ["//cc/toolchains/capabilities:supports_pic"],
     data = ["//tests/rule_based_toolchain/testdata:bin"],
     tags = ["requires-network"],
 )
diff --git a/tests/rule_based_toolchain/toolchain_config/BUILD b/tests/rule_based_toolchain/toolchain_config/BUILD
index b002eff..6d894a9 100644
--- a/tests/rule_based_toolchain/toolchain_config/BUILD
+++ b/tests/rule_based_toolchain/toolchain_config/BUILD
@@ -47,6 +47,7 @@
     name = "c_compile_tool",
     src = "//tests/rule_based_toolchain/testdata:bin_wrapper",
     allowlist_include_directories = ["//tests/rule_based_toolchain/testdata:subdirectory_3"],
+    capabilities = ["//cc/toolchains/capabilities:supports_pic"],
 )
 
 cc_sysroot(
diff --git a/tests/rule_based_toolchain/toolchain_config/toolchain_config_test.bzl b/tests/rule_based_toolchain/toolchain_config/toolchain_config_test.bzl
index 71a05cf..f54fb52 100644
--- a/tests/rule_based_toolchain/toolchain_config/toolchain_config_test.bzl
+++ b/tests/rule_based_toolchain/toolchain_config/toolchain_config_test.bzl
@@ -208,6 +208,10 @@
             )],
         ),
         legacy_feature(
+            name = "supports_pic",
+            enabled = False,
+        ),
+        legacy_feature(
             name = "implied_by_always_enabled",
             enabled = True,
             flag_sets = [
@@ -252,6 +256,7 @@
             action_name = "c_compile",
             enabled = True,
             tools = [legacy_tool(tool = exe)],
+            implies = ["supports_pic"],
         ),
         legacy_action_config(
             action_name = "cpp_compile",
diff --git a/tools/migration/crosstool_to_starlark_lib.go b/tools/migration/crosstool_to_starlark_lib.go
index 4403a4b..15f5c12 100644
--- a/tools/migration/crosstool_to_starlark_lib.go
+++ b/tools/migration/crosstool_to_starlark_lib.go
@@ -27,7 +27,7 @@
 
 // Writes the load statement for the cc_toolchain_config_lib
 func getCcToolchainConfigHeader() string {
-	return `load("@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl",
+	return `load("@rules_cc//cc:cc_toolchain_config_lib.bzl",
     "action_config",
     "artifact_name_pattern",
     "env_entry",
@@ -118,7 +118,7 @@
 }
 
 func getLoadActionsStmt() string {
-	return "load(\"@bazel_tools//tools/build_defs/cc:action_names.bzl\", \"ACTION_NAMES\")\n\n"
+	return "load(\"@rules_cc//cc:action_names.bzl\", \"ACTION_NAMES\")\n\n"
 }
 
 // Returns a map {toolchain_identifier : CToolchainIdentifier}
diff --git a/tools/migration/crosstool_to_starlark_lib_test.go b/tools/migration/crosstool_to_starlark_lib_test.go
index a5db02f..63d9736 100644
--- a/tools/migration/crosstool_to_starlark_lib_test.go
+++ b/tools/migration/crosstool_to_starlark_lib_test.go
@@ -1533,7 +1533,7 @@
 
 func TestRule(t *testing.T) {
 	simpleToolchain := getSimpleCToolchain("simple")
-	expected := `load("@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl",
+	expected := `load("@rules_cc//cc:cc_toolchain_config_lib.bzl",
     "action_config",
     "artifact_name_pattern",
     "env_entry",
@@ -1548,7 +1548,7 @@
     "variable_with_value",
     "with_feature_set",
 )
-load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
+load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES")
 
 def _impl(ctx):
     toolchain_identifier = "id-simple"