Skip to content

[Feature request] Easy way to switch to rust-lld for linking on Linux #3602

@timothyg-stripe

Description

@timothyg-stripe

With the exception of wasm, rules_rust currently always uses the linker specified in the relevant cc_toolchain:

if toolchain.target_arch not in ("wasm32", "wasm64"):
if output_dir:
use_pic = _should_use_pic(cc_toolchain, feature_configuration, crate_info.type, compilation_mode)
rpaths = _compute_rpaths(toolchain, output_dir, dep_info, use_pic)
else:
rpaths = depset()
ld, link_args, link_env = get_linker_and_args(ctx, crate_info.type, cc_toolchain, feature_configuration, rpaths, add_flags_for_binary = add_flags_for_binary)
env.update(link_env)
rustc_flags.add(ld, format = "--codegen=linker=%s")
. However, it would be good to let users configure what linker to use for Rust:

  • On Linux, rules_cc defaults to LLD, then gold, then the default ld (ld.bfd). If LLD is not installed globally, then it'll use gold, but gold is deprecated and not appropriate for Rust.
  • On several platforms, Rust comes bundled with rust-lld. In fact, Rust 1.90.0 will make it so that it uses rust-lld by default on x86-64 Linux.
  • LLD is much faster than both ld.bfd and gold.

It would be nice to be able to use rust-lld for linking, either through a gcc driver, or directly. (I.e., -Clinker-flavor=ld.lld/gnu-lld and gnu-lld-cc.)


As breadcrumbs, I was able to get the equivalent of linker-flavor=gnu-lld-cc working locally by applying:

  • Add gcc-ld to rustc_lib target #3600

  • A patch to expand $(RUST_SYSROOT) in extra_exec_rustc_flags
    diff -ur rules_rust/rust/private/rustc.bzl rules_rust-patched/rust/private/rustc.bzl
    --- rules_rust/rust/private/rustc.bzl 2025-09-09 01:16:47.480776299 +0000
    +++ rules_rust-patched/rust/private/rustc.bzl 2025-09-09 01:20:48.211779196 +0000
    @@ -1099,10 +1099,12 @@
         if crate_info.type in toolchain.extra_rustc_flags_for_crate_types.keys():
             rustc_flags.add_all(toolchain.extra_rustc_flags_for_crate_types[crate_info.type], map_each = map_flag)
    
    -    if is_exec_configuration(ctx):
    -        rustc_flags.add_all(toolchain.extra_exec_rustc_flags, map_each = map_flag)
    -    else:
    -        rustc_flags.add_all(toolchain.extra_rustc_flags, map_each = map_flag)
    +    for flag in (toolchain.extra_exec_rustc_flags if is_exec_configuration(ctx) else toolchain.extra_rustc_flags):
    +        if map_flag:
    +            flag = map_flag(flag)
    +        if flag != None:
    +            flag = flag.replace("$(RUST_SYSROOT)", toolchain.sysroot)
    +        rustc_flags.add(flag)
    
         # extra_rustc_flags apply to the target configuration, not the exec configuration.
         if hasattr(ctx.attr, "_extra_rustc_flags") and not is_exec_configuration(ctx):
  • Finally, extra_rustc_flags to tell the GCC driver to use lld

    rust_register_toolchains(
        versions = ["1.89.0"],
        extra_rustc_flags = {
            "x86_64-unknown-linux-gnu": [
                "--codegen=link-arg=-B$(RUST_SYSROOT)/lib/rustlib/x86_64-unknown-linux-gnu/bin/gcc-ld",
                "--codegen=link-arg=-fuse-ld=lld",
            ],
        },
    )

    With rust_repository_set: Allow extra_exec_rustc_flags to be a dict #3601 applied, we would be able to also do the same with extra_exec_rustc_flags

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions