Refactor unix cc autoconfiguration to not use a template Starlark cc_toolchain_config rule

RELNOTES: None.
PiperOrigin-RevId: 249219938
diff --git a/tools/cpp/BUILD.tpl b/tools/cpp/BUILD.tpl
index be1fbf5..23a4bc5 100644
--- a/tools/cpp/BUILD.tpl
+++ b/tools/cpp/BUILD.tpl
@@ -73,6 +73,24 @@
     name = "%{cc_toolchain_identifier}",
     cpu = "%{target_cpu}",
     compiler = "%{compiler}",
+    toolchain_identifier = "%{cc_toolchain_identifier}",
+    host_system_name = "%{host_system_name}",
+    target_system_name = "%{target_system_name}",
+    target_libc = "%{target_libc}",
+    abi_version = "%{abi_version}",
+    abi_libc_version = "%{abi_libc_version}",
+    cxx_builtin_include_directories = [%{cxx_builtin_include_directories}],
+    tool_paths = {%{tool_paths}},
+    compile_flags = [%{compile_flags}],
+    opt_compile_flags = [%{opt_compile_flags}],
+    dbg_compile_flags = [%{dbg_compile_flags}],
+    cxx_flags = [%{cxx_flags}],
+    link_flags = [%{link_flags}],
+    opt_link_flags = [%{opt_link_flags}],
+    unfiltered_compile_flags = [%{unfiltered_compile_flags}],
+    coverage_compile_flags = [%{coverage_compile_flags}],
+    coverage_link_flags = [%{coverage_link_flags}],
+    supports_start_end_lib = %{supports_start_end_lib},
 )
 
 toolchain(
diff --git a/tools/cpp/unix_cc_configure.bzl b/tools/cpp/unix_cc_configure.bzl
index 2eeca8e..0cfc5aa 100644
--- a/tools/cpp/unix_cc_configure.bzl
+++ b/tools/cpp/unix_cc_configure.bzl
@@ -72,14 +72,6 @@
     else:
         return "\"%s\"" % it
 
-def _build_tool_path(d):
-    """Build the list of %-escaped tool_path for the CROSSTOOL file."""
-    return ["  tool_path { name: \"%s\" path: \"%s\" }" % (k, escape_string(d[k])) for k in d]
-
-def _build_tool_path_starlark(d):
-    """Build the list of %-escaped tool_path for the Starlark rule."""
-    return "\n".join(["        tool_path ( name= \"%s\", path= \"%s\" )," % (k, escape_string(d[k])) for k in d])
-
 def _find_tool(repository_ctx, tool, overriden_tools):
     """Find a tool for repository, taking overriden tools into account."""
     if tool in overriden_tools:
@@ -87,9 +79,9 @@
     return which(repository_ctx, tool, "/usr/bin/" + tool)
 
 def _get_tool_paths(repository_ctx, overriden_tools):
-    """Compute the path to the various tools. Doesn't %-escape the result!"""
+    """Compute the %-escaped path to the various tools"""
     return dict({
-        k: _find_tool(repository_ctx, k, overriden_tools)
+        k: escape_string(_find_tool(repository_ctx, k, overriden_tools))
         for k in [
             "ar",
             "ld",
@@ -231,7 +223,7 @@
     else:
         return ""
 
-def _coverage_feature(repository_ctx, darwin):
+def _coverage_flags(repository_ctx, darwin):
     use_llvm_cov = "1" == get_env_var(
         repository_ctx,
         "BAZEL_USE_LLVM_NATIVE_COVERAGE",
@@ -239,49 +231,14 @@
         enable_warning = False,
     )
     if darwin or use_llvm_cov:
-        compile_flags = """flag_group (
-                    flags = ["-fprofile-instr-generate",  "-fcoverage-mapping"],
-                ),"""
-        link_flags = """flag_group (flags = ["-fprofile-instr-generate"]),"""
+        compile_flags = '"-fprofile-instr-generate",  "-fcoverage-mapping"'
+        link_flags = '"-fprofile-instr-generate"'
     else:
         # gcc requires --coverage being passed for compilation and linking
         # https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html#Instrumentation-Options
-        compile_flags = """flag_group (flags = ["--coverage"]),"""
-        link_flags = """flag_group (flags = ["--coverage"]),"""
-
-    # Note that we also set --coverage for c++-link-nodeps-dynamic-library. The
-    # generated code contains references to gcov symbols, and the dynamic linker
-    # can't resolve them unless the library is linked against gcov.
-    return """
-    coverage_feature = feature (
-        name = "coverage",
-        provides = ["profile"],
-        flag_sets = [
-            flag_set(
-                actions = [
-                    ACTION_NAMES.preprocess_assemble,
-                    ACTION_NAMES.c_compile,
-                    ACTION_NAMES.cpp_compile,
-                    ACTION_NAMES.cpp_header_parsing,
-                    ACTION_NAMES.cpp_module_compile,
-                ],
-                flag_groups = [
-                    """ + compile_flags + """
-                ],
-            ),
-            flag_set (
-                actions = [
-                    ACTION_NAMES.cpp_link_dynamic_library,
-                    ACTION_NAMES.cpp_link_nodeps_dynamic_library,
-                    ACTION_NAMES.cpp_link_executable,
-                ],
-                flag_groups = [
-                    """ + link_flags + """
-                ],
-            ),
-        ],
-    )
-"""
+        compile_flags = '"--coverage"'
+        link_flags = '"--coverage"'
+    return compile_flags, link_flags
 
 def _find_generic(repository_ctx, name, env_name, overriden_tools, warn = False, silent = False):
     """Find a generic C++ toolchain tool. Doesn't %-escape the result."""
@@ -314,20 +271,22 @@
 def find_cc(repository_ctx, overriden_tools):
     return _find_generic(repository_ctx, "gcc", "CC", overriden_tools)
 
-def _feature(name, enabled):
-    return "  feature { name: '" + name + "' enabled: " + ("true" if enabled else "false") + " }"
-
 def configure_unix_toolchain(repository_ctx, cpu_value, overriden_tools):
     """Configure C++ toolchain on Unix platforms."""
     paths = resolve_labels(repository_ctx, [
         "@bazel_tools//tools/cpp:BUILD.tpl",
         "@bazel_tools//tools/cpp:armeabi_cc_toolchain_config.bzl",
-        "@bazel_tools//tools/cpp:cc_toolchain_config.bzl.tpl",
+        "@bazel_tools//tools/cpp:unix_cc_toolchain_config.bzl",
         "@bazel_tools//tools/cpp:linux_cc_wrapper.sh.tpl",
         "@bazel_tools//tools/cpp:osx_cc_wrapper.sh.tpl",
     ])
 
     repository_ctx.symlink(
+        paths["@bazel_tools//tools/cpp:unix_cc_toolchain_config.bzl"],
+        "cc_toolchain_config.bzl",
+    )
+
+    repository_ctx.symlink(
         paths["@bazel_tools//tools/cpp:armeabi_cc_toolchain_config.bzl"],
         "armeabi_cc_toolchain_config.bzl",
     )
@@ -351,25 +310,12 @@
         overriden_tools["ar"] = "/usr/bin/libtool"
 
     tool_paths = _get_tool_paths(repository_ctx, overriden_tools)
-    cc_toolchain_identifier = get_env_var(repository_ctx, "CC_TOOLCHAIN_NAME", "local", False)
-
-    repository_ctx.template(
-        "BUILD",
-        paths["@bazel_tools//tools/cpp:BUILD.tpl"],
-        {
-            "%{cc_toolchain_identifier}": cc_toolchain_identifier,
-            "%{name}": cpu_value,
-            "%{supports_param_files}": "0" if darwin else "1",
-            "%{cc_compiler_deps}": ":cc_wrapper" if darwin else ":empty",
-            "%{compiler}": get_env_var(
-                repository_ctx,
-                "BAZEL_COMPILER",
-                "compiler",
-                False,
-            ),
-            "%{target_cpu}": escape_string(get_env_var(repository_ctx, "BAZEL_TARGET_CPU", cpu_value, False)),
-        },
-    )
+    cc_toolchain_identifier = escape_string(get_env_var(
+        repository_ctx,
+        "CC_TOOLCHAIN_NAME",
+        "local",
+        False,
+    ))
 
     cc_wrapper_src = (
         "@bazel_tools//tools/cpp:osx_cc_wrapper.sh.tpl" if darwin else "@bazel_tools//tools/cpp:linux_cc_wrapper.sh.tpl"
@@ -383,8 +329,18 @@
         },
     )
 
-    cxx_opts = split_escaped(get_env_var(repository_ctx, "BAZEL_CXXOPTS", "-std=c++0x", False), ":")
-    link_opts = split_escaped(get_env_var(repository_ctx, "BAZEL_LINKOPTS", "-lstdc++:-lm", False), ":")
+    cxx_opts = split_escaped(get_env_var(
+        repository_ctx,
+        "BAZEL_CXXOPTS",
+        "-std=c++0x",
+        False,
+    ), ":")
+    link_opts = split_escaped(get_env_var(
+        repository_ctx,
+        "BAZEL_LINKOPTS",
+        "-lstdc++:-lm",
+        False,
+    ), ":")
     supports_gold_linker = _is_gold_supported(repository_ctx, cc)
     cc_path = repository_ctx.path(cc)
     if not str(cc_path).startswith(str(repository_ctx.path(".")) + "/"):
@@ -394,20 +350,61 @@
         # cc is inside the repository, don't set -B.
         bin_search_flag = []
 
+    coverage_compile_flags, coverage_link_flags = _coverage_flags(repository_ctx, darwin)
+
     repository_ctx.template(
-        "cc_toolchain_config.bzl",
-        paths["@bazel_tools//tools/cpp:cc_toolchain_config.bzl.tpl"],
+        "BUILD",
+        paths["@bazel_tools//tools/cpp:BUILD.tpl"],
         {
-            "%{toolchain_identifier}": escape_string(cc_toolchain_identifier),
-            "%{abi_version}": escape_string(get_env_var(repository_ctx, "ABI_VERSION", "local", False)),
-            "%{abi_libc_version}": escape_string(get_env_var(repository_ctx, "ABI_LIBC_VERSION", "local", False)),
-            "%{builtin_sysroot}": "",
-            "%{compiler}": escape_string(get_env_var(repository_ctx, "BAZEL_COMPILER", "compiler", False)),
-            "%{host_system_name}": escape_string(get_env_var(repository_ctx, "BAZEL_HOST_SYSTEM", "local", False)),
-            "%{target_libc}": "macosx" if darwin else escape_string(get_env_var(repository_ctx, "BAZEL_TARGET_LIBC", "local", False)),
-            "%{target_cpu}": escape_string(get_env_var(repository_ctx, "BAZEL_TARGET_CPU", cpu_value, False)),
-            "%{target_system_name}": escape_string(get_env_var(repository_ctx, "BAZEL_TARGET_SYSTEM", "local", False)),
-            "%{tool_paths}": _build_tool_path_starlark(tool_paths),
+            "%{cc_toolchain_identifier}": cc_toolchain_identifier,
+            "%{name}": cpu_value,
+            "%{supports_param_files}": "0" if darwin else "1",
+            "%{cc_compiler_deps}": ":cc_wrapper" if darwin else ":empty",
+            "%{compiler}": escape_string(get_env_var(
+                repository_ctx,
+                "BAZEL_COMPILER",
+                "compiler",
+                False,
+            )),
+            "%{abi_version}": escape_string(get_env_var(
+                repository_ctx,
+                "ABI_VERSION",
+                "local",
+                False,
+            )),
+            "%{abi_libc_version}": escape_string(get_env_var(
+                repository_ctx,
+                "ABI_LIBC_VERSION",
+                "local",
+                False,
+            )),
+            "%{host_system_name}": escape_string(get_env_var(
+                repository_ctx,
+                "BAZEL_HOST_SYSTEM",
+                "local",
+                False,
+            )),
+            "%{target_libc}": "macosx" if darwin else escape_string(get_env_var(
+                repository_ctx,
+                "BAZEL_TARGET_LIBC",
+                "local",
+                False,
+            )),
+            "%{target_cpu}": escape_string(get_env_var(
+                repository_ctx,
+                "BAZEL_TARGET_CPU",
+                cpu_value,
+                False,
+            )),
+            "%{target_system_name}": escape_string(get_env_var(
+                repository_ctx,
+                "BAZEL_TARGET_SYSTEM",
+                "local",
+                False,
+            )),
+            "%{tool_paths}": ",\n        ".join(
+                ['"%s": "%s"' % (k, v) for k, v in tool_paths.items()],
+            ),
             "%{cxx_builtin_include_directories}": get_starlark_list(
                 _uniq(
                     get_escaped_cxx_inc_directories(repository_ctx, cc, "-xc") +
@@ -426,7 +423,7 @@
                     ),
                 ),
             ),
-            "%{compile_content}": get_starlark_list(
+            "%{compile_flags}": get_starlark_list(
                 [
                     # Security hardening requires optimization.
                     # We need to undef it as some distributions now have it enabled by default.
@@ -451,8 +448,8 @@
                     "-fno-omit-frame-pointer",
                 ],
             ),
-            "%{cxx_content}": get_starlark_list(cxx_opts + _escaped_cplus_include_paths(repository_ctx)),
-            "%{link_content}": get_starlark_list((
+            "%{cxx_flags}": get_starlark_list(cxx_opts + _escaped_cplus_include_paths(repository_ctx)),
+            "%{link_flags}": get_starlark_list((
                 ["-fuse-ld=gold"] if supports_gold_linker else []
             ) + _add_linker_option_if_supported(
                 repository_ctx,
@@ -480,7 +477,7 @@
                     "-pass-exit-codes",
                 )
             ) + link_opts),
-            "%{opt_compile_content}": get_starlark_list(
+            "%{opt_compile_flags}": get_starlark_list(
                 [
                     # No debug symbols.
                     # Maybe we should enable https://gcc.gnu.org/wiki/DebugFission for opt or
@@ -500,12 +497,13 @@
                     # Disable assertions
                     "-DNDEBUG",
 
-                    # Removal of unused code and data at link time (can this increase binary size in some cases?).
+                    # Removal of unused code and data at link time (can this increase binary
+                    # size in some cases?).
                     "-ffunction-sections",
                     "-fdata-sections",
                 ],
             ),
-            "%{opt_link_content}": get_starlark_list(
+            "%{opt_link_flags}": get_starlark_list(
                 [] if darwin else _add_linker_option_if_supported(
                     repository_ctx,
                     cc,
@@ -513,7 +511,7 @@
                     "-gc-sections",
                 ),
             ),
-            "%{unfiltered_content}": get_starlark_list(
+            "%{unfiltered_compile_flags}": get_starlark_list(
                 _get_no_canonical_prefixes_opt(repository_ctx, cc) + [
                     # Make C++ compilation deterministic. Use linkstamping instead of these
                     # compiler symbols.
@@ -523,9 +521,9 @@
                     "-D__TIME__=\\\"redacted\\\"",
                 ],
             ),
-            "%{dbg_compile_content}": get_starlark_list(["-g"]),
-            "%{coverage_feature}": _coverage_feature(repository_ctx, darwin),
-            "%{use_coverage_feature}": "coverage_feature,",
-            "%{supports_start_end_lib}": "supports_start_end_lib_feature," if supports_gold_linker else "",
+            "%{dbg_compile_flags}": get_starlark_list(["-g"]),
+            "%{coverage_compile_flags}": coverage_compile_flags,
+            "%{coverage_link_flags}": coverage_link_flags,
+            "%{supports_start_end_lib}": "True" if supports_gold_linker else "False",
         },
     )
diff --git a/tools/cpp/cc_toolchain_config.bzl.tpl b/tools/cpp/unix_cc_toolchain_config.bzl
similarity index 82%
rename from tools/cpp/cc_toolchain_config.bzl.tpl
rename to tools/cpp/unix_cc_toolchain_config.bzl
index 253001a..d7da983 100644
--- a/tools/cpp/cc_toolchain_config.bzl.tpl
+++ b/tools/cpp/unix_cc_toolchain_config.bzl
@@ -13,23 +13,18 @@
 # limitations under the License.
 
 """A Starlark cc_toolchain configuration rule"""
-load("@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl",
-     "action_config",
-     "artifact_name_pattern",
-     "env_entry",
-     "env_set",
-     "feature",
-     "feature_set",
-     "flag_group",
-     "flag_set",
-     "make_variable",
-     "tool",
-     "tool_path",
-     "variable_with_value",
-     "with_feature_set",
-     )
-load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
 
+load(
+    "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl",
+    "feature",
+    "feature_set",
+    "flag_group",
+    "flag_set",
+    "tool_path",
+    "variable_with_value",
+    "with_feature_set",
+)
+load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
 
 all_compile_actions = [
     ACTION_NAMES.c_compile,
@@ -81,45 +76,11 @@
 
 def _impl(ctx):
     tool_paths = [
-%{tool_paths}
+        tool_path(name = name, path = path)
+        for name, path in ctx.attr.tool_paths.items()
     ]
-
-    cxx_builtin_include_directories = [
-%{cxx_builtin_include_directories}
-    ]
-
     action_configs = []
 
-    compile_flags = [
-        %{compile_content}
-    ]
-
-    dbg_compile_flags = [
-        %{dbg_compile_content}
-    ]
-
-    opt_compile_flags = [
-        %{opt_compile_content}
-    ]
-
-    cxx_flags = [
-        %{cxx_content}
-    ]
-
-    link_flags = [
-        %{link_content}
-    ]
-
-    opt_link_flags = [
-        %{opt_link_content}
-    ]
-
-    unfiltered_compile_flags = [
-        %{unfiltered_content}
-    ]
-
-    %{coverage_feature}
-
     supports_pic_feature = feature(
         name = "supports_pic",
         enabled = True,
@@ -146,7 +107,11 @@
                     ACTION_NAMES.lto_backend,
                     ACTION_NAMES.clif_match,
                 ],
-                flag_groups = ([flag_group(flags = compile_flags)] if compile_flags else []),
+                flag_groups = ([
+                    flag_group(
+                        flags = ctx.attr.compile_flags,
+                    ),
+                ] if ctx.attr.compile_flags else []),
             ),
             flag_set(
                 actions = [
@@ -161,7 +126,11 @@
                     ACTION_NAMES.lto_backend,
                     ACTION_NAMES.clif_match,
                 ],
-                flag_groups = ([flag_group(flags = dbg_compile_flags)] if dbg_compile_flags else []),
+                flag_groups = ([
+                    flag_group(
+                        flags = ctx.attr.dbg_compile_flags,
+                    ),
+                ] if ctx.attr.dbg_compile_flags else []),
                 with_features = [with_feature_set(features = ["dbg"])],
             ),
             flag_set(
@@ -177,7 +146,11 @@
                     ACTION_NAMES.lto_backend,
                     ACTION_NAMES.clif_match,
                 ],
-                flag_groups = ([flag_group(flags = opt_compile_flags)] if opt_compile_flags else []),
+                flag_groups = ([
+                    flag_group(
+                        flags = ctx.attr.opt_compile_flags,
+                    ),
+                ] if ctx.attr.opt_compile_flags else []),
                 with_features = [with_feature_set(features = ["opt"])],
             ),
             flag_set(
@@ -190,7 +163,11 @@
                     ACTION_NAMES.lto_backend,
                     ACTION_NAMES.clif_match,
                 ],
-                flag_groups = ([flag_group(flags = cxx_flags)] if cxx_flags else []),
+                flag_groups = ([
+                    flag_group(
+                        flags = ctx.attr.cxx_flags,
+                    ),
+                ] if ctx.attr.cxx_flags else []),
             ),
         ],
     )
@@ -201,11 +178,19 @@
         flag_sets = [
             flag_set(
                 actions = all_link_actions,
-                flag_groups = ([flag_group(flags = link_flags)] if link_flags else []),
+                flag_groups = ([
+                    flag_group(
+                        flags = ctx.attr.link_flags,
+                    ),
+                ] if ctx.attr.link_flags else []),
             ),
             flag_set(
                 actions = all_link_actions,
-                flag_groups = ([flag_group(flags = opt_link_flags)] if opt_link_flags else []),
+                flag_groups = ([
+                    flag_group(
+                        flags = ctx.attr.opt_link_flags,
+                    ),
+                ] if ctx.attr.opt_link_flags else []),
                 with_features = [with_feature_set(features = ["opt"])],
             ),
         ],
@@ -221,24 +206,24 @@
         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_codegen,
-                  ACTION_NAMES.lto_backend,
-                  ACTION_NAMES.clif_match,
-                  ACTION_NAMES.cpp_link_executable,
-                  ACTION_NAMES.cpp_link_dynamic_library,
-                  ACTION_NAMES.cpp_link_nodeps_dynamic_library,
+                    ACTION_NAMES.preprocess_assemble,
+                    ACTION_NAMES.linkstamp_compile,
+                    ACTION_NAMES.c_compile,
+                    ACTION_NAMES.cpp_compile,
+                    ACTION_NAMES.cpp_header_parsing,
+                    ACTION_NAMES.cpp_module_compile,
+                    ACTION_NAMES.cpp_module_codegen,
+                    ACTION_NAMES.lto_backend,
+                    ACTION_NAMES.clif_match,
+                    ACTION_NAMES.cpp_link_executable,
+                    ACTION_NAMES.cpp_link_dynamic_library,
+                    ACTION_NAMES.cpp_link_nodeps_dynamic_library,
                 ],
                 flag_groups = [
-                  flag_group(
-                      flags = ["--sysroot=%{sysroot}"],
-                      expand_if_available = "sysroot",
-                  ),
+                    flag_group(
+                        flags = ["--sysroot=%{sysroot}"],
+                        expand_if_available = "sysroot",
+                    ),
                 ],
             ),
         ],
