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: