Implement tests in Bazel's CppLinkstampCompileHelperTest in Starlark in rules_cc.

The tests only check observable behaviour in rule outputs so we can treat them
them as tests of cc_binary outputs under specific conditions.

PiperOrigin-RevId: 964048225
Change-Id: I74802bb4966b4036d65106f835de0b09f7cb76ac
diff --git a/tests/cc/common/BUILD b/tests/cc/common/BUILD
index 9d60013..a3e3d1b 100644
--- a/tests/cc/common/BUILD
+++ b/tests/cc/common/BUILD
@@ -8,6 +8,7 @@
 load(":cc_import_configured_target_tests.bzl", "cc_import_configured_target_tests")
 load(":cc_library_configured_target_tests.bzl", "cc_library_configured_target_tests")
 load(":cc_link_action_test.bzl", "cc_link_action_tests")
+load(":cc_linkstamp_compile_test.bzl", "cc_linkstamp_compile_tests")
 load(":cc_objc_library_configured_target_tests.bzl", "cc_objc_library_configured_target_tests")
 load(":cc_output_groups_test.bzl", "cc_output_groups_tests")
 load(":compile_build_variables_tests.bzl", "compile_build_variables_tests")
@@ -46,3 +47,5 @@
 cc_binary_split_functions_tests(name = "cc_binary_split_functions_tests")
 
 cc_link_action_tests(name = "cc_link_action_tests")
