rules_swift_package_manager
rules_swift_package_manager copied to clipboard
Support depending on Bazel modules which also use rules_swift_package_manager
Use case
External repository
I have an external repository: External which is built using SPM. To support Bazel as well, the repository uses rules_swift_package_manager to generate BUILD files for its dependencies and its products. These dependencies are generated into the External repositories MODULE.bazel file using the gazelle plugin.
External has two dependencies: Foo and Bar.
Client repository
I have a repository: Client which is built using Bazel. I'd like to depend on External since it provides a functional MODULE.bazel.
Client has two dependencies: Foo (same as External) and External
I add a bazel_dep(name = "External") to Clients MODULE.bazel. I use Externals public targets via @External//:Target.
The version in External/Foo does not conflict with Client/Foo and is resolved correctly, ideally with as little duplication as possible.
Current issues
This currently fails to resolve at all with the following error:
Error in repository_rule: A repo named swiftpkg_{PACKAGE_NAME} is already generated by this module extension at /private/var/tmp/_bazel_{USER}/{HASH}/external/rules_swift_package_manager~0.21.0/swiftpkg/bzlmod/swift_deps.bzl:31:22
ERROR: error evaluating module extension swift_deps in @rules_swift_package_manager~0.21.0//:extensions.bzl. Type 'bazel help mod' for syntax and help.
checking cached actions
Solution
TODO
A current workaround: instead of using MODULE.bazel depend on this via Package.swift and use the gazelle plugin to generate MODULE.bazel use_repo delcartions.
@cgrindel What are your thoughts on this issue and how to move it forward? Would the simple workaround of just suffixing the repo with the Bazel module name be enough? I imagine that would also break a lot of build files that depended on @swiftpkg
I think that we need SPM to resolve the deps. So, I don't think prefixing the names will be enough. If we don't we could end up with duplicate symbol errors in Swift.
Perhaps, we can come up with a way for a Bazel module to declare itself and its direct deps to the root workspace and then have the root workspace generate a temporary Package.swift that is used for SPM resolution. However, this would ignore any Bazel-specific functionality that you might have in the Bazel module that you are providing as a Swift package. 🤔
In short, I don't have any good ideas on this, right now.
@luispadron A couple of questions:
Is there a publicly available repository that we can reference as a real-world example?
Is the Package.swift for theExternal repository a minimal one (i.e., what rspm needs) or can it build the project? In other words, can a regular Swift package consume External?
Interesting and possibly related conversations / issues:
- https://github.com/bazelbuild/bazel/issues/19055
To implement this, we would want to convert each Swift package to a Bazel module. Today, we generate repositories and build files which is close but not a complete module. If we went this route, we would need to figure out how the root module would load these generated, on-the-fly, Bazel modules.
I think that we would need to generate a Bazel module for every requested version for every Swift package. Then, Bazel's version selection logic would select the version to use. 🤔
@cgrindel I like the generate Bazel modules idea and it works for folks who'd like to use SPM as the source of truth (because they primarily have downstream SPM users) but would like to also support Bazel (without maintaining two sources of truth). This allows Bazel users who are not using rules_swift_package_manager to use the module. It also would make adding Swift packages to the Bazel registry easier.
Some questions/thoughts on implementation:
- It would need to be flexible enough to support custom Bazel rules and deps being added to the
MODULE.bazel/workspace. - How would these generated Bazel modules be made, can that be done via an bzlmod extensions?
Keith asked about generating modules. Answer: No. I mean generating them during the repository load. We could still generate them using a separate utility.
How would these generated Bazel modules be made, can that be done via an bzlmod extensions?
Based upon the link that I just posted. No.
Just an FYI that this issue was a blocker for me adopting rules_swift_package_manager.
@ileitch Which Swift package do you use that is also a Bazel module?
My aim was to add Bazel module support to https://github.com/peripheryapp/periphery, however a key place I tried to use it is a private iOS app already using rules_swift_package_manager. Essentially the same scenario described in the original issue.