@@ -250,13 +235,13 @@
             flag_set(
                 actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile],
                 flag_groups = [
-                  flag_group(
-                      flags = [
-                        "-fprofile-use=%{fdo_profile_path}",
-                        "-fprofile-correction",
-                      ],
-                      expand_if_available = "fdo_profile_path",
-                  ),
+                    flag_group(
+                        flags = [
+                            "-fprofile-use=%{fdo_profile_path}",
+                            "-fprofile-correction",
+                        ],
+                        expand_if_available = "fdo_profile_path",
+                    ),
                 ],
             ),
         ],
@@ -271,26 +256,26 @@
         flag_sets = [
             flag_set(
                 actions = [
-                  ACTION_NAMES.assemble,
-                  ACTION_NAMES.preprocess_assemble,
-                  ACTION_NAMES.linkstamp_compile,
-                  ACTION_NAMES.c_compile,
-                  ACTION_NAMES.cpp_compile,
-                  ACTION_NAMES.cpp_header_parsing,
-                  ACTION_NAMES.cpp_module_compile,
-                  ACTION_NAMES.cpp_module_codegen,
-                  ACTION_NAMES.lto_backend,
-                  ACTION_NAMES.clif_match,
+                    ACTION_NAMES.assemble,
+                    ACTION_NAMES.preprocess_assemble,
+                    ACTION_NAMES.linkstamp_compile,
+                    ACTION_NAMES.c_compile,
+                    ACTION_NAMES.cpp_compile,
+                    ACTION_NAMES.cpp_header_parsing,
+                    ACTION_NAMES.cpp_module_compile,
+                    ACTION_NAMES.cpp_module_codegen,
+                    ACTION_NAMES.lto_backend,
+                    ACTION_NAMES.clif_match,
                 ],
                 flag_groups = [
-                  flag_group(
-                      flags = ["%{user_compile_flags}"],
-                      iterate_over = "user_compile_flags",
-                      expand_if_available = "user_compile_flags",
-                  ),
+                    flag_group(
+                        flags = ["%{user_compile_flags}"],
+                        iterate_over = "user_compile_flags",
+                        expand_if_available = "user_compile_flags",
+                    ),
                 ],
             ),
-          ],
+        ],
     )
 
     unfiltered_compile_flags_feature = feature(
@@ -299,18 +284,22 @@
         flag_sets = [
             flag_set(
                 actions = [
-                  ACTION_NAMES.assemble,
-                  ACTION_NAMES.preprocess_assemble,
-                  ACTION_NAMES.linkstamp_compile,
-                  ACTION_NAMES.c_compile,
-                  ACTION_NAMES.cpp_compile,
-                  ACTION_NAMES.cpp_header_parsing,
-                  ACTION_NAMES.cpp_module_compile,
-                  ACTION_NAMES.cpp_module_codegen,
-                  ACTION_NAMES.lto_backend,
-                  ACTION_NAMES.clif_match,
+                    ACTION_NAMES.assemble,
+                    ACTION_NAMES.preprocess_assemble,
+                    ACTION_NAMES.linkstamp_compile,
+                    ACTION_NAMES.c_compile,
+                    ACTION_NAMES.cpp_compile,
+                    ACTION_NAMES.cpp_header_parsing,
+                    ACTION_NAMES.cpp_module_compile,
+                    ACTION_NAMES.cpp_module_codegen,
+                    ACTION_NAMES.lto_backend,
+                    ACTION_NAMES.clif_match,
                 ],
-                flag_groups = ([flag_group(flags = unfiltered_compile_flags)] if unfiltered_compile_flags else []),
+                flag_groups = ([
+                    flag_group(
+                        flags = ctx.attr.unfiltered_compile_flags,
+                    ),
+                ] if ctx.attr.unfiltered_compile_flags else []),
             ),
         ],
     )
@@ -342,7 +331,7 @@
                 ],
                 flag_groups = [flag_group(flags = ["-static-libgcc"])],
                 with_features = [
-                    with_feature_set(features = ["static_link_cpp_runtimes"])
+                    with_feature_set(features = ["static_link_cpp_runtimes"]),
                 ],
             ),
         ],
@@ -481,7 +470,7 @@
                     ),
                 ],
                 with_features = [
-                    with_feature_set(features = ["static_link_cpp_runtimes"])
+                    with_feature_set(features = ["static_link_cpp_runtimes"]),
                 ],
             ),
             flag_set(
@@ -537,9 +526,6 @@
         ],
     )
 
-    if "%{use_coverage_feature}" == "":
-        coverage_feature = feature(name = "coverage")
-
     random_seed_feature = feature(
         name = "random_seed",
         enabled = True,
@@ -628,7 +614,7 @@
                 flag_groups = [
                     flag_group(
                         flags = [
-                            "-fcs-profile-generate=%{cs_fdo_instrument_path}"
+                            "-fcs-profile-generate=%{cs_fdo_instrument_path}",
                         ],
                         expand_if_available = "cs_fdo_instrument_path",
                     ),
@@ -680,7 +666,7 @@
                 flag_groups = [
                     flag_group(
                         flags = [
-                            "-Wl,--print-symbol-counts=%{symbol_counts_output}"
+                            "-Wl,--print-symbol-counts=%{symbol_counts_output}",
                         ],
                         expand_if_available = "symbol_counts_output",
                     ),
@@ -705,7 +691,7 @@
                     flag_group(
                         flags = [
                             "-fprofile-instr-generate",
-                            "-fcoverage-mapping"
+                            "-fcoverage-mapping",
                         ],
                     ),
                 ],
@@ -719,7 +705,7 @@
                     "objc++-executable",
                 ],
                 flag_groups = [
-                    flag_group(flags = ["-fprofile-instr-generate"])
+                    flag_group(flags = ["-fprofile-instr-generate"]),
                 ],
             ),
         ],
