tweag / rules_nixpkgs

Rules for importing Nixpkgs packages into Bazel.
Apache License 2.0
276 stars 79 forks source link

Add toolchain for rust-analyzer #395

Open contagnas opened 1 year ago

contagnas commented 1 year ago

Is your feature request related to a problem? Please describe.

rules_rust provides a toolchain for rust-analyzer (docs).

It'd be nice to provide a way here to set this up with nix binaries.

Describe the solution you'd like

Add an option to nixpkgs_rust_configure to set up a rust-analyzer toolchain.

Describe alternatives you've considered

On NixOS, rules_rust's default setup almost works, but it sets up an unpatched rust-analyzer-proc-macro-srv that'll cause it to not be able to expand proc macros:

proc macro `stream_inner` not expanded: Failed to run proc-macro server from path `bazel info output_base`/external/rust_analyzer_1.69.0_tools/libexec/rust-analyzer-proc-macro-srv, error: Os { code: 2, kind: NotFound, message: \"No such file or directory\" }

Additional context

I tried to set this up in my downstream repo but couldn't quite wrap my head around how the tools toolchains work in rules_rust. My attempt:

# WORKSPACE.bzl
nixpkgs_package(
    name = "rust-analyzer",
    attribute_path = "rust-analyzer",
    repository = "@nixpkgs",
)

nixpkgs_package(
    name = "rustc",
    attribute_path = "rustc",
    repository = "@nixpkgs",
)

nixpkgs_package(
    name = "rustc-src",
    attribute_path = "rust.packages.stable.rustPlatform.rustcSrc",
    repository = "@nixpkgs",
    build_file_content = """
package(default_visibility = [ "//visibility:public" ])
filegroup(
    name = "src",
    srcs = glob(["src/**/*"]),
)
    """,
)

register_toolchains("//bazel/toolchains:rust_analyzer_toolchain")
# bazel/toolchains/BUILD.bazel
load("@rules_rust//rust:toolchain.bzl", "rust_analyzer_toolchain")

rust_analyzer_toolchain(
    name = "rust_analyzer_toolchain",
    proc_macro_srv = "@rust-analyzer//:bin/rust-analyzer",
    rustc = "@rustc//:bin/rustc",
    rustc_srcs = "@rustc-src//:src",
)

But this isn't quite right:

ERROR: `bazel info output_base`/external/rules_rust/tools/rust_analyzer/BUILD.bazel:5:12: While resolving toolchains for target @rules_rust//tools/rust_analyzer:gen_rust_project: invalid registered toolchain '//bazel/toolchains:rust_analyzer_toolchain': target does not provide the DeclaredToolchainInfo provider
aherrmann commented 1 year ago

@contagnas Thanks for raising this. Yes, this sounds like it would be a good addition.

{ code: 2, kind: NotFound, message: \"No such file or directory\" }

This sounds like it could be the classic interpreter path issue, see https://github.com/NixOS/nixpkgs/issues/107375. Using a Nix provided binary instead would be a good way to avoid this issue.

target does not provide the DeclaredToolchainInfo provider

It looks like you're pretty close with your solution already. Bazel toolchains are defined with two layers of rules, the tool specific rule, rust_analyzer_toolchain in this case, and the generic toolchain rule. IIUC rules_rust sets this up here for the standard rust analyzer toolchain. It involves a bit of indirection, but toolchain_repository_proxy leads down to the BUILD file containing the toolchain target.

It makes sense to place the toolchain target and the corresponding rust_analyzer_toolchain target into separate external workspaces. Bazel needs to inspect the toolchain target to perform toolchain resolution, but may resolve a different toolchain instance. So, placing rust_analyzer_toolchain into a separate external workspace enables lazy fetching of the corresponding external workspace.