-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Bzlmod: allow repos to be visible to other module extensions #19301
Comments
FWIW, I encountered a similar situation when attempting to modularize Kythe. We depend on https://github.com/google/brotli from both C++ and Go. The Go module also depends on the C++ library, but that library can't be handled directly by Go. In order to accomplish this, I had to patch the BUILD file to use the canonical repo path to the non-modular C++ repository. Were that repository to be a modular dependency, this gets really fiddly and flaky. Similarly, any kind of shared dependency that needs to bridge external package managers becomes challenging without someway of making that dependency known and available to the language-specific module extension. |
While this doesn't help in the general case, in the Go case you can just add the Go module with patches to the BCR as a Bazel module and But I fully agree we need something more flexible and generally applicable to add the repo mapping entries for patches. |
This can work as long as the Similar for @shahms, as long as you make sure the tag attribute has type "label", you should be able to pass that label around (in a capability-passing fashion, almost). |
@shahms use case, which is similar to bazelbuild/rules_python#48 (comment), also requires a way to reference this label from (patched) BUILD files. I can think of three ways to make this work:
|
I found a fourth option that I currently like best: |
So IIUC the capability is there (using label-typed attributes), just the usability is really bad because the user needs to somehow translate a BUILD file patch containing single- Assuming that it is, I'm sympathetic to the concern and agree that we should have a better story for this use case. But first I wanted to make sure we're aware of a specific technical challenge, which is that any "repo mapping injection" we do is subject to conflicts. Suppose Now, going over @fmeum's suggestions:
The "reverse use_repo"/"make_visible_to" idea brought up in the other thread also suffers from the injection conflict problem, but has the advantage of being more ergonomic -- no funny label business. To mitigate the injection conflict problem, I wonder if we can limit the scope of an injected repo mapping to select repos generated by the extension. Essentially this would be bringing back the But wait, isn't that #17493 (comment), where you said this was infeasible?? Well, not quite -- the This approach still requires the user to "expose" a repo to an extension via a label (a capability), but then the extension can decide smartly what to do with that capability. Admittedly usability still isn't great; we could repurpose the "make_visible_to" idea to improve usability ( |
In the internal team discussion we had on how to pin a module extension generated repo, instead of using
If we only use the repo mapping functionality alone, for the go use case, it would be:
|
@bazel-io fork 7.1.0 |
This still needs some design work, so it's unlikely to happen for 7.1.0. Punting to 7.2.0 for now. |
This is made possible by a refactoring that moves the label parsing of `RepoSpec` attributes coming from module overrides as well as `.bzl` file labels containing repo rules from `BzlmodRepoRuleFunction` into `ModuleFileGlobals`. Also adds a TODO to `BzlmodRepoRuleFunction` to further simplify the logic after the next lockfile version bumps, as old lockfiles are now the only source of non-canonical labels in `RepoSpec`s. Work towards #19301 Closes #21188. PiperOrigin-RevId: 605517195 Change-Id: Id34c81fa9474fef2354ff1fbc898e518a9044640 Co-authored-by: Fabian Meumertzheim <fabian@meumertzhe.im>
I was blocked by the similar issue. The protobuf require python toolchain for compiling. With legacy WORKSPACE: # .bazelrc
build --define=use_fast_cpp_protos=true # WORKSPACE
load("@rules_python//python:repositories.bzl", "python_register_toolchains")
# Register toolchain for hermetic build
python_register_toolchains(
name = "python_3_9",
python_version = "3.9",
)
# Use bind to override the //external: python_headers used in protobuf repo
bind(
name = "python_headers",
actual = "@python_3_9//:python_headers",
)
http_archive(
name = "com_google_protobuf",
# XXXX
) Now the newest protobuf in BCR adapt for bazlmod by replacing use of # MODULE.bazel
python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.toolchain(
configure_coverage_tool = True,
is_default = True,
python_version = "3.9",
)
use_repo(python, "python_3_9")
bazel_dep(name = "protobuf", version = "23.1", repo_name = "com_google_protobuf")
# !!!!!!!!!!! How to let the protobuf module adapt my registers python toolchain? !!!!!!!!!!!! Any help will be appreciate, thanks. |
I just found out my build ERROR is caused by pybind/pybind11_bazel#57 (comment) |
This seems like a fatal flaw for rules_go users, in the sense that bzlmod requires me to go visit the BUILD files of any Go package I depend on, and alter them to conform to the strict repo visibility semantics. @Wyverald is it still on-track for 7.2? |
Yes. Current plan is to do #19301 (comment). Does that address your concern? |
It looks to me like that proposal still requires that users of a go dependency will have to include workarounds in their MODULE.bazel file? Or will rules_go be able to use that API internally such that every repository it generates works correctly? Probably a question for @fmeum |
Sorry, I missed this part -- this doesn't sound like it would be addressed by the comment I linked. What is this problem, actually? Does it coincide with any of the other comments in this thread? I don't quite understand why you need to change other BUILD files. |
While writing a module extension that instantiates repos with user-supplied BUILD files, I used the following replacement for
|
Workaround for bazelbuild/bazel#19301
FYI in the upcoming Gazelle release, there is a new workaround for this issue bazelbuild/bazel-gazelle@7d10bf7 Using the new mode, for a go_repository, gazelle will wipe all existing BUILD files and generate them new from scratch. This ensures that only MODULEs that are relevant to go builds are included in each BUILD file. The fix is not ideal, but should address most simple cases in the Go ecosystem. I hope Bazel 7.3 release will provide a solution to this madness. |
If we decouple "overriding a repo definition" from "modifying a repo's repo mapping", we may be able to realize a cleaner API for the latter. This is a concept with different pros and cons: use_repo(some_ext, my_repo_a = "repo_a")
use_repo(other_ext, my_repo_b = “repo_b”, my_repo_c = "repo_c")
repo_mapping_override(
"my_repo_a", # required positional argument
“my_repo_b”, # extra positionals
io_bazel_repo_c = "my_repo_c", # extra keyword arguments
)
# vs.
repo_override(
repo_name = "my_repo_a",
additional_repo_mapping = {
"my_repo_b": "my_repo_b",
“io_bazel_repo_c”: “my_repo_c”,
},
) Pros I see compared to the
Cons:
Generally speaking, I find the |
Does this mean we'd need to introduce two new directives? One for repo definitions, one for repo mappings? (Since as we discussed elsewhere, I don't think we should reuse But now that I think about it, we could actually do this decoupling and make "modifying a repo's repo mapping" work on a per-extension level. The "overriding a repo definition" part simply becomes "define a repo using any mechanism, be it This even works around the "con" you named, since the first argument would just be the extension proxy object. So, for Yun's earlier example: # This earlier example:
ext = use_extension("//:extension.bzl", "my_extension")
ext.bar(name = "bar", ...)
use_repo(ext, "bar")
repo_override(
repo_name = "bar",
repo_class = "local_repository",
attrs = {"path": "./third_party/bar"},
# If the overridden version requires additional repo mappings, users can fix them here.
# The key is the apparent repo name seen by bar, and the value is the apparent repo name seen by the root module.
additional_repo_mapping = {"baz": "my_barz"}
)
########################
# ... would become:
local_repository = use_repo_rule("@bazel_tools//:blah.bzl", "local_repository")
local_repository(name="my_own_bar", path="./third_party/bar")
ext = use_extension("//:extension.bzl", "my_extension")
ext.bar(name = "bar", ...)
repo_override(ext, bar="my_own_bar", baz="my_barz") One extra good thing: You don't need to One debatable thing: Is applying a repo mapping override across all repos in an extension actually desirable? In other words, can we claim "it's never a good idea to override repo mappings for some but not all repos generated by an extension"? I think the answer is yes, but I'm happy to be convinced otherwise. |
@Wyverald I like this idea.
IIUC, this basically means the old repo is completely replaced by the new one and won't be visible to anyone, right? If so, it's essentially the same the old repo_override, but with a much cleaner API. I do tend to agree it's a much more common case to override a repo for everyone than for a specific repo. |
Syntax-wise To clarify your idea, is it that Assuming that is the case, I have some concerns:
I could see cases where someone would want to override the mapping for a single repo (e.g. have one particular Go dependency link against a particular OpenSSL version, without affecting any other Go deps), but I don't think that's common enough to make the API for it more complicated. There is also always a workaround, assuming the module extension allows applying patches: You can first patch the references in the one extension repo to refer to a unique, new repo name and then inject a repo mapping entry for it. This seems acceptable for the rare cases in which one would need this and module extensions usually support patches. It's even more transparent since future readers of the BUILD files do not need to keep in mind that the same label may resolve to different labels in different extension repos. |
There is another type of reference which a |
OK, so it looks like the biggest "hole" in this new idea is that the overridden repo is still accessible through its original canonical name. This hole is rather hard to plug, since we'd need some sort of repo-level alias (#19927) for this to work. (The idea being that the overridden repo's canonical name aliases to the overriding repo's canonical name.) While this is easy to do on a surface level (just make a symlink), the proper fix for this is nigh impossible (involves making labels compare equal while cognizant of repo-level aliases). We could work around this issue in the "
While that's true, I'm still kind of sympathetic to the "patching MODULE.bazel with |
Does that mean we have this plan?
This looks good to me (and doable in time for 7.4.0/8.0.0) |
SGTM. One last bikeshed for the road: I'd prefer the name |
Description of the feature request:
In certain situations, there exists a need to have a module extension be able to have visibility of repositories that are created by other module extensions.
Let's take
go_sdk
module extension for example inrules_go
.I have some repo declared locally in the main module, say for example
@go_sdk_linux_amd64
is the name of the repo.Now, I want to have the
go_sdk
module extension load this with something that is similar to theWORKSPACE
repository rulego_wrap_sdk
: (https://github.com/bazelbuild/rules_go/blob/master/go/private/sdk.bzl#L372-L391)The issue here, is that if I make a tag (for example
go_sdk.wrap(name = "@go_sdk_linux_amd64")
, the build will fail because the module extensiongo_deps
doesn't see the repo @go_sdk_linux_amd64Which category does this issue belong to?
No response
What underlying problem are you trying to solve with this feature?
The ability to use a repo that is declared in the main module in a call to a module extension that is externally declared.
Which operating system are you running Bazel on?
Linux
What is the output of
bazel info release
?release 6.3.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 master; git rev-parse HEAD
?Have you found anything relevant by searching the web?
No response
Any other information, logs, or outputs that you want to share?
No response
The text was updated successfully, but these errors were encountered: