C++: Add preloaded_deps support for cc_binary

RELNOTES:none
PiperOrigin-RevId: 283748069
Change-Id: Ife31d30ddca38e0f34fa2004a1e75de5ccd696fe
diff --git a/examples/experimental_cc_shared_library.bzl b/examples/experimental_cc_shared_library.bzl
index 4694653..27c7856 100644
--- a/examples/experimental_cc_shared_library.bzl
+++ b/examples/experimental_cc_shared_library.bzl
@@ -20,11 +20,17 @@
     fields = {
         "dynamic_deps": "All shared libraries depended on transitively",
         "linker_input": "the resulting linker input artifact for the shared library",
+        "preloaded_deps": "cc_libraries needed by this cc_shared_library that should" +
+                          " be linked the binary. If this is set, this cc_shared_library has to " +
+                          " be a direct dependency of the cc_binary",
         "exports": "cc_libraries that are linked statically and exported",
     },
 )
 
-def _separate_static_and_dynamic_link_libraries(direct_children, can_be_linked_dynamically):
+def _separate_static_and_dynamic_link_libraries(
+        direct_children,
+        can_be_linked_dynamically,
+        preloaded_deps_direct_labels):
     node = None
     all_children = list(direct_children)
     link_statically_labels = {}
@@ -38,7 +44,7 @@
 
         if node.label in can_be_linked_dynamically:
             link_dynamically_labels[node.label] = None
-        else:
+        elif node.label not in preloaded_deps_direct_labels:
             link_statically_labels[node.label] = node.linked_statically_by
             all_children.extend(node.children)
     return (link_statically_labels, link_dynamically_labels)
@@ -56,6 +62,10 @@
     dynamic_deps = []
     transitive_dynamic_deps = []
     for dep in ctx.attr.dynamic_deps:
+        if dep[CcSharedLibraryInfo].preloaded_deps != None:
+            fail("{} can only be a direct dependency of a " +
+                 " cc_binary because it has " +
+                 "preloaded_deps".format(str(dep.label)))
         dynamic_dep_entry = (
             dep[CcSharedLibraryInfo].exports,
             dep[CcSharedLibraryInfo].linker_input,
@@ -102,7 +112,12 @@
         additional_inputs = depset(direct = linker_input.additional_inputs),
     )
 
-def _filter_inputs(ctx, feature_configuration, cc_toolchain, transitive_exports):
+def _filter_inputs(
+        ctx,
+        feature_configuration,
+        cc_toolchain,
+        transitive_exports,
+        preloaded_deps_direct_labels):
     static_linker_inputs = []
     dynamic_linker_inputs = []
 
@@ -123,6 +138,7 @@
     (link_statically_labels, link_dynamically_labels) = _separate_static_and_dynamic_link_libraries(
         graph_structure_aspect_nodes,
         can_be_linked_dynamically,
+        preloaded_deps_direct_labels,
     )
 
     already_linked_dynamically = {}
@@ -186,11 +202,23 @@
         if str(export.label) in exports_map:
             fail("Trying to export a library already exported by a different shared library: " +
                  str(export.label))
+
+    preloaded_deps_direct_labels = {}
+    preloaded_dep_merged_cc_info = None
+    if len(ctx.attr.preloaded_deps) != 0:
+        preloaded_deps_cc_infos = []
+        for preloaded_dep in ctx.attr.preloaded_deps:
+            preloaded_deps_direct_labels[str(preloaded_dep.label)] = True
+            preloaded_deps_cc_infos.append(preloaded_dep[CcInfo])
+
+        preloaded_dep_merged_cc_info = cc_common.merge_cc_infos(cc_infos = preloaded_deps_cc_infos)
+
     (static_linker_inputs, dynamic_linker_inputs) = _filter_inputs(
         ctx,
         feature_configuration,
         cc_toolchain,
         exports_map,
+        preloaded_deps_direct_labels,
     )
 
     linking_context = _create_linker_context(ctx, static_linker_inputs, dynamic_linker_inputs)
@@ -237,6 +265,7 @@
                 owner = ctx.label,
                 libraries = depset([linking_outputs.library_to_link]),
             ),
+            preloaded_deps = preloaded_dep_merged_cc_info,
         ),
     ]
 
@@ -267,8 +296,9 @@
     implementation = _cc_shared_library_impl,
     attrs = {
         "dynamic_deps": attr.label_list(providers = [CcSharedLibraryInfo]),
+        "preloaded_deps": attr.label_list(providers = [CcInfo]),
         "visibility_file": attr.label(allow_single_file = True),
-        "exports": attr.label_list(aspects = [graph_structure_aspect]),
+        "exports": attr.label_list(providers = [CcInfo], aspects = [graph_structure_aspect]),
         "_cc_toolchain": attr.label(default = "@bazel_tools//tools/cpp:current_cc_toolchain"),
     },
     toolchains = ["@rules_cc//cc:toolchain_type"],  # copybara-use-repo-external-label