module.is_root is turning bzlmod into yet another WORKSPACE #22024
Replies: 8 comments 18 replies
-
Thanks for raising this discussion. I do see great potential for Bazel working well as a meta build system in this way, but I think that this kind of modularity can only be realized if we properly design the domain-specific interactions. I think that the ultimate root cause of the type of problem you are seeing is that "toolchains are like WORKSPACE": Most toolchains are highly configurable, making different versions hard to reconcile, and registrations have "first registered wins" semantics. Many module extensions, apparently including rules_rust and also toolchains_llvm, have taken the A pattern that I could see working here is to:
This sidesteps the issue of reconciling toolchain requirements by multiple transitive dependencies while still allowing rulesets to use Rust tools without manual setup required from the root module. Would that work in your case? @illicitonion @UebelAndre in case they want to provide their input on this.
While that works in your particular example, it looks to me as if this would stop working in the typical diamond situation with dependency chains A -> B -> rules_rust and A -> C -> rules_rust. This is an example of what I described above: If B and C have opinions about Rust toolchains, it's essentially impossible to reconcile them automatically. Instead, either A is tasked with defining a toolchain (the current situation) or rules_rust provides a toolchain good enough for B and C and tunable by A if desired (the "improved" approach described above).
While it's true that module extensions can currently only query the BFS order of modules using them and not the dependency edges between them, I'm not sure whether this extra information is what extensions are missing to become more modular: It already seems difficult to reconcile the fully featured toolchain requirements of two module that aren't comparable with respect to this partial order. I would rather think that domain-specific information or restrictions (say, editions/language versions/etc. instead of arbitrary toolchain features) could help do better here (say use Minimum Version Selection on the toolchain versions). |
Beta Was this translation helpful? Give feedback.
-
cc @matts1 who probably has the most context here, and introduced this requirement in bazelbuild/rules_rust#2021 including this snippet: # Toolchain configuration is only allowed in the root module.
# It would be very confusing (and a security concern) if I was using the
# default rust toolchains, then when I added a module built on rust, I was
# suddenly using a custom rustc.
root = _find_root(module_ctx)
if not root:
fail(_TRANSITIVE_DEP_ERR % module_ctx.modules[0].name) |
Beta Was this translation helpful? Give feedback.
-
I definitely understand your issues with it. I do also take issue with it, but I don't currently have any ideas that can improve on it - I'm open to suggestions. I believe that the biggest problem with To me, there were pros and cons of doing it either way. I'll outline a few of them: Pros of explicitly doing it in root workspace:
Pros of implicitly using the toolchain from the modules that you depend on:
The minimum version selection on the toolchain versions is an interesting idea, and might work for simpler use cases, it starts failing when you do anything more complex.
I think my conclusion is that what you're suggesting would indeed make things slightly simpler for the simple use cases, but it'd make things much harder for the more complex use cases. I personally don't think the tradeoff is worth it, but if anyone has suggestions that make this easier. FWIW, in rules_rust, we only allow the root module to configure the toolchain, but IIRC there is a default configuration. So you should just need to register that default toolchain. I haven't ever tried your use case, so I'm not actually too familiar with how it currently works. |
Beta Was this translation helpful? Give feedback.
-
We hit this issue in rules_jsonnet in the following PR. Our goal is to allow users to use either a Go, Cpp or Rust based Jsonnet The PR introduced Rust, and thus also rules_rust to be able to compile it.
Unfortunately this behaviour blocks us from merging the PR, because we don't I understand that the current setup in rules_rust is a sane default, as this
We're open to a temporary solution that allows us to move forward with |
Beta Was this translation helpful? Give feedback.
-
I converted this to a discussion since it's not really a Bazel issue. |
Beta Was this translation helpful? Give feedback.
-
So I've been thinking about this, and here's what I think could be a set of reasonable policies: Every module that defines a new toolchain type must also register a non-dev default toolchain for that toolchainRules_rust introduces toolchain types for If a project defines a new toolchain for which the toolchain type was defined by another module, it must register it as a dev toolchainIf my project uses rules_rust, it may register its own custom rust toolchain. However, it must do so by invoking The toolchain configuration of a toolchain may only be affected by the module defining said toolchain type, and the root moduleThat is, if a user in
In practice, this means that any toolchain module extension should look like:
Enforcement@meteorcloudy How would you feel about adding a The third one seems difficult to enforce. |
Beta Was this translation helpful? Give feedback.
-
Hello, what is the conclusion here? Android kernel build is also using rust on android15-6.6, and we found it difficult to use if all users of the kernel build tools must also put a |
Beta Was this translation helpful? Give feedback.
-
It sounds like part of the conclusion here is that |
Beta Was this translation helpful? Give feedback.
-
Description of the bug:
Some time last week I migrated Buildbarn from WORKSPACE to MODULE.bazel. This process went smoother than I had expected up front, so kudos to the folks implementing this.
Unfortunately, I came to the conclusion that the MODULE.bazel approach still isn't as 'modular' as I had hoped.
Which category does this issue belong to?
No response
What's the simplest, easiest way to reproduce this bug? Please provide a minimal example if possible.
For example, let's create a toy project that uses rules_rust:
Now let's consider that some user wants to integrate this project into their organisation in the form of a tarball, so they create a Bazel project that looks like this:
When they try to build their tarball, they get presented with the following error message:
So now the user, who couldn't care less that my tool is written in Rust, needs to copy-paste code from the original MODULE.bazel file into their own project, and make sure that that code remains up to date. In my opinion this completely undermines the problem that MODULE.bazel was trying to solve. It adds unnecessary complexity when people try to use Bazel as a meta-build system for tying multiple projects together.
rules_rust isn't the only set of rules that has such weird restrictions. I have also observed this to be an issue with toolchains_llvm.
Which operating system are you running Bazel on?
All of them
What is the output of
bazel info release
?7.1.1
If
bazel info release
returnsdevelopment version
or(@non-git)
, tell us how you built Bazel.No response
What's the output of
git remote get-url origin; git rev-parse HEAD
?No response
Is this a regression? If yes, please try to identify the Bazel commit where the bug was introduced.
is_root was introduced here: #15815
Have you found anything relevant by searching the web?
No response
Any other information, logs, or outputs that you want to share?
In my opinion either one of the two following things needs to be done:
is_root
to returnTrue
if and only if it is the root of all modules that depend on a given module instead of the literal root of the project.is_root
and introduce a way where rules authors can compare modules along a partial order based on parent/child relationships.In my opinion archive_override and git_override should be given a similar treatment. Namely, it's completely valid for them to get ignored when declared in a child module when the parent also has a dependency on it. But ignoring it if none of the parents/siblings/... depend on it either? That's just cruel.
Beta Was this translation helpful? Give feedback.
All reactions