Handle crt for binaries.

Test: build/bazel/ci/bp2build.sh
Test: build/bazel/ci/mixed_libc.sh
Change-Id: I28152f65abe4a4417d65b18f3ca011aec5449d43
diff --git a/cc_toolchain_config.bzl b/cc_toolchain_config.bzl
index 3d9b9ea..5f0b899 100644
--- a/cc_toolchain_config.bzl
+++ b/cc_toolchain_config.bzl
@@ -7,9 +7,9 @@
 load(
     ":cc_toolchain_constants.bzl",
     _actions = "actions",
+    _bionic_crt = "bionic_crt",
     _flags = "flags",
     _generated_constants = "generated_constants",
-    _crt = "crt",
 )
 load(":cc_toolchain_features.bzl", "get_features")
 
@@ -198,6 +198,14 @@
     # b/186035856: Do not add anything to this list.
     builtin_include_dirs.extend(_generated_constants.CommonGlobalIncludes)
 
+    crt_files = struct(
+        shared_library_crtbegin = ctx.file.shared_library_crtbegin,
+        shared_library_crtend = ctx.file.shared_library_crtend,
+        shared_binary_crtbegin = ctx.file.shared_binary_crtbegin,
+        static_binary_crtbegin = ctx.file.static_binary_crtbegin,
+        binary_crtend = ctx.file.binary_crtend,
+    )
+
     features = get_features(
         ctx.attr.target_os,
         ctx.attr.target_arch,
@@ -205,8 +213,7 @@
         ctx.attr.linker_flags,
         builtin_include_dirs,
         ctx.file.libclang_rt_builtin,
-        ctx.file.shared_library_crtbegin,
-        ctx.file.shared_library_crtend,
+        crt_files,
     )
 
     return cc_common.create_cc_toolchain_config_info(
@@ -241,11 +248,9 @@
         # cc_binary against the Bionic runtime
         "shared_library_crtbegin": attr.label(allow_single_file = True, cfg = "target"),
         "shared_library_crtend": attr.label(allow_single_file = True, cfg = "target"),
-        # TODO(b/197920036): handle cc_binary
-        # "shared_binary_crtbegin": attr.label(allow_single_file = True),
-        # "shared_binary_crtend": attr.label(allow_single_file = True),
-        # "static_binary_crtbegin": attr.label(allow_single_file = True),
-        # "static_binary_crtend": attr.label(allow_single_file = True),
+        "shared_binary_crtbegin": attr.label(allow_single_file = True, cfg = "target"),
+        "static_binary_crtbegin": attr.label(allow_single_file = True, cfg = "target"),
+        "binary_crtend": attr.label(allow_single_file = True, cfg = "target"),
     },
     provides = [CcToolchainConfigInfo],
 )
@@ -293,8 +298,11 @@
     _cc_toolchain_config(
         name = "%s_config" % name,
         toolchain_identifier = toolchain_identifier,
-        shared_library_crtbegin = _crt.shared_library_crtbegin,
-        shared_library_crtend = _crt.shared_library_crtend,
+        shared_library_crtbegin = _bionic_crt.shared_library_crtbegin,
+        shared_library_crtend = _bionic_crt.shared_library_crtend,
+        shared_binary_crtbegin = _bionic_crt.shared_binary_crtbegin,
+        static_binary_crtbegin = _bionic_crt.static_binary_crtbegin,
+        binary_crtend = _bionic_crt.binary_crtend,
         **common_toolchain_config
     )
 
@@ -371,8 +379,11 @@
     native.filegroup(
         name = "%s_crt_libs" % name,
         srcs = [
-            _crt.shared_library_crtbegin,
-            _crt.shared_library_crtend,
+            _bionic_crt.shared_library_crtbegin,
+            _bionic_crt.shared_library_crtend,
+            _bionic_crt.shared_binary_crtbegin,
+            _bionic_crt.static_binary_crtbegin,
+            _bionic_crt.binary_crtend,
         ],
     )
 
diff --git a/cc_toolchain_constants.bzl b/cc_toolchain_constants.bzl
index 1133133..eff5727 100644
--- a/cc_toolchain_constants.bzl
+++ b/cc_toolchain_constants.bzl
@@ -83,15 +83,14 @@
     strip = ACTION_NAMES.strip,
 )
 
-crt = struct(
+bionic_crt = struct(
     # crtbegin and crtend libraries for compiling cc_library_shared and
     # cc_binary against the Bionic runtime
     shared_library_crtbegin = "//bionic/libc:crtbegin_so",
     shared_library_crtend = "//bionic/libc:crtend_so",
     shared_binary_crtbegin = "//bionic/libc:crtbegin_dynamic",
-    shared_binary_crtend = "//bionic/libc:crtend_android",
     static_binary_crtbegin = "//bionic/libc:crtbegin_static",
-    static_binary_crtend = "//bionic/libc:crtend_android",
+    binary_crtend = "//bionic/libc:crtend_android",
 )
 
 default_cpp_std_version = "gnu++17"
diff --git a/cc_toolchain_features.bzl b/cc_toolchain_features.bzl
index 9b4af0b..23fd5b2 100644
--- a/cc_toolchain_features.bzl
+++ b/cc_toolchain_features.bzl
@@ -1008,30 +1008,82 @@
 
     return features
 
-def _link_crtbegin(shared_library_crtbegin = None):
-    if shared_library_crtbegin == None:
+def _link_crtbegin(crt_files):
+    # in practice, either all of these are supported for a toolchain or none of them do
+    if crt_files.shared_library_crtbegin == None or crt_files.shared_binary_crtbegin == None or crt_files.static_binary_crtbegin == None:
         return []
 
     features = [
         feature(
             # User facing feature
             name = "link_crt",
-            implies = [
-                "link_crtbegin",
-                "link_crtend"
-            ],
             enabled = True,
+            implies = ["link_crtbegin", "link_crtend"],
         ),
-        # TODO(b/197920036): add support for linking shared/static executables
         feature(
             name = "link_crtbegin",
-            enabled = False,
+            enabled = True,
+        ),
+        feature(
+            name = "link_crtbegin_so",
+            enabled = True,
             flag_sets = [
                 flag_set(
                     actions = [_actions.cpp_link_dynamic_library],
                     flag_groups = [
                         flag_group(
-                            flags = [shared_library_crtbegin.path],
+                            flags = [crt_files.shared_library_crtbegin.path],
+                        ),
+                    ],
+                    with_features = [
+                        with_feature_set(
+                            features = ["link_crt", "link_crtbegin"],
+                        ),
+                    ],
+                ),
+            ],
+        ),
+        feature(
+            name = "link_crtbegin_dynamic",
+            enabled = True,
+            flag_sets = [
+                flag_set(
+                    actions = [_actions.cpp_link_executable],
+                    flag_groups = [
+                        flag_group(
+                            flags = [crt_files.shared_binary_crtbegin.path],
+                        ),
+                    ],
+                    with_features = [
+                        with_feature_set(
+                            features = [
+                                "dynamic_executable",
+                                "link_crt",
+                                "link_crtbegin",
+                            ],
+                        ),
+                    ],
+                ),
+            ],
+        ),
+        feature(
+            name = "link_crtbegin_static",
+            enabled = True,
+            flag_sets = [
+                flag_set(
+                    actions = [_actions.cpp_link_executable],
+                    flag_groups = [
+                        flag_group(
+                            flags = [crt_files.static_binary_crtbegin.path],
+                        ),
+                    ],
+                    with_features = [
+                        with_feature_set(
+                            features = [
+                                "link_crt",
+                                "link_crtbegin",
+                                "static_executable",
+                            ],
                         ),
                     ],
                 ),
@@ -1041,25 +1093,55 @@
 
     return features
 
-def _link_crtend(shared_library_crtend):
-    if shared_library_crtend == None:
+def _link_crtend(crt_files):
+    # in practice, either all of these are supported for a toolchain or none of them do
+    if crt_files.shared_library_crtend == None or crt_files.binary_crtend == None:
         return None
 
-    # TODO(b/197920036): add support for linking shared/static executables
-    return feature(
-        name = "link_crtend",
-        enabled = False,
-        flag_sets = [
-            flag_set(
-                actions = [_actions.cpp_link_dynamic_library],
-                flag_groups = [
-                    flag_group(
-                        flags = [shared_library_crtend.path],
-                    ),
-                ],
-            ),
-        ],
-    )
+    return [
+        feature(
+            name = "link_crtend",
+            enabled = True,
+        ),
+        feature(
+            name = "link_crtend_so",
+            enabled = True,
+            flag_sets = [
+                flag_set(
+                    actions = [_actions.cpp_link_dynamic_library],
+                    flag_groups = [
+                        flag_group(
+                            flags = [crt_files.shared_library_crtend.path],
+                        ),
+                    ],
+                    with_features = [
+                        with_feature_set(
+                            features = ["link_crt", "link_crtend"],
+                        ),
+                    ],
+                ),
+            ],
+        ),
+        feature(
+            name = "link_crtend_binary",
+            enabled = True,
+            flag_sets = [
+                flag_set(
+                    actions = [_actions.cpp_link_executable],
+                    flag_groups = [
+                        flag_group(
+                            flags = [crt_files.binary_crtend.path],
+                        ),
+                    ],
+                    with_features = [
+                        with_feature_set(
+                            features = ["link_crt", "link_crtend"],
+                        ),
+                    ],
+                ),
+            ],
+        ),
+    ]
 
 # Create the full list of features.
 def get_features(
@@ -1069,8 +1151,7 @@
         linker_only_flags,
         builtin_include_dirs,
         libclang_rt_builtin,
-        shared_library_crtbegin,
-        shared_library_crtend):
+        crt_files):
     os_is_device = target_os == "android"
     arch_is_64_bit = target_arch.endswith("64")
 
@@ -1080,7 +1161,7 @@
         feature(name = "no_legacy_features"),
 
         # This must always come first, after no_legacy_features.
-        _link_crtbegin(shared_library_crtbegin),
+        _link_crtbegin(crt_files),
 
         # Explicitly depend on a subset of legacy configs:
         _get_legacy_features_begin(),
@@ -1111,6 +1192,6 @@
         _get_legacy_features_end(),
 
         # This must always come last.
-        _link_crtend(shared_library_crtend),
+        _link_crtend(crt_files),
     ]
     return _flatten([f for f in features if f != None])