Refactor cc_binary so that it is instansiated by a macro.

Needed to avoid propagating aspects when not necessary. Aspects should only
propagated in case dynamic_deps attribute of cc_binary is specified.

PiperOrigin-RevId: 426339989
diff --git a/src/main/starlark/builtins_bzl/common/cc/cc_binary.bzl b/src/main/starlark/builtins_bzl/common/cc/cc_binary.bzl
index f84c072..6f1f22f 100644
--- a/src/main/starlark/builtins_bzl/common/cc/cc_binary.bzl
+++ b/src/main/starlark/builtins_bzl/common/cc/cc_binary.bzl
@@ -1033,100 +1033,23 @@
 ALLOWED_SRC_FILES.extend(cc_helper.extensions.OBJECT_FILE)
 ALLOWED_SRC_FILES.extend(cc_helper.extensions.PIC_OBJECT_FILE)
 
-# Intended only to be used by cc_test. Do not import.
-cc_binary_attrs = {
-    "srcs": attr.label_list(
-        flags = ["DIRECT_COMPILE_TIME_INPUT"],
-        allow_files = True,
-    ),
-    "win_def_file": attr.label(
-        allow_single_file = [".def"],
-    ),
-    "reexport_deps": attr.label_list(
-        allow_files = True,
-        allow_rules = semantics.ALLOWED_RULES_IN_DEPS,
-    ),
-    "linkopts": attr.string_list(),
-    "copts": attr.string_list(),
-    "defines": attr.string_list(),
-    "local_defines": attr.string_list(),
-    "includes": attr.string_list(),
-    "nocopts": attr.string(),
-    # TODO(b/198254254): Only once inside Google? in progress
-    # TODO(b/198254254): Add default = cc_internal.default_hdrs_check_computed_default().
-    "hdrs_check": attr.string(),
-    "linkstatic": attr.bool(
-        default = True,
-    ),
-    "additional_linker_inputs": attr.label_list(
-        allow_files = True,
-        flags = ["ORDER_INDEPENDENT", "DIRECT_COMPILE_TIME_INPUT"],
-    ),
-    "deps": attr.label_list(
-        allow_files = semantics.ALLOWED_FILES_IN_DEPS,
-        allow_rules = semantics.ALLOWED_RULES_IN_DEPS + semantics.ALLOWED_RULES_WITH_WARNINGS_IN_DEPS,
-        flags = ["SKIP_ANALYSIS_TIME_FILETYPE_CHECK"],
-        providers = [CcInfo],
-    ),
-    "dynamic_deps": attr.label_list(
-        allow_files = False,
-        providers = [CcSharedLibraryInfo],
-    ),
-    "malloc": attr.label(
-        default = Label("@//tools/cpp:malloc"),
-        allow_files = False,
-        allow_rules = ["cc_library"],
-        # TODO(b/198254254): Add aspects. in progress
-        aspects = [],
-    ),
-    "_default_malloc": attr.label(
-        # TODO(b/198254254): Add default value. in progress
-        default = configuration_field(fragment = "cpp", name = "custom_malloc"),
-    ),
-    "stamp": attr.int(
-        default = -1,
-    ),
-    "linkshared": attr.bool(
-        default = False,
-    ),
-    "data": attr.label_list(
-        allow_files = True,
-        flags = ["SKIP_CONSTRAINTS_OVERRIDE"],
-    ),
-    "env": attr.string_dict(),
-    "distribs": attr.string_list(),
-    "_is_test": attr.bool(default = False),
-    "_grep_includes": attr.label(
-        allow_files = True,
+def make_cc_binary(cc_binary_attrs, **kwargs):
+    return rule(
+        implementation = cc_binary_impl,
+        attrs = cc_binary_attrs,
+        outputs = {
+            # TODO(b/198254254): Handle case for windows.
+            "stripped_binary": "%{name}.stripped",
+            "dwp_file": "%{name}.dwp",
+        },
+        fragments = ["google_cpp", "cpp"],
+        exec_groups = {
+            "cpp_link": exec_group(copy_from_rule = True),
+        },
+        toolchains = [
+            "@" + semantics.get_repo() + "//tools/cpp:toolchain_type",
+        ],
+        incompatible_use_toolchain_transition = True,
         executable = True,
-        cfg = "exec",
-        default = Label("@//tools/cpp:grep-includes"),
-    ),
-    "_stl": attr.label(default = "@//third_party/stl"),
-    "_cc_toolchain": attr.label(default = "@//tools/cpp:current_cc_toolchain"),
-    "_cc_toolchain_type": attr.label(default = "@//tools/cpp:toolchain_type"),
-    # TODO(b/198254254): Add default computed value once it is available in the API.
-    "_default_copts": attr.string_list(),
-}
-cc_binary_attrs.update(semantics.get_licenses_attr())
-cc_binary_attrs.update(semantics.get_distribs_attr())
-cc_binary_attrs.update(semantics.get_loose_mode_in_hdrs_check_allowed_attr())
-
-cc_binary = rule(
-    implementation = cc_binary_impl,
-    attrs = cc_binary_attrs,
-    outputs = {
-        # TODO(b/198254254): Handle case for windows.
-        "stripped_binary": "%{name}.stripped",
-        "dwp_file": "%{name}.dwp",
-    },
-    fragments = ["google_cpp", "cpp"],
-    exec_groups = {
-        "cpp_link": exec_group(copy_from_rule = True),
-    },
-    toolchains = [
-        "@//tools/cpp:toolchain_type",
-    ],
-    incompatible_use_toolchain_transition = True,
-    executable = True,
-)
+        **kwargs
+    )
diff --git a/src/main/starlark/builtins_bzl/common/cc/cc_binary_attrs.bzl b/src/main/starlark/builtins_bzl/common/cc/cc_binary_attrs.bzl
new file mode 100644
index 0000000..a9c075f
--- /dev/null
+++ b/src/main/starlark/builtins_bzl/common/cc/cc_binary_attrs.bzl
@@ -0,0 +1,119 @@
+# Copyright 2022 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.
+
+"""Attributes for cc_binary.
+"""
+
+load(":common/cc/semantics.bzl", "semantics")
+load(":common/cc/experimental_cc_shared_library.bzl", "CcSharedLibraryInfo", "graph_structure_aspect")
+
+CcInfo = _builtins.toplevel.CcInfo
+
+cc_binary_attrs_with_aspects = {
+    "srcs": attr.label_list(
+        flags = ["DIRECT_COMPILE_TIME_INPUT"],
+        allow_files = True,
+    ),
+    "win_def_file": attr.label(
+        allow_single_file = [".def"],
+    ),
+    "reexport_deps": attr.label_list(
+        allow_files = True,
+        allow_rules = semantics.ALLOWED_RULES_IN_DEPS,
+    ),
+    "linkopts": attr.string_list(),
+    "copts": attr.string_list(),
+    "defines": attr.string_list(),
+    "local_defines": attr.string_list(),
+    "includes": attr.string_list(),
+    "nocopts": attr.string(),
+    # TODO(b/198254254): Only once inside Google? in progress
+    # TODO(b/198254254): Add default = cc_internal.default_hdrs_check_computed_default().
+    "hdrs_check": attr.string(),
+    "linkstatic": attr.bool(
+        default = True,
+    ),
+    "additional_linker_inputs": attr.label_list(
+        allow_files = True,
+        flags = ["ORDER_INDEPENDENT", "DIRECT_COMPILE_TIME_INPUT"],
+    ),
+    "deps": attr.label_list(
+        allow_files = semantics.ALLOWED_FILES_IN_DEPS,
+        allow_rules = semantics.ALLOWED_RULES_IN_DEPS + semantics.ALLOWED_RULES_WITH_WARNINGS_IN_DEPS,
+        flags = ["SKIP_ANALYSIS_TIME_FILETYPE_CHECK"],
+        providers = [CcInfo],
+        aspects = [graph_structure_aspect],
+    ),
+    "dynamic_deps": attr.label_list(
+        allow_files = False,
+        providers = [CcSharedLibraryInfo],
+    ),
+    "malloc": attr.label(
+        default = Label("@" + semantics.get_repo() + "//tools/cpp:malloc"),
+        allow_files = False,
+        allow_rules = ["cc_library"],
+        aspects = [graph_structure_aspect],
+    ),
+    "_default_malloc": attr.label(
+        default = configuration_field(fragment = "cpp", name = "custom_malloc"),
+        aspects = [graph_structure_aspect],
+    ),
+    "stamp": attr.int(
+        default = -1,
+    ),
+    "linkshared": attr.bool(
+        default = False,
+    ),
+    "data": attr.label_list(
+        allow_files = True,
+        flags = ["SKIP_CONSTRAINTS_OVERRIDE"],
+    ),
+    "env": attr.string_dict(),
+    "distribs": attr.string_list(),
+    "_cc_binary": attr.bool(),
+    "_is_test": attr.bool(default = False),
+    "_grep_includes": attr.label(
+        allow_files = True,
+        executable = True,
+        cfg = "exec",
+        default = Label("@" + semantics.get_repo() + "//tools/cpp:grep-includes"),
+    ),
+    "_stl": semantics.get_stl(),
+    "_cc_toolchain": attr.label(default = "@" + semantics.get_repo() + "//tools/cpp:current_cc_toolchain"),
+    "_cc_toolchain_type": attr.label(default = "@" + semantics.get_repo() + "//tools/cpp:toolchain_type"),
+    # TODO(b/198254254): Add default computed value once it is available in the API.
+    "_default_copts": attr.string_list(),
+    "_def_parser": semantics.get_def_parser(),
+}
+
+cc_binary_attrs_with_aspects.update(semantics.get_licenses_attr())
+cc_binary_attrs_with_aspects.update(semantics.get_distribs_attr())
+cc_binary_attrs_with_aspects.update(semantics.get_loose_mode_in_hdrs_check_allowed_attr())
+
+# Update attributes to contain no aspect implementation.
+cc_binary_attrs_without_aspects = dict(cc_binary_attrs_with_aspects)
+cc_binary_attrs_without_aspects["deps"] = attr.label_list(
+    allow_files = semantics.ALLOWED_FILES_IN_DEPS,
+    allow_rules = semantics.ALLOWED_RULES_IN_DEPS + semantics.ALLOWED_RULES_WITH_WARNINGS_IN_DEPS,
+    flags = ["SKIP_ANALYSIS_TIME_FILETYPE_CHECK"],
+    providers = [CcInfo],
+)
+cc_binary_attrs_without_aspects["malloc"] = attr.label(
+    default = Label("@" + semantics.get_repo() + "//tools/cpp:malloc"),
+    allow_files = False,
+    allow_rules = ["cc_library"],
+)
+cc_binary_attrs_without_aspects["_default_malloc"] = attr.label(
+    default = configuration_field(fragment = "cpp", name = "custom_malloc"),
+)
diff --git a/src/main/starlark/builtins_bzl/common/cc/cc_binary_with_aspects.bzl b/src/main/starlark/builtins_bzl/common/cc/cc_binary_with_aspects.bzl
new file mode 100644
index 0000000..bb172f7
--- /dev/null
+++ b/src/main/starlark/builtins_bzl/common/cc/cc_binary_with_aspects.bzl
@@ -0,0 +1,24 @@
+# Copyright 2022 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.
+
+"""Exports cc_binary variant with aspects.
+
+If dynamic_deps attribute is specified we need to propagate
+aspects.
+"""
+
+load(":common/cc/cc_binary.bzl", "make_cc_binary")
+load(":common/cc/cc_binary_attrs.bzl", "cc_binary_attrs_with_aspects")
+
+cc_binary = make_cc_binary(cc_binary_attrs_with_aspects)
diff --git a/src/main/starlark/builtins_bzl/common/cc/cc_binary_without_aspects.bzl b/src/main/starlark/builtins_bzl/common/cc/cc_binary_without_aspects.bzl
new file mode 100644
index 0000000..5470e32
--- /dev/null
+++ b/src/main/starlark/builtins_bzl/common/cc/cc_binary_without_aspects.bzl
@@ -0,0 +1,24 @@
+# Copyright 2022 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.
+
+"""Exports cc_binary variant without aspects.
+
+If dynamic_deps attribute is not specified we do not propagate
+aspects.
+"""
+
+load(":common/cc/cc_binary.bzl", "make_cc_binary")
+load(":common/cc/cc_binary_attrs.bzl", "cc_binary_attrs_without_aspects")
+
+cc_binary = make_cc_binary(cc_binary_attrs_without_aspects)
diff --git a/src/main/starlark/builtins_bzl/common/cc/cc_binary_wrapper.bzl b/src/main/starlark/builtins_bzl/common/cc/cc_binary_wrapper.bzl
new file mode 100644
index 0000000..15fdfef
--- /dev/null
+++ b/src/main/starlark/builtins_bzl/common/cc/cc_binary_wrapper.bzl
@@ -0,0 +1,29 @@
+# Copyright 2022 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.
+
+"""Macro encapsulating cc_binary rule implementation.
+
+This is to avoid propagating aspect on certain attributes in case
+dynamic_deps attribute is not specified.
+"""
+
+load(":common/cc/cc_binary_with_aspects.bzl", cc_binary_with_aspects = "cc_binary")
+load(":common/cc/cc_binary_without_aspects.bzl", cc_binary_without_aspects = "cc_binary")
+
+def cc_binary(**kwargs):
+    # Propagate an aspect if dynamic_deps attribute is specified.
+    if "dynamic_deps" in kwargs and len(kwargs["dynamic_deps"]) > 0:
+        cc_binary_with_aspects(**kwargs)
+    else:
+        cc_binary_without_aspects(**kwargs)
diff --git a/src/main/starlark/builtins_bzl/common/cc/cc_helper.bzl b/src/main/starlark/builtins_bzl/common/cc/cc_helper.bzl
index 1c9b85e..0e4037c 100644
--- a/src/main/starlark/builtins_bzl/common/cc/cc_helper.bzl
+++ b/src/main/starlark/builtins_bzl/common/cc/cc_helper.bzl
@@ -44,9 +44,10 @@
 
 def _merge_cc_debug_contexts(compilation_outputs, dep_cc_infos):
     debug_context = cc_common.create_debug_context(compilation_outputs)
-    debug_contexts = [debug_context]
+    debug_contexts = []
     for dep_cc_info in dep_cc_infos:
         debug_contexts.append(dep_cc_info.debug_context())
+    debug_contexts.append(debug_context)
 
     return cc_common.merge_debug_context(debug_contexts)
 
diff --git a/src/main/starlark/builtins_bzl/common/cc/cc_test.bzl b/src/main/starlark/builtins_bzl/common/cc/cc_test.bzl
index 778660f..f89305e 100644
--- a/src/main/starlark/builtins_bzl/common/cc/cc_test.bzl
+++ b/src/main/starlark/builtins_bzl/common/cc/cc_test.bzl
@@ -14,11 +14,15 @@
 
 """cc_test Starlark implementation."""
 
-load(":common/cc/cc_binary.bzl", "cc_binary_attrs", "cc_binary_impl")
+load(":common/cc/cc_binary.bzl", "cc_binary_impl")
+
+# TODO(b/198254254): We need to do a wrapper around cc_test like for
+# cc_binary, but for now it should work.
+load(":common/cc/cc_binary_attrs.bzl", "cc_binary_attrs_with_aspects")
 
 testing = _builtins.toplevel.testing
 
-_cc_test_attrs = dict(cc_binary_attrs)
+_cc_test_attrs = dict(cc_binary_attrs_with_aspects)
 
 # Update other cc_test defaults:
 _cc_test_attrs.update(
diff --git a/src/main/starlark/builtins_bzl/common/cc/experimental_cc_shared_library.bzl b/src/main/starlark/builtins_bzl/common/cc/experimental_cc_shared_library.bzl
index 75a3f7f..f34ec20 100644
--- a/src/main/starlark/builtins_bzl/common/cc/experimental_cc_shared_library.bzl
+++ b/src/main/starlark/builtins_bzl/common/cc/experimental_cc_shared_library.bzl
@@ -103,7 +103,8 @@
     dynamic_deps = []
     transitive_dynamic_deps = []
     for dep in ctx.attr.dynamic_deps:
-        if dep[CcSharedLibraryInfo].preloaded_deps != None:
+        # This error is not relevant for cc_binary.
+        if not hasattr(ctx.attr, "_cc_binary") and 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)))
@@ -519,7 +520,8 @@
 def _graph_structure_aspect_impl(target, ctx):
     children = []
 
-    if hasattr(ctx.rule.attr, "deps"):
+    # For now ignore cases when deps is of type label instead of label_list.
+    if hasattr(ctx.rule.attr, "deps") and type(ctx.rule.attr.deps) != "Target":
         for dep in ctx.rule.attr.deps:
             if GraphNodeInfo in dep:
                 children.append(dep[GraphNodeInfo])
diff --git a/src/main/starlark/builtins_bzl/common/exports.bzl b/src/main/starlark/builtins_bzl/common/exports.bzl
index d739ed1..53714ca 100644
--- a/src/main/starlark/builtins_bzl/common/exports.bzl
+++ b/src/main/starlark/builtins_bzl/common/exports.bzl
@@ -15,7 +15,7 @@
 """Exported builtins symbols that are not specific to OSS Bazel."""
 
 load("@_builtins//:common/cc/cc_import.bzl", "cc_import")
-load("@_builtins//:common/cc/cc_binary.bzl", "cc_binary")
+load("@_builtins//:common/cc/cc_binary_wrapper.bzl", "cc_binary")
 load("@_builtins//:common/cc/cc_test.bzl", "cc_test")
 load("@_builtins//:common/cc/experimental_cc_shared_library.bzl", "cc_shared_library", "cc_shared_library_permissions")
 load("@_builtins//:common/objc/objc_import.bzl", "objc_import")