Add a static C++ toolchain configuration for freebsd

The toolchain configuration rule freebsd currently is relying on will be removed as part of #8546

Tested locally that the resulting cc_toolchain_config rules are the same with @rules_cc//tools/migration/cc_toolchain_config_comparator.bzl

RELNOTES: None.
PiperOrigin-RevId: 262555744
diff --git a/tools/cpp/BUILD.static.freebsd b/tools/cpp/BUILD.static.freebsd
index a3a69d3..ded0f537 100644
--- a/tools/cpp/BUILD.static.freebsd
+++ b/tools/cpp/BUILD.static.freebsd
@@ -16,7 +16,7 @@
 
 package(default_visibility = ["//visibility:public"])
 
-load("@bazel_tools//tools/cpp:cc_toolchain_config.bzl", "cc_toolchain_config")
+load(":cc_toolchain_config.bzl", "cc_toolchain_config")
 load("@rules_cc//cc:defs.bzl", "cc_toolchain_suite", "cc_toolchain", "cc_library")
 
 cc_library(
@@ -57,7 +57,6 @@
 cc_toolchain_config(
     name = "local_freebsd",
     cpu = "freebsd",
-    compiler = "compiler",
 )
 
 toolchain(
@@ -92,7 +91,6 @@
 cc_toolchain_config(
     name = "stub_armeabi-v7a",
     cpu = "armeabi-v7a",
-    compiler = "compiler",
 )
 
 toolchain(
diff --git a/tools/cpp/cc_configure.bzl b/tools/cpp/cc_configure.bzl
index 36b3365..de834d6 100644
--- a/tools/cpp/cc_configure.bzl
+++ b/tools/cpp/cc_configure.bzl
@@ -92,7 +92,6 @@
        overriden_tools: dict of tool paths to use instead of autoconfigured tools
     """
     paths = resolve_labels(repository_ctx, [
-        "@bazel_tools//tools/cpp:BUILD.static.freebsd",
         "@bazel_tools//tools/cpp:cc_toolchain_config.bzl",
     ])
 
@@ -102,11 +101,16 @@
         repository_ctx.symlink(paths["@bazel_tools//tools/cpp:cc_toolchain_config.bzl"], "cc_toolchain_config.bzl")
         repository_ctx.symlink(Label("@bazel_tools//tools/cpp:BUILD.empty"), "BUILD")
     elif cpu_value == "freebsd":
-        # This is defaulting to the static crosstool, we should eventually
+        paths = resolve_labels(repository_ctx, [
+            "@bazel_tools//tools/cpp:BUILD.static.freebsd",
+            "@bazel_tools//tools/cpp:freebsd_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["@bazel_tools//tools/cpp:cc_toolchain_config.bzl"], "cc_toolchain_config.bzl")
+        repository_ctx.symlink(paths["@bazel_tools//tools/cpp:freebsd_cc_toolchain_config.bzl"], "cc_toolchain_config.bzl")
         repository_ctx.symlink(paths["@bazel_tools//tools/cpp:BUILD.static.freebsd"], "BUILD")
     elif cpu_value == "x64_windows":
         # TODO(ibiryukov): overriden_tools are only supported in configure_unix_toolchain.
diff --git a/tools/cpp/freebsd_cc_toolchain_config.bzl b/tools/cpp/freebsd_cc_toolchain_config.bzl
new file mode 100644
index 0000000..d8818d4
--- /dev/null
+++ b/tools/cpp/freebsd_cc_toolchain_config.bzl
@@ -0,0 +1,307 @@
+# Copyright 2019 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 Starlark cc_toolchain configuration rule for freebsd."""
+
+load(
+    "@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl",
+    "action_config",
+    "feature",
+    "flag_group",
+    "flag_set",
+    "tool",
+    "tool_path",
+    "with_feature_set",
+)
+load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES")
+
+all_compile_actions = [
+    ACTION_NAMES.c_compile,
+    ACTION_NAMES.cpp_compile,
+    ACTION_NAMES.linkstamp_compile,
+    ACTION_NAMES.assemble,
+    ACTION_NAMES.preprocess_assemble,
+    ACTION_NAMES.cpp_header_parsing,
+    ACTION_NAMES.cpp_module_compile,
+    ACTION_NAMES.cpp_module_codegen,
+    ACTION_NAMES.clif_match,
+    ACTION_NAMES.lto_backend,
+]
+
+all_cpp_compile_actions = [
+    ACTION_NAMES.cpp_compile,
+    ACTION_NAMES.linkstamp_compile,
+    ACTION_NAMES.cpp_header_parsing,
+    ACTION_NAMES.cpp_module_compile,
+    ACTION_NAMES.cpp_module_codegen,
+    ACTION_NAMES.clif_match,
+]
+
+all_link_actions = [
+    ACTION_NAMES.cpp_link_executable,
+    ACTION_NAMES.cpp_link_dynamic_library,
+    ACTION_NAMES.cpp_link_nodeps_dynamic_library,
+]
+
+def _impl(ctx):
+    cpu = ctx.attr.cpu
+    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"
+
+    objcopy_embed_data_action = action_config(
+        action_name = "objcopy_embed_data",
+        enabled = True,
+        tools = [tool(path = "/usr/bin/objcopy")],
+    )
+
+    action_configs = [objcopy_embed_data_action] if cpu == "freebsd" else []
+
+    default_link_flags_feature = feature(
+        name = "default_link_flags",
+        enabled = True,
+        flag_sets = [
+            flag_set(
+                actions = all_link_actions,
+                flag_groups = [
+                    flag_group(
+                        flags = [
+                            "-lstdc++",
+                            "-Wl,-z,relro,-z,now",
+                            "-no-canonical-prefixes",
+                        ],
+                    ),
+                ],
+            ),
+            flag_set(
+                actions = all_link_actions,
+                flag_groups = [flag_group(flags = ["-Wl,--gc-sections"])],
+                with_features = [with_feature_set(features = ["opt"])],
+            ),
+        ],
+    )
+
+    unfiltered_compile_flags_feature = feature(
+        name = "unfiltered_compile_flags",
+        enabled = True,
+        flag_sets = [
+            flag_set(
+                actions = all_compile_actions,
+                flag_groups = [
+                    flag_group(
+                        flags = [
+                            "-no-canonical-prefixes",
+                            "-Wno-builtin-macro-redefined",
+                            "-D__DATE__=\"redacted\"",
+                            "-D__TIMESTAMP__=\"redacted\"",
+                            "-D__TIME__=\"redacted\"",
+                        ],
+                    ),
+                ],
+            ),
+        ],
+    )
+
+    supports_pic_feature = feature(name = "supports_pic", enabled = True)
+
+    default_compile_flags_feature = feature(
+        name = "default_compile_flags",
+        enabled = True,
+        flag_sets = [
+            flag_set(
+                actions = all_compile_actions,
+                flag_groups = [
+                    flag_group(
+                        flags = [
+                            "-U_FORTIFY_SOURCE",
+                            "-D_FORTIFY_SOURCE=1",
+                            "-fstack-protector",
+                            "-Wall",
+                            "-fno-omit-frame-pointer",
+                        ],
+                    ),
+                ],
+            ),
+            flag_set(
+                actions = all_compile_actions,
+                flag_groups = [flag_group(flags = ["-g"])],
+                with_features = [with_feature_set(features = ["dbg"])],
+            ),
+            flag_set(
+                actions = all_compile_actions,
+                flag_groups = [
+                    flag_group(
+                        flags = [
+                            "-g0",
+                            "-O2",
+                            "-DNDEBUG",
+                            "-ffunction-sections",
+                            "-fdata-sections",
+                        ],
+                    ),
+                ],
+                with_features = [with_feature_set(features = ["opt"])],
+            ),
+            flag_set(
+                actions = all_cpp_compile_actions + [ACTION_NAMES.lto_backend],
+                flag_groups = [flag_group(flags = ["-std=c++0x"])],
+            ),
+        ],
+    )
+
+    opt_feature = feature(name = "opt")
+
+    supports_dynamic_linker_feature = feature(name = "supports_dynamic_linker", enabled = True)
+
+    objcopy_embed_flags_feature = feature(
+        name = "objcopy_embed_flags",
+        enabled = True,
+        flag_sets = [
+            flag_set(
+                actions = ["objcopy_embed_data"],
+                flag_groups = [flag_group(flags = ["-I", "binary"])],
+            ),
+        ],
+    )
+
+    dbg_feature = feature(name = "dbg")
+
+    user_compile_flags_feature = feature(
+        name = "user_compile_flags",
+        enabled = True,
+        flag_sets = [
+            flag_set(
+                actions = all_compile_actions,
+                flag_groups = [
+                    flag_group(
+                        flags = ["%{user_compile_flags}"],
+                        iterate_over = "user_compile_flags",
+                        expand_if_available = "user_compile_flags",
+                    ),
+                ],
+            ),
+        ],
+    )
+
+    sysroot_feature = feature(
+        name = "sysroot",
+        enabled = True,
+        flag_sets = [
+            flag_set(
+                actions = [
+                    ACTION_NAMES.c_compile,
+                    ACTION_NAMES.cpp_compile,
+                    ACTION_NAMES.linkstamp_compile,
+                    ACTION_NAMES.preprocess_assemble,
+                    ACTION_NAMES.cpp_header_parsing,
+                    ACTION_NAMES.cpp_module_compile,
+                    ACTION_NAMES.cpp_module_codegen,
+                    ACTION_NAMES.clif_match,
+                    ACTION_NAMES.lto_backend,
+                ] + all_link_actions,
+                flag_groups = [
+                    flag_group(
+                        flags = ["--sysroot=%{sysroot}"],
+                        expand_if_available = "sysroot",
+                    ),
+                ],
+            ),
+        ],
+    )
+
+    if cpu == "freebsd":
+        features = [
+            default_compile_flags_feature,
+            default_link_flags_feature,
+            supports_dynamic_linker_feature,
+            supports_pic_feature,
+            objcopy_embed_flags_feature,
+            opt_feature,
+            dbg_feature,
+            user_compile_flags_feature,
+            sysroot_feature,
+            unfiltered_compile_flags_feature,
+        ]
+    else:
+        features = [supports_dynamic_linker_feature, supports_pic_feature]
+
+    if (cpu == "freebsd"):
+        cxx_builtin_include_directories = ["/usr/lib/clang", "/usr/local/include", "/usr/include"]
+    else:
+        cxx_builtin_include_directories = []
+
+    if cpu == "freebsd":
+        tool_paths = [
+            tool_path(name = "ar", path = "/usr/bin/ar"),
+            tool_path(name = "compat-ld", path = "/usr/bin/ld"),
+            tool_path(name = "cpp", path = "/usr/bin/cpp"),
+            tool_path(name = "dwp", path = "/usr/bin/dwp"),
+            tool_path(name = "gcc", path = "/usr/bin/clang"),
+            tool_path(name = "gcov", path = "/usr/bin/gcov"),
+            tool_path(name = "ld", path = "/usr/bin/ld"),
+            tool_path(name = "nm", path = "/usr/bin/nm"),
+            tool_path(name = "objcopy", path = "/usr/bin/objcopy"),
+            tool_path(name = "objdump", path = "/usr/bin/objdump"),
+            tool_path(name = "strip", path = "/usr/bin/strip"),
+        ]
+    else:
+        tool_paths = [
+            tool_path(name = "ar", path = "/bin/false"),
+            tool_path(name = "compat-ld", path = "/bin/false"),
+            tool_path(name = "cpp", path = "/bin/false"),
+            tool_path(name = "dwp", path = "/bin/false"),
+            tool_path(name = "gcc", path = "/bin/false"),
+            tool_path(name = "gcov", path = "/bin/false"),
+            tool_path(name = "ld", path = "/bin/false"),
+            tool_path(name = "nm", path = "/bin/false"),
+            tool_path(name = "objcopy", path = "/bin/false"),
+            tool_path(name = "objdump", path = "/bin/false"),
+            tool_path(name = "strip", path = "/bin/false"),
+        ]
+
+    out = ctx.actions.declare_file(ctx.label.name)
+    ctx.actions.write(out, "Fake executable")
+    return [
+        cc_common.create_cc_toolchain_config_info(
+            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 = cpu,
+            target_libc = target_libc,
+            compiler = compiler,
+            abi_version = abi_version,
+            abi_libc_version = abi_libc_version,
+            tool_paths = tool_paths,
+        ),
+        DefaultInfo(
+            executable = out,
+        ),
+    ]
+
+cc_toolchain_config = rule(
+    implementation = _impl,
+    attrs = {
+        "cpu": attr.string(mandatory = True),
+    },
+    provides = [CcToolchainConfigInfo],
+    executable = True,
+)