Use --ld-path= for the autoconfigured Clang linker (#935)

When Clang is the compiler, the autoconfigured toolchain passes the linker's absolute path through `-fuse-ld=`, e.g.
`-fuse-ld=/usr/bin/ld.lld`. Clang 12 deprecated `-fuse-ld=<path>` in favor of `--ld-path=` (https://reviews.llvm.org/D83015) because the `-fuse-ld=` value is the linker flavor, which a path loses. For example, on Darwin `-fuse-ld=/path/to/ld64.lld` makes the driver pass ld64's version-dependent options to lld.

Pass `-fuse-ld=lld --ld-path=/usr/bin/ld.lld` (or the gold equivalent) when Clang accepts `--ld-path=`, and fall back to `-fuse-ld=<path>` otherwise.

Fixes #934

Closes #935

COPYBARA_INTEGRATE_REVIEW=https://github.com/bazelbuild/rules_cc/pull/935 from MaskRay:ld-path 4245e780980665cd3aa2d699bad594ae3e3b6f50
PiperOrigin-RevId: 1012001045
Change-Id: I59ab45762d04dd9be202c2515135b60d21519ef4
diff --git a/cc/private/toolchain/unix_cc_configure.bzl b/cc/private/toolchain/unix_cc_configure.bzl
index 4297f37..5091813 100644
--- a/cc/private/toolchain/unix_cc_configure.bzl
+++ b/cc/private/toolchain/unix_cc_configure.bzl
@@ -216,7 +216,7 @@
 def _is_oso_prefix_supported(repository_ctx, ld):
     return repository_ctx.execute([ld, "-v", "-oso_prefix", "."]).return_code == 0
 
-def _find_linker_path(repository_ctx, cc, linker, is_clang):
+def _find_linker_flags(repository_ctx, cc, linker, is_clang):
     """Checks if a given linker is supported by the C compiler.
 
     Args:
@@ -226,7 +226,7 @@
       is_clang: whether the compiler is known to be clang
 
     Returns:
-      String to put as value to -fuse-ld= flag, or None if linker couldn't be found.
+      List of flags selecting the linker, or None if linker couldn't be found.
     """
     result = repository_ctx.execute([
         cc,
@@ -245,7 +245,7 @@
         return None
 
     if not is_clang:
-        return linker
+        return ["-fuse-ld=" + linker]
 
     # Extract linker path from:
     # /usr/bin/clang ...
@@ -254,9 +254,22 @@
     # https://github.com/llvm/llvm-project/blob/85c78274358717e4d5d019a801decba5c1add484/clang/lib/Driver/Job.cpp#L207-L209
     invocations = [line for line in result.stderr.splitlines() if line.startswith(" \"")]
     if not invocations:
-        return linker
+        return ["-fuse-ld=" + linker]
     linker_command = invocations[-1]
-    return linker_command.strip().split(" ")[0].strip("\"'")
+    linker_path = linker_command.strip().split(" ")[0].strip("\"'")
+
+    # Clang uses the -fuse-ld= value as the linker flavor. --ld-path= (Clang 12+)
+    # specifies the path without losing the flavor.
+    flags = ["-fuse-ld=" + linker, "--ld-path=" + linker_path]
+    result = repository_ctx.execute([
+        cc,
+        str(repository_ctx.path("tools/cpp/empty.cc")),
+        "-o",
+        "/dev/null",
+    ] + flags)
+    if result.return_code != 0:
+        return ["-fuse-ld=" + linker_path]
+    return flags
 
 def _add_compiler_option_if_supported(repository_ctx, cc, option):
     """Returns `[option]` if supported, `[]` otherwise. Doesn't %-escape the option."""
@@ -548,9 +561,9 @@
         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)
+    gold_or_lld_linker_flags = (
+        _find_linker_flags(repository_ctx, cc, "lld", is_clang) or
+        _find_linker_flags(repository_ctx, cc, "gold", is_clang)
     )
     cc_path = repository_ctx.path(cc)
     if not str(cc_path).startswith(str(repository_ctx.path(".")) + "/"):
@@ -559,7 +572,7 @@
     else:
         # cc is inside the repository, don't set -B.
         bin_search_flags = []
-    if not gold_or_lld_linker_path:
+    if not gold_or_lld_linker_flags:
         ld_path = repository_ctx.path(tool_paths["ld"])
         if ld_path.dirname != cc_path.dirname:
             bin_search_flags.append("-B" + escape_string(str(ld_path.dirname)))
@@ -570,8 +583,8 @@
             if ld_path.dirname != cc_path.dirname:
                 bin_search_flags.append("-B" + escape_string(str(ld_path.dirname)))
     force_linker_flags = []
-    if gold_or_lld_linker_path:
-        force_linker_flags.append("-fuse-ld=" + gold_or_lld_linker_path)
+    if gold_or_lld_linker_flags:
+        force_linker_flags.extend(gold_or_lld_linker_flags)
 
     # TODO: It's unclear why these flags aren't added on macOS.
     if bin_search_flags and not darwin: