Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bazel query is broken for Rust targets #2383

Closed
csmulhern opened this issue Dec 29, 2023 · 9 comments
Closed

Bazel query is broken for Rust targets #2383

csmulhern opened this issue Dec 29, 2023 · 9 comments
Assignees
Labels
bug import Issues related to //util/import

Comments

@csmulhern
Copy link
Contributor

bazel version: 7.0.0
rules_rust version: 0.36.1

Sample: example.zip

To reproduce, run:

bazel query "deps(//:main)"

Output:

ERROR: /private/var/tmp/_bazel_cameron/bd7f4772f50608f24ec4c16fe5369dcc/external/rules_rust/util/import/3rdparty/crates/BUILD.bazel:52:6: no such package '@@rules_rust_util_import__quote-1.0.10//': The repository '@@rules_rust_util_import__quote-1.0.10' could not be resolved: Repository '@@rules_rust_util_import__quote-1.0.10' is not defined and referenced by '@@rules_rust//util/import/3rdparty/crates:quote'
ERROR: Evaluation of query "deps(//:main)" failed: preloading transitive closure failed: no such package '@@rules_rust_util_import__quote-1.0.10//': The repository '@@rules_rust_util_import__quote-1.0.10' could not be resolved: Repository '@@rules_rust_util_import__quote-1.0.10' is not defined

It looks like there is an implicit dependency on @rules_rust/util/import for all rust rules, but these dependencies are not included through rules_rust_dependencies.

I'm guessing this dependency is coming from:

