rust-lang / rust-analyzer

A Rust compiler front-end for IDEs
https://rust-analyzer.github.io/
Apache License 2.0
14.34k stars 1.62k forks source link

rust-analyzer doesn’t enable/pass a feature with `cargo.features` to a build script #18450

Open 4JX opened 3 weeks ago

4JX commented 3 weeks ago

Converting to an issue since I see no way this would be intended behavior, and I haven't been able to solve it myself.

I have "rust-analyzer.cargo.features": ["scrap/linux-pkg-config"] in a .vscode/settings.json, but it seemingly doesn't want to work.

Build script fails on this function, with VCPKG_ROOT not found..., which is code it shouldn't be getting to given that using pkg-config is enabled and I'm not setting NO_PKG_CONFIG_* anywhere.

Manually running the command does work:

» cargo check --workspace --message-format=json-diagnostic-rendered-ansi --manifest-path /path/to/Cargo.toml --keep-going --all-targets --features scrap/linux-pkg-config
(whole load of diagnostics text)

Using some logging suggests that the feature isn't being enabled at all after a server restart:

Caused by:
  process didn't exit successfully:...
  --- stdout
  Starting build script...
...
  Checking config for linux-pkg-config feature: false
  Checking NO_PKG_CONFIG variable value: Err(NotPresent)
  Using homebrew
  target_os: linux, target_arch: x86_64

Originally posted by @4JX in https://github.com/rust-lang/rust-analyzer/discussions/18416

ChayimFriedman2 commented 3 weeks ago

In build scripts you don't check for cfg(feature = "foo") since they are compiled without features, you instead check the environment variable CARGO_FEATURE_FOO. Also this isn't related to rust-analyzer. See https://doc.rust-lang.org/stable/cargo/reference/build-scripts.html.

4JX commented 3 weeks ago

In build scripts you don't check for cfg(feature = "foo") since they are compiled without features, you instead check the environment variable CARGO_FEATURE_FOO.

I'm not sure I understand this. Does rust-analyzer explicitly not set the features for certain external crates?

// /tmp/buildtest/build.rs
// In another crate elsewhere: buildtest = { path = "/tmp/buildtest" }, without explicitly setting features here
fn main() {
    let feature_var = std::env::var("CARGO_FEATURE_FOO");
    dbg!(&feature_var);

    if !feature_var.is_ok() {
        dbg!("foo is disabled (env check)");
    }

    if !cfg!(feature = "foo") {
        dbg!("foo is disabled");
        panic!("oh no");
    }
}

This prints "disabled" for both checks with "rust-analyzer.cargo.features": ["buildtest/foo"], despite a manual cargo check/build behaving as expected when I add or remove --features="buildtest/foo".

ChayimFriedman2 commented 3 weeks ago

It needs to be just foo, not buildtest/foo (perhaps we can support the later format too).

4JX commented 3 weeks ago

It needs to be just foo, not buildtest/foo (perhaps we can support the later format too).

The build.rs example crate is used from another crate that depends on it. In my case, I depend on scrap as a dependency, I'm not working on scrap itself.

Using foo fails with

2024-11-01T17:12:28.650541693+01:00 ERROR Flycheck failed to run the following command: CommandHandle { program: "/nix/store/mz68k40jyzrq6r5pjfsk0jcp0a9yniyl-rust-default-1.81.0/bin/cargo", arguments: ["check", "--workspace", "--message-format=json-diagnostic-rendered-ansi", "--manifest-path", "/tmp/program/Cargo.toml", "--keep-going", "--all-targets", "--features", "foo"], current_dir: Some("/tmp/program") }, error=Cargo watcher failed, the command produced no valid metadata (exit code: ExitStatus(unix_wait_status(25856))):
error: none of the selected packages contains these features: foo

Because the program's source does not have a feature foo; it depends on a library with the feature foo.

As a workaround, I could add a feature in my crate like this:

# /tmp/program
[features]
foo = ["buildtest/foo"]

But that feels unnecessary.