Repository: bazelbuild/bazel
Issue: After upgrading to bazel 7.0.0 gcc fails with: --push-state: unknown option
Labels: type: bug
team-Rules-CPP
untriaged

### Description of the bug:


After upgrading to bazel 7.0.0 the builds in our internal CIs that have an old gcc compiler are failing with:
```
(08:11:06) ERROR: /home/build/.cache/native_bazel_output_base/external/io_grpc_grpc_java/compiler/BUILD.bazel:5:10: Linking external/io_grpc_grpc_java/compiler/grpc_java_plugin [for tool] failed: (Exit 1): gcc failed: error executing CppLink command (from target @@io_grpc_grpc_java//compiler:grpc_java_plugin) 
  (cd /home/build/.cache/native_bazel_output_base/sandbox/processwrapper-sandbox/7179/execroot/core && \
  exec env - \
    PATH=/bin:/usr/bin:/usr/local/bin \
    PWD=/proc/self/cwd \
    ZERO_AR_DATE=1 \
  /usr/bin/gcc @bazel-out/k8-opt-exec-ST-13d3ddad9198/bin/external/io_grpc_grpc_java/compiler/grpc_java_plugin-2.params)
# Configuration: 922915957e448184486ff0fb7f0ba0ee9f92dfb993e46799f9d5193882b93aa1
# Execution platform: @@local_config_platform//:host
```
seems that the check for is_push_state_supported in https://github.com/bazelbuild/bazel/commit/2482322fedb463e0bbecd29c5e8e6d0f087ed884 is not working well



### Which category does this issue belong to?


C++/Objective-C Rules

### What's the simplest, easiest way to reproduce this bug? Please provide a minimal example if possible.


_No response_

### Which operating system are you running Bazel on?


MacOS and Linux

### What is the output of `bazel info release`?


release 7.0.0

### If `bazel info release` returns `development version` or `(@non-git)`, tell us how you built Bazel.


_No response_

### What's the output of `git remote get-url origin; git rev-parse master; git rev-parse HEAD` ?


_No response_

### Is this a regression? If yes, please try to identify the Bazel commit where the bug was introduced.


https://github.com/bazelbuild/bazel/commit/2482322fedb463e0bbecd29c5e8e6d0f087ed884

### Have you found anything relevant by searching the web?

_No response_

### Any other information, logs, or outputs that you want to share?

_No response_

Issue comments:
@bazel-io fork 7.0.1
@fmeum Are you looking into a fix? This seems to be the only blocker for 7.0.1
@meteorcloudy Yes, the speculative fix is https://github.com/bazelbuild/bazel/pull/20833. Unfortunately the reporter is unable to test this and it's also very challenging to cover in integration tests.
A fix for this issue has been included in [Bazel 7.0.1 RC2](https://releases.bazel.build/7.0.1/rc2/index.html). Please test out the release candidate and report any issues as soon as possible. Thanks!

Verified that 7.0.1 fixes this issue.
@bazel-io fork 7.1.0

Pull request review comments:

Patch that resolved the issue:
diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock
index 985f3b8cb8a5aa..badb20420084f0 100644
--- a/MODULE.bazel.lock
+++ b/MODULE.bazel.lock
@@ -2180,7 +2180,7 @@
       "general": {
         "bzlTransitiveDigest": "OaXuahb8Ga1zYeFJL4rrJjYmP9XovLouv9Tp+aqzEX0=",
         "accumulatedFileDigests": {
-          "@@//src/test/tools/bzlmod:MODULE.bazel.lock": "a35aced942408a91b1d681edb1049ebf55c7ddad7f382d6a45d44953510f4d96",
+          "@@//src/test/tools/bzlmod:MODULE.bazel.lock": "a76d8c53ac208e3b6335eefa542a24b2e1a70fcfccb5d79fd80cea2cc2947ab4",
           "@@//:MODULE.bazel": "1ce286c2e04a814940dcb741cddee8772a3d8b97d22e12ee12e116dac57f1cd3"
         },
         "envVariables": {},
diff --git a/tools/cpp/unix_cc_configure.bzl b/tools/cpp/unix_cc_configure.bzl
index 6d6e7171edc98b..5e7b3b79f427c9 100644
--- a/tools/cpp/unix_cc_configure.bzl
+++ b/tools/cpp/unix_cc_configure.bzl
@@ -161,10 +161,9 @@ def _is_compiler_option_supported(repository_ctx, cc, option):
     ])
     return result.stderr.find(option) == -1
 
-def _is_linker_option_supported(repository_ctx, cc, option, pattern):
+def _is_linker_option_supported(repository_ctx, cc, force_linker_flags, option, pattern):
     """Checks that `option` is supported by the C linker. Doesn't %-escape the option."""