@@ -1070,9 +1056,41 @@
         ],
     )
 
-    is_linux = "%{target_libc}" != "macosx"
+    # Note that we also set --coverage for c++-link-nodeps-dynamic-library. The
+    # generated code contains references to gcov symbols, and the dynamic linker
+    # can't resolve them unless the library is linked against gcov.
+    coverage_feature = feature(
+        name = "coverage",
+        provides = ["profile"],
+        flag_sets = [
+            flag_set(
+                actions = [
+                    ACTION_NAMES.preprocess_assemble,
+                    ACTION_NAMES.c_compile,
+                    ACTION_NAMES.cpp_compile,
+                    ACTION_NAMES.cpp_header_parsing,
+                    ACTION_NAMES.cpp_module_compile,
+                ],
+                flag_groups = ([
+                    flag_group(flags = ctx.attr.coverage_compile_flags),
+                ] if ctx.attr.coverage_compile_flags else []),
+            ),
+            flag_set(
+                actions = [
+                    ACTION_NAMES.cpp_link_dynamic_library,
+                    ACTION_NAMES.cpp_link_nodeps_dynamic_library,
+                    ACTION_NAMES.cpp_link_executable,
+                ],
+                flag_groups = ([
+                    flag_group(flags = ctx.attr.coverage_link_flags),
+                ] if ctx.attr.coverage_link_flags else []),
+            ),
+        ],
+    )
 