"_import_macro_dep": attr.label(
default = Label("//util/import"),
cfg = "exec",

The simplest fix seems like it would be to add import_deps to rules_rust_dependencies. However, I'm also wondering if it's really necessary for all rules to depend on @rules_rust/util/import.

This issue prevents usage of bazel query with rust targets, and breaks workflows that depend on bazel query, e.g. ibazel.

@illicitonion
Copy link
Collaborator

It looks like Bazel 7 made label_flag more eager during query: bazelbuild/bazel@658b3a6

cc @cfredric @hlopko as authors of the feature

cc @gregestren - it looks like rules_rust was depending on not reading through label_flag to avoiding dependencies needing to be set up for a niche use-case - do you know of any handy workarounds?

@scentini
Copy link
Collaborator

scentini commented Jan 3, 2024

@gregestren Could you please advise what to do here?

@katre
Copy link
Member

katre commented Jan 3, 2024

It looks like the standard attribute _import_macro_dep is a label-valued attribute, which points to //util/import, which is an alias with a select:

alias(
    name = "import",
    actual = select({
        ":use_fake_import_macro": ":fake_import_macro_impl",
        "//conditions:default": ":import_macro_label",
    }),
    visibility = ["//visibility:public"],
)

The long-standing behavior of select and query has been to overapproxamate the dependencies by including all of them. This is where the label_flag arrives: as the value of the select.

Why are you using an alias/select and a label_flag? Would a custom flag be more useful here?

You're correct: we changed how label_flag works with query, based on the same idea of overapproxamation from the select handling. It looks like this was associated with an internal bug, but the core problem was that increased use of label-typed flags led to failures in dependency analysis with the old behavior, which caused some breakages due to tests not being run when they should have been (and when they would have shown failures).

@illicitonion
Copy link
Collaborator

That all makes sense in terms of how we got here, and I don't disagree with the behaviour of select and query here in general :)

The background here in terms of rules_rust is that Google effectively wanted to add an optional implicit dependency to all of its rust code (#1008), and there hasn't historically been a very nice way of doing so. Macros are hard because you can't force other rulesets to use them. Possibly the extensible rules stuff Ivo is working on could help, though still has the "how do you force other rulesets to use it" problem.

That implicit dependency, unfortunately, requires additional repositories to be registered in the workspace. We ideally don't want to do this automatically for the 99% of non-Google users who don't use this feature (and in a pre-bzlmod world it may be hard to do so, as it would possibly require our users add a second initialisation function to their WORKSPACE file, as that repository would depend on symbols we initialise in the function they already call).

This broke query because we didn't register these repositories by default, and @hlopko found the cute workaround that was in place.

So I guess the question is: How should Google be adding this dependency for their own code and not impact anyone else? Is there a reasonable way for them to extend the rules (or will there be soon)? Is there a way to register a dependency which doesn't show up to query unless it's enabled (maybe we could do something ugly like add this target as a dependency of a toolchain and either use an optional toolchain to enable it or have Google enable a custom toolchain which includes the dep where the default toolchain wouldn't)? Or any other cute ideas?

@katre
Copy link
Member

katre commented Jan 3, 2024

The best ways, in rough order:

  1. Use rule extensions inside google to add google-only functionality (and make sure that google code only uses those extended rules).
  2. Use a new toolchain type which is optional for the new functionality (and gate the code that calls it behind a check for whether the toolchain exists, but this adds complexity to the open source rules).
    1. The benefit to this approach is that any motivated rust user could use the functionality, not just google. I don't actually know what the internal google team is doing here.

@scentini scentini assigned scentini and unassigned gregestren Jan 3, 2024
@scentini
Copy link
Collaborator

scentini commented Jan 3, 2024

I'm happy to try rule extensions if they are suitable to solve this problem; @comius are they in good enough shape to be reliably depended upon? Could you point me to documentation/example usage?

@gregestren
Copy link

I didn't read through in detail, but could

"_import_macro_dep": attr.label(
default = Label("//util/import"),
cfg = "exec",

be replaced by a direct dependency on a label_flag that defaults to a trivial no-op label (which is what query would follow)? But Google could custom-route to its own special dependency by setting the flag differently?

The current selection is on

"@rules_rust//rust/settings:use_real_import_macro": "False",

Can whatever sets that boolean to True just directly set the label flag?

@scentini
Copy link
Collaborator

scentini commented Jan 9, 2024

I talked about this issue to @krasimirgg and @hlopko. We may have a need for having the import macro in OSS in the future, at which point we'll need to revisit this again; but for now it's okay to replace the import macro with a dummy in rules_rust and use the real import macro in Google's monorepo.
I think @katre's option #2 is worth giving a shot, unfortunately I don't think we'll have the cycles for it anytime soon, and this does look like a blocker for adopting Bazel 7.0.

scentini added a commit that referenced this issue Jan 11, 2024
As discussed over at
#2383
daivinhtran pushed a commit to daivinhtran/rules_rust that referenced this issue Jan 17, 2024
daivinhtran pushed a commit to daivinhtran/rules_rust that referenced this issue Jan 17, 2024
Drop import macro (bazelbuild#2411)

As discussed over at
bazelbuild#2383

Fix rustfmt toolchains when consuming rules_rust with bzlmod. (bazelbuild#2410)

Fixes bazelbuild#2260

Provide a better error message when trying to generate rust-project.json (bazelbuild#2196)

Currently when trying to generate a `rust-project.json`, if there aren't
actually any Rust targets defined, the script mysteriously fails.

This adds a better error message.

Update android example to use Starlark version of android_ndk_repository (bazelbuild#2417)

The native version of `android_ndk_repository` rule no longer work with
the newer ndk versions.

When I set `ANDROID_NDK_HOME` to
`/usr/local/vinhdaitran/Android/Sdk/ndk/26.1.10909125`, the rule expects
a different structure from the Android NDK path.
```
ERROR: /usr/local/vinhdaitran/github/rules_rust/examples/android/WORKSPACE.bazel:67:23: fetching android_ndk_repository rule //external:androidndk: java.io.IOException:
Expected directory at /usr/local/vinhdaitran/Android/Sdk/ndk/26.1.10909125/platforms but it is not a directory or it does not exist.
Unable to read the Android NDK at /usr/local/vinhdaitran/Android/Sdk/ndk/26.1.10909125, the path may be invalid. Is the path in android_ndk_repository() or ANDROID_NDK_HOME set correctly?
If the path is correct, the contents in the Android NDK directory may have been modified.
```

Using the Starlark version of the rule, as recommended in
https://bazel.build/reference/be/android#android_ndk_repository, fixes
the issue.

cc: @keith

Allow ~ in repository names (bazelbuild#2427)

Fixes bazelbuild#2426

Prepare rust rules for Starlark CcToolchainInfo. (bazelbuild#2424)

bazelbuild#2425
@jfirebaugh
Copy link
Contributor

It wasn't immediately clear to me from the discussion above, so for anyone else who may be hitting this issue when trying to upgrade to Bazel 7: it's fixed in 0.38.0.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug import Issues related to //util/import
Projects
None yet
Development

No branches or pull requests

7 participants