-    result = repository_ctx.execute([
-        cc,
+    result = repository_ctx.execute([cc] + force_linker_flags + [
         option,
         "-o",
         "/dev/null",
@@ -213,9 +212,9 @@ def _add_compiler_option_if_supported(repository_ctx, cc, option):
     """Returns `[option]` if supported, `[]` otherwise. Doesn't %-escape the option."""
     return [option] if _is_compiler_option_supported(repository_ctx, cc, option) else []
 
-def _add_linker_option_if_supported(repository_ctx, cc, option, pattern):
+def _add_linker_option_if_supported(repository_ctx, cc, force_linker_flags, option, pattern):
     """Returns `[option]` if supported, `[]` otherwise. Doesn't %-escape the option."""
-    return [option] if _is_linker_option_supported(repository_ctx, cc, option, pattern) else []
+    return [option] if _is_linker_option_supported(repository_ctx, cc, force_linker_flags, option, pattern) else []
 
 def _get_no_canonical_prefixes_opt(repository_ctx, cc):
     # If the compiler sometimes rewrites paths in the .d files without symlinks
@@ -420,16 +419,40 @@ def configure_unix_toolchain(repository_ctx, cpu_value, overriden_tools):
         False,
     ), ":")
 
+    gold_or_lld_linker_path = (
+        _find_linker_path(repository_ctx, cc, "lld", is_clang) or
+        _find_linker_path(repository_ctx, cc, "gold", is_clang)
+    )
+    cc_path = repository_ctx.path(cc)
+    if not str(cc_path).startswith(str(repository_ctx.path(".")) + "/"):
+        # cc is outside the repository, set -B
+        bin_search_flags = ["-B" + escape_string(str(cc_path.dirname))]
+    else:
+        # cc is inside the repository, don't set -B.
+        bin_search_flags = []
+    if not gold_or_lld_linker_path:
+        ld_path = repository_ctx.path(tool_paths["ld"])
+        if ld_path.dirname != cc_path.dirname:
+            bin_search_flags.append("-B" + str(ld_path.dirname))
+    force_linker_flags = []
+    if gold_or_lld_linker_path:
+        force_linker_flags.append("-fuse-ld=" + gold_or_lld_linker_path)
+
+    # TODO: It's unclear why these flags aren't added on macOS.
+    if bin_search_flags and not darwin:
+        force_linker_flags.extend(bin_search_flags)
     use_libcpp = darwin or bsd
     is_as_needed_supported = _is_linker_option_supported(
         repository_ctx,
         cc,
+        force_linker_flags,
         "-Wl,-no-as-needed",
         "-no-as-needed",
     )
     is_push_state_supported = _is_linker_option_supported(
         repository_ctx,
         cc,
+        force_linker_flags,
         "-Wl,--push-state",
         "--push-state",
     )
@@ -463,21 +486,6 @@ def configure_unix_toolchain(repository_ctx, cpu_value, overriden_tools):
         bazel_linklibs,
         False,
     ), ":")
-    gold_or_lld_linker_path = (
-        _find_linker_path(repository_ctx, cc, "lld", is_clang) or
-        _find_linker_path(repository_ctx, cc, "gold", is_clang)
-    )
-    cc_path = repository_ctx.path(cc)
-    if not str(cc_path).startswith(str(repository_ctx.path(".")) + "/"):
-        # cc is outside the repository, set -B
-        bin_search_flags = ["-B" + escape_string(str(cc_path.dirname))]
-    else:
-        # cc is inside the repository, don't set -B.
-        bin_search_flags = []
-    if not gold_or_lld_linker_path:
-        ld_path = repository_ctx.path(tool_paths["ld"])
-        if ld_path.dirname != cc_path.dirname:
-            bin_search_flags.append("-B" + str(ld_path.dirname))
     coverage_compile_flags, coverage_link_flags = _coverage_flags(repository_ctx, darwin)
     print_resource_dir_supported = _is_compiler_option_supported(
         repository_ctx,
@@ -610,19 +618,18 @@ def configure_unix_toolchain(repository_ctx, cpu_value, overriden_tools):
             ),
             "%{cxx_flags}": get_starlark_list(cxx_opts + _escaped_cplus_include_paths(repository_ctx)),
             "%{conly_flags}": get_starlark_list(conly_opts),
-            "%{link_flags}": get_starlark_list((
-                ["-fuse-ld=" + gold_or_lld_linker_path] if gold_or_lld_linker_path else []
-            ) + (
+            "%{link_flags}": get_starlark_list(force_linker_flags + (
                 ["-Wl,-no-as-needed"] if is_as_needed_supported else []
             ) + _add_linker_option_if_supported(
                 repository_ctx,
                 cc,
+                force_linker_flags,
                 "-Wl,-z,relro,-z,now",
                 "-z",
             ) + (
                 [
                     "-headerpad_max_install_names",
-                ] if darwin else bin_search_flags + [
+                ] if darwin else [
                     # Gold linker only? Can we enable this by default?
                     # "-Wl,--warn-execstack",
                     # "-Wl,--detect-odr-violations"
@@ -664,6 +671,7 @@ def configure_unix_toolchain(repository_ctx, cpu_value, overriden_tools):
                 ["-Wl,-dead_strip"] if darwin else _add_linker_option_if_supported(
                     repository_ctx,
                     cc,
+                    force_linker_flags,
                     "-Wl,--gc-sections",
                     "-gc-sections",
                 ),


Test patch:
diff --git a/src/test/tools/bzlmod/MODULE.bazel.lock b/src/test/tools/bzlmod/MODULE.bazel.lock
index 6887b750690452..b7493f2c371bf4 100644
--- a/src/test/tools/bzlmod/MODULE.bazel.lock
+++ b/src/test/tools/bzlmod/MODULE.bazel.lock
@@ -1016,7 +1016,7 @@
     },
     "@@bazel_tools//tools/cpp:cc_configure.bzl%cc_configure_extension": {
       "general": {
-        "bzlTransitiveDigest": "O9sf6ilKWU9Veed02jG9o2HM/xgV/UAyciuFBuxrFRY=",
+        "bzlTransitiveDigest": "mcsWHq3xORJexV5/4eCvNOLxFOQKV6eli3fkr+tEaqE=",
         "accumulatedFileDigests": {},
         "envVariables": {},
         "generatedRepoSpecs": {