-    # TODO(#8303): Windows and Mac crosstools should also declare every feature.
+    is_linux = ctx.attr.target_libc != "macosx"
+
+    # TODO(#8303): Mac crosstool should also declare every feature.
     if is_linux:
         features = [
             dependency_file_feature,
@@ -1098,18 +1116,14 @@
             archiver_flags_feature,
             force_pic_flags_feature,
             fission_support_feature,
-            strip_debug_symbols_feature
-        ]
-        if "%{use_coverage_feature}" == "":
-            features.extend([
-                coverage_feature,
-                llvm_coverage_map_format_feature,
-                gcc_coverage_map_format_feature
-            ])
-        features.extend([
+            strip_debug_symbols_feature,
+            coverage_feature,
             supports_pic_feature,
-            %{supports_start_end_lib}
-            %{use_coverage_feature}
+        ] + (
+            [
+                supports_start_end_lib_feature,
+            ] if ctx.attr.supports_start_end_lib else []
+        ) + [
             default_compile_flags_feature,
             default_link_flags_feature,
             libraries_to_link_feature,
@@ -1122,12 +1136,16 @@
             user_compile_flags_feature,
             sysroot_feature,
             unfiltered_compile_flags_feature,
-        ])
+        ]
     else:
         features = [
             supports_pic_feature,
-            %{supports_start_end_lib}
-            %{use_coverage_feature}
+        ] + (
+            [
+                supports_start_end_lib_feature,
+            ] if ctx.attr.supports_start_end_lib else []
+        ) + [
+            coverage_feature,
             default_compile_flags_feature,
             default_link_flags_feature,
             fdo_optimize_feature,
@@ -1143,25 +1161,41 @@
         ctx = ctx,
         features = features,
         action_configs = action_configs,
-        cxx_builtin_include_directories = cxx_builtin_include_directories,
-        toolchain_identifier = "%{toolchain_identifier}",
-        host_system_name = "%{host_system_name}",
-        target_system_name = "%{target_system_name}",
-        target_cpu = "%{target_cpu}",
-        target_libc = "%{target_libc}",
-        compiler = "%{compiler}",
-        abi_version = "%{abi_version}",
-        abi_libc_version = "%{abi_libc_version}",
+        cxx_builtin_include_directories = ctx.attr.cxx_builtin_include_directories,
+        toolchain_identifier = ctx.attr.toolchain_identifier,
+        host_system_name = ctx.attr.host_system_name,
+        target_system_name = ctx.attr.target_system_name,
+        target_cpu = ctx.attr.cpu,
+        target_libc = ctx.attr.target_libc,
+        compiler = ctx.attr.compiler,
+        abi_version = ctx.attr.abi_version,
+        abi_libc_version = ctx.attr.abi_libc_version,
         tool_paths = tool_paths,
-        builtin_sysroot = "%{builtin_sysroot}",
-        cc_target_os = None,
     )
 
 cc_toolchain_config = rule(
     implementation = _impl,
     attrs = {
-        "cpu" : attr.string(mandatory = True),
-        "compiler": attr.string(),
+        "cpu": attr.string(mandatory = True),
+        "compiler": attr.string(mandatory = True),
+        "toolchain_identifier": attr.string(mandatory = True),
+        "host_system_name": attr.string(mandatory = True),
+        "target_system_name": attr.string(mandatory = True),
+        "target_libc": attr.string(mandatory = True),
+        "abi_version": attr.string(mandatory = True),
+        "abi_libc_version": attr.string(mandatory = True),
+        "cxx_builtin_include_directories": attr.string_list(),
+        "tool_paths": attr.string_dict(),
+        "compile_flags": attr.string_list(),
+        "dbg_compile_flags": attr.string_list(),
+        "opt_compile_flags": attr.string_list(),
+        "cxx_flags": attr.string_list(),
+        "link_flags": attr.string_list(),
+        "opt_link_flags": attr.string_list(),
+        "unfiltered_compile_flags": attr.string_list(),
+        "coverage_compile_flags": attr.string_list(),
+        "coverage_link_flags": attr.string_list(),
+        "supports_start_end_lib": attr.bool(),
     },
     provides = [CcToolchainConfigInfo],
 )