+
+cc_linkstamp_compile_tests(name = "cc_linkstamp_compile_tests")
diff --git a/tests/cc/common/cc_linkstamp_compile_test.bzl b/tests/cc/common/cc_linkstamp_compile_test.bzl
new file mode 100644
index 0000000..108ee1c
--- /dev/null
+++ b/tests/cc/common/cc_linkstamp_compile_test.bzl
@@ -0,0 +1,317 @@
+"""Tests the compile actions for linkstamps."""
+
+load("@bazel_features//:features.bzl", "bazel_features")
+load("@bazel_skylib//lib:paths.bzl", "paths")
+load("@rules_testing//lib:analysis_test.bzl", "test_suite")
+load("@rules_testing//lib:truth.bzl", "matching")
+load("@rules_testing//lib:util.bzl", "util")
+load("//cc:cc_binary.bzl", "cc_binary")
+load("//cc:cc_library.bzl", "cc_library")
+load("//cc/common:cc_common.bzl", "cc_common")
+load("//cc/toolchains:fdo_profile.bzl", "fdo_profile")
+load("//tests/cc/testutil:cc_analysis_test.bzl", "cc_analysis_test")
+
+def _test_linkstamp_compile_options_for_executable(name, **kwargs):
+    util.helper_target(
+        cc_library,
+        name = name + "/lib",
+        srcs = ["lib.cc"],
+        linkstamp = "ls.cc",
+    )
+
+    util.helper_target(
+        cc_binary,
+        name = name + "/foo",
+        deps = [name + "/lib"],
+    )
+
+    cc_analysis_test(
+        name = name,
+        impl = _test_linkstamp_compile_options_for_executable_impl,
+        targets = {
+            "target": name + "/foo",
+            "cc_toolchain": "//tests/cc/testutil/toolchains:current_cc_toolchain",
+        },
+        **kwargs
+    )
+
+def _test_linkstamp_compile_options_for_executable_impl(env, targets):
+    target = targets.target
+    cc_toolchain_info = targets.cc_toolchain[cc_common.CcToolchainInfo]
+    assert_linkstamp_action = env.expect.that_target(target).action_generating("{package}/{test_name}/_objs/foo/{package}/ls.o")
+    assert_linkstamp_action.argv().contains_at_least([
+        "--sysroot={}".format(cc_toolchain_info.sysroot),
+        "-include",
+        "-DGPLATFORM=\"{}\"".format(cc_toolchain_info.toolchain_id),
+        "-I.",
+        "-DG3_BUILD_TARGET=\"{bindir}/{package}/{name}\"",
+    ])
+    assert_linkstamp_action.argv().contains_predicate(
+        matching.str_matches("-DG3_TARGET_NAME=\"*//{}:{}".format(target.label.package, target.label.name)),
+    )
+    assert_linkstamp_action.argv().not_contains_predicate(
+        matching.str_matches("-DBUILD_FDO_TYPE"),
+    )
+
+def _test_linkstamp_compile_options_for_shared_library(name, **kwargs):
+    util.helper_target(
+        cc_library,
+        name = name + "/lib",
+        srcs = ["lib.cc"],
+        linkstamp = "ls.cc",
+    )
+
+    util.helper_target(
+        cc_binary,
+        name = name + "/foo",
+        deps = [name + "/lib"],
+        linkshared = True,
+    )
+
+    cc_analysis_test(
+        name = name,
+        impl = _test_linkstamp_compile_options_for_shared_library_impl,
+        targets = {
+            "target": name + "/foo",
+            "cc_toolchain": "//tests/cc/testutil/toolchains:current_cc_toolchain",
+        },
+        **kwargs
+    )
+
+def _test_linkstamp_compile_options_for_shared_library_impl(env, targets):
+    target = targets.target
+    cc_toolchain_info = targets.cc_toolchain[cc_common.CcToolchainInfo]
+    libfoo_so_name = paths.dirname(target.label.name) + "/libfoo.so"
+    assert_linkstamp_action = env.expect.that_target(target).action_generating("{package}/{test_name}/_objs/libfoo.so/{package}/ls.o")
+    assert_linkstamp_action.argv().contains_at_least([
+        "--sysroot={}".format(cc_toolchain_info.sysroot),
+        "-include",
+        "-DGPLATFORM=\"{}\"".format(cc_toolchain_info.toolchain_id),
+        "-I.",
+        "-DG3_BUILD_TARGET=\"{bindir}/{package}/" + libfoo_so_name + "\"",
+    ])
+    assert_linkstamp_action.argv().contains_predicate(
+        matching.str_matches("-DG3_TARGET_NAME=\"*//{}:{}".format(target.label.package, target.label.name)),
+    )
+    assert_linkstamp_action.argv().not_contains_predicate(
+        matching.str_matches("-DBUILD_FDO_TYPE"),
+    )
+
+def _test_linkstamp_compile_pic(name, **kwargs):
+    util.helper_target(
+        cc_library,
+        name = name + "/lib",
+        srcs = ["lib.cc"],
+        linkstamp = "ls.cc",
+    )
+
+    util.helper_target(
+        cc_binary,
+        name = name + "/foo",
+        deps = [name + "/lib"],
+    )
+
+    cc_analysis_test(
+        name = name,
+        impl = _test_linkstamp_compile_pic_impl,
+        target = name + "/foo",
+        config_settings = {
+            "//command_line_option:force_pic": True,
+        },
+        **kwargs
+    )
+
+def _test_linkstamp_compile_pic_impl(env, target):
+    assert_linkstamp_action = env.expect.that_target(target).action_generating("{package}/{test_name}/_objs/foo/{package}/ls.o")
+    assert_linkstamp_action.argv().contains("-fPIC")
+
+def _test_linkstamp_compile_fdo(name, **kwargs):
+    util.helper_target(
+        cc_library,
+        name = name + "/lib",
+        srcs = ["lib.cc"],
+        linkstamp = "ls.cc",
+    )
+
+    util.helper_target(
+        cc_binary,
+        name = name + "/foo",
+        deps = [name + "/lib"],
+    )
+
+    cc_analysis_test(
+        name = name,
+        impl = _test_linkstamp_compile_fdo_impl,
+        target = name + "/foo",
+        config_settings = {
+            "//command_line_option:fdo_instrument": "foo",
+        },
+        **kwargs
+    )
+
+def _test_linkstamp_compile_fdo_impl(env, target):
+    assert_linkstamp_action = env.expect.that_target(target).action_generating("{package}/{test_name}/_objs/foo/{package}/ls.o")
+    assert_linkstamp_action.argv().contains("-DBUILD_FDO_TYPE=\"FDO\"")
+
+# Regression test for b/73447914 - Linkstamps were not re-built when only
+# volatile data changed - they were not recompiled after changing a cc_binary
+# source resulting in old timestamps.
+# Assert that the relevant compilation outputs from a cc_binary are added as
+# inputs to the linkstamp action to ensure the action is invalidated whenever
+# any cc_binary inputs change.
+def _test_linkstamp_compile_cc_binary_deps(name, **kwargs):
+    util.helper_target(
+        cc_library,
+        name = name + "/lib",
+        srcs = ["lib.cc"],
+        linkstamp = "ls.cc",
+    )
+
+    util.helper_target(
+        cc_binary,
+        name = name + "/foo",
+        srcs = ["foo.cc"],
+        deps = [name + "/lib"],
+    )
+
+    cc_analysis_test(
+        name = name,
+        impl = _test_linkstamp_compile_cc_binary_deps_impl,
+        target = name + "/foo",
+        **kwargs
+    )
+
+def _test_linkstamp_compile_cc_binary_deps_impl(env, target):
+    assert_linkstamp_action = env.expect.that_target(target).action_generating("{package}/{test_name}/_objs/foo/{package}/ls.o")
+    assert_linkstamp_action.inputs().contains_at_least([
+        "{package}/_objs/{name}/foo.o",
+        "{package}/{test_name}/liblib.a",
+    ])
+
+def _test_linkstamp_compile_gets_copts_from_options(name, **kwargs):
+    util.helper_target(
+        cc_library,
+        name = name + "/lib",
+        srcs = ["lib.cc"],
+        copts = ["-copt_from_cc_library"],
+        linkstamp = "ls.cc",
+    )
+
+    util.helper_target(
+        cc_binary,
+        name = name + "/foo",
+        copts = ["-copt_from_cc_binary"],
+        deps = [name + "/lib"],
+    )
+
+    cc_analysis_test(
+        name = name,
+        impl = _test_linkstamp_compile_gets_copts_from_options_impl,
+        target = name + "/foo",
+        config_settings = {
+            "//command_line_option:copt": ["-copt_from_config"],
+        },
+        **kwargs
+    )
+
+def _test_linkstamp_compile_gets_copts_from_options_impl(env, target):
+    assert_linkstamp_action = env.expect.that_target(target).action_generating("{package}/{test_name}/_objs/foo/{package}/ls.o")
+    assert_linkstamp_action.argv().contains(
+        "-copt_from_config",
+    )
+    assert_linkstamp_action.argv().contains_none_of([
+        "-copt_from_cc_library",
+        "-copt_from_cc_binary",
+    ])
+
+def _test_linkstamp_compile_ignores_copts_from_attributes(name, **kwargs):
+    util.helper_target(
+        cc_library,
+        name = name + "/lib",
+        srcs = ["lib.cc"],
+        copts = ["-copt_from_cc_library"],
+        linkstamp = "ls.cc",
+    )
+
+    util.helper_target(
+        cc_binary,
+        name = name + "/foo",
+        copts = ["-copt_from_cc_binary"],
+        deps = [name + "/lib"],
+    )
+
+    cc_analysis_test(
+        name = name,
+        impl = _test_linkstamp_compile_ignores_copts_from_attributes_impl,
+        target = name + "/foo",
+        **kwargs
+    )
+
+def _test_linkstamp_compile_ignores_copts_from_attributes_impl(env, target):
+    assert_linkstamp_action = env.expect.that_target(target).action_generating("{package}/{test_name}/_objs/foo/{package}/ls.o")
+    assert_linkstamp_action.argv().contains_none_of([
+        "-copt_from_cc_library",
+        "-copt_from_cc_binary",
+    ])
+
+def _test_linkstamp_compile_uses_memprof(name, **kwargs):
+    util.helper_target(
+        fdo_profile,
+        name = name + "/prof",
+        profile = "out.afdo",
+        memprof_profile = "memprof.zip",
+    )
+
+    util.helper_target(
+        cc_library,
+        name = name + "/lib",
+        srcs = ["lib.cc"],
+        linkstamp = "ls.cc",
+    )
+
+    util.helper_target(
+        cc_binary,
+        name = name + "/foo",
+        deps = [name + "/lib"],
+    )
+
+    cc_analysis_test(
+        name = name,
+        impl = _test_linkstamp_compile_uses_memprof_impl,
+        target = name + "/foo",
+        config_settings = {
+            "//command_line_option:compilation_mode": "opt",
+            # buildifier: disable=canonical-repository
+            "//command_line_option:fdo_profile": "@@//" + native.package_name() + ":" + name + "/prof",
+        },
+        test_features = [
+            "memprof_optimize",
+        ],
+        **kwargs
+    )
+
+def _test_linkstamp_compile_uses_memprof_impl(env, target):
+    assert_linkstamp_action = env.expect.that_target(target).action_generating("{package}/{test_name}/_objs/foo/{package}/ls.o")
+    assert_linkstamp_action.argv().contains("-DBUILD_PGHO_TYPE=\"opt\"")
+
+def cc_linkstamp_compile_tests(name):
+    tests = [
+        _test_linkstamp_compile_options_for_executable,
+        _test_linkstamp_compile_options_for_shared_library,
+        _test_linkstamp_compile_pic,
+        _test_linkstamp_compile_fdo,
+        _test_linkstamp_compile_cc_binary_deps,
+        _test_linkstamp_compile_gets_copts_from_options,
+        _test_linkstamp_compile_ignores_copts_from_attributes,
+    ]
+
+    # TODO(cmita): This is overly restrictive - the requirement is for the memprof_profile attribute (Bazel 8)
+    if bazel_features.cc.cc_common_is_in_rules_cc:
+        tests.extend([
+            _test_linkstamp_compile_uses_memprof,
+        ])
+
+    test_suite(
+        name = name,
+        tests = tests,
+    )
diff --git a/tests/cc/testutil/toolchains/cc_toolchain_config.bzl b/tests/cc/testutil/toolchains/cc_toolchain_config.bzl
index b927fd0..f712751 100644
--- a/tests/cc/testutil/toolchains/cc_toolchain_config.bzl
+++ b/tests/cc/testutil/toolchains/cc_toolchain_config.bzl
@@ -565,6 +565,17 @@
                 ),
             ],
         ),
+        flag_set(
+            actions = [
+                ACTION_NAMES.linkstamp_compile,
+            ],
+            flag_groups = [
+                flag_group(
+                    expand_if_available = "is_using_memprof",
+                    flags = ["-DBUILD_PGHO_TYPE=\"opt\""],
+                ),
+            ],
+        ),
     ],
 )