Skip to content

Support rules_swift_package_manager usage in non-root modules #769

@luispadron

Description

@luispadron

Summary

Depending on non-root bzlmod modules that use rules_swift_package_manager currently causes collisions when multiple modules declare the same swiftpkg_* repositories. This blocks scenarios where Bazel rules expose Swift-based tools with their own SPM dependencies, and it prevents clean composition when both root and transitive modules use rules_spm. A mechanism is needed in the rules_spm bzlmod extension to reconcile these declarations and define a coherent resolution model.

Proposals

  • Single-version resolution: via merged Package.swift (preferred)
    The extension synthesizes a unified Package.swift by treating each module’s declared packages as local-package dependencies (.package(path:)). SwiftPM is then invoked once to resolve the entire dependency graph, producing a single authoritative set of package versions. This avoids duplicate repositories, aligns with how SPM resolves dependencies outside of Bazel, and ensures deterministic version selection across all bzlmod modules. The merged result can be surfaced through a generated Package.resolved-like artifact, enabling stability and caching or we can see if this all just works with Bazel's extension_metadata. The downside are: more complex extension logic to merge Package.swift, need to surface errors in a clear way to understand where resolution issues happen, Package.resovled for the root module either no longer exists or is not strictly related to Package.swift

  • Multi-version resolution: by allowing per-module Package.swift. Each bzlmod module continues resolving its Package.swift independently. The extension generates repository names that encode the module identity (e.g., swiftpkg_modname_argument_parser) to avoid collisions. This avoids enforcing a single global version across modules but intentionally permits multiple copies of the same package at different versions. The downside are: multiple repositories for the same Swift package and no guarantee of a unified dependency graph, additionally this doesn't match how SPM does resolution (single-version).

Breaking Changes

swift_package and swift_deps_info would no longer be defined automatically in from_package; they would instead be declared as development dependencies via a new extension API.

Existing users of rules_swift_package_manager would need to update their module configurations (e.g., adopting the new swift_dev_deps extension).

A major-version bump (likely 2.x) would be required due to shifts in repository naming, dependency declaration semantics, and resolution behavior.

Example

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions