cgrindel / rules_swift_package_manager

Collection of utilities and Bazel rules to aid in the development and maintenance of Swift repositories using Bazel.
Apache License 2.0
74 stars 29 forks source link

Support depending on Bazel modules which require the same dependencies #769

Open luispadron opened 11 months ago

luispadron commented 11 months ago

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
luispadron commented 11 months ago

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.

luispadron commented 11 months ago

@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

cgrindel commented 11 months ago

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.

cgrindel commented 10 months ago

@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?

cgrindel commented 10 months ago

Interesting and possibly related conversations / issues:

cgrindel commented 9 months ago

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. 🤔

luispadron commented 9 months ago

@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:

cgrindel commented 9 months ago

Keith asked about generating modules. Answer: No. I mean generating them during the repository load. We could still generate them using a separate utility.

cgrindel commented 9 months ago

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.

ileitch commented 2 months ago

Just an FYI that this issue was a blocker for me adopting rules_swift_package_manager.

cgrindel commented 2 months ago

@ileitch Which Swift package do you use that is also a Bazel module?

ileitch commented 2 months ago

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.