SPM dependency resolution: version vs. tag/branch

Hello,

I have a question about a dependency that cannot be resolved correctly by the SPM. The situation is as follows:

App => Vapor@3.0.0... => Console-Kit@3.0.0... => swift-log@1.0.0...
        => LogModel@master => swift-log@master

Context

I wanted to use the levels of swift-log in my LogModel. But for this Logger.Level must conform to Codable and so I opened the Pull Request which got merged. However, no version swift-log@1.1.2 was created for this (which I totally understand), so the dependency conflict described above has now occurred.

Minimal example

    // swift-tools-version:5.1
    import PackageDescription

    let package = Package(
        name: "Backend",
        products: [
            .library(name: "Backend", targets: ["App"]),
        ],
        dependencies: [
            .package(url: "https://github.com/apple/swift-log.git", from: "1.0.0"),  // just for the minimal example, otherwise vapor@3.0.0... => console-kit@3.0.0... => swift-log@1.0.0...
            .package(url: "https://github.com/PDF-Archiver/LogModel.git", .branch("master"))
        ],
        targets: [
            .target(name: "App", dependencies: ["Logging", "LogModel"]),
            .testTarget(name: "AppTests", dependencies: ["App"])
        ]
    )

Now the swift package update leads to the following error:

Updating https://github.com/PDF-Archiver/LogModel.git
Updating https://github.com/apple/swift-log.git
error: the package dependency graph could not be resolved; possibly because of these requirements:    https://github.com/apple/swift-log.git @ 1.0.0..<2.0.0

Question

I can understand that this configuration leads to a conflict. However, I want to ask if there is a solution. For example the forcing a specific dependency (here: "swift-log@master"). Because I think that this is a quite common scenario in the „OpenSource World“ and I could not find a solution for it.

Can anyone help me out with this problem?

In theory, this should already work since branch-based dependencies override version-based dependencies but the current resolver has a bunch of bugs. SwiftPM recently switched to a new resolver which behaves correctly in this example. For now, you should be able to work around the resolver bug by also adding .package(url: "https://github.com/apple/swift-log.git", .branch("master")) in your top-level package.

HI @Aciid,

thank you so much for your super quick response! I added the Vapor dependency to be as close as possible to my "real world" example und added .package(url: "https://github.com/apple/swift-log.git", .branch("master")) in my top-level package:

// swift-tools-version:5.1
import PackageDescription

let package = Package(
    name: "Backend",
    products: [
        .library(name: "Backend", targets: ["App"]),
    ],
    dependencies: [
        .package(url: "https://github.com/vapor/vapor.git", from: "3.0.0"),
        .package(url: "https://github.com/apple/swift-log.git", .branch("master")),
        .package(url: "https://github.com/PDF-Archiver/LogModel.git", .branch("master"))
    ],
    targets: [
        .target(name: "App", dependencies: ["Vapor", "Logging", "LogModel"]),
        .testTarget(name: "AppTests", dependencies: ["App"])
    ]
)

I got the same error and an additional warning (which I do not understand, since Logging is a dependency of "App"):

$ swift package show-dependencies
error: multiple products named 'Logging' in: Console, swift-log
error: multiple targets named 'Logging' in: Console, swift-log
warning: dependency 'swift-log' is not used by any target

And just in case ....

$ swift --version
Apple Swift version 5.1 (swiftlang-1100.0.270.13 clang-1100.0.33.7)
Target: x86_64-apple-darwin19.0.0

$ swift package tools-version
5.1.0

That error looks like you're running into Logging module name clash in Vapor 3. Unfortunately (for now at least) Vapor 3 isn't compatible with swift-log.

@Joe_Smith thank you. You are right! So lets decuple the vapor question from the initial question.

I created a TestLib with swift-log@1.0.0... and added .package(url: "https://github.com/apple/swift-log.git", .branch("master")) in my top-level package as @Aciid suggested:

// swift-tools-version:5.1
import PackageDescription

let package = Package(
    name: "Backend",
    products: [
        .library(name: "Backend", targets: ["App"]),
    ],
    dependencies: [
        .package(url: "https://github.com/apple/swift-log.git", .branch("master")),
        .package(url: "https://github.com/JulianKahnert/TestLib.git", .branch("master")),   // swift-log@1.0.0...
        .package(url: "https://github.com/PDF-Archiver/LogModel.git", .branch("master"))    // swift-log.git@master
    ],
    targets: [
        .target(name: "App", dependencies: ["TestLib", "LogModel"]),
        .testTarget(name: "AppTests", dependencies: ["App"])
    ]
)

Now I got this error (independent of swift-log in the top-level package):

$ swift package update
Updating https://github.com/JulianKahnert/TestLib.git
Updating https://github.com/PDF-Archiver/LogModel.git
Updating https://github.com/apple/swift-log.git
error: the package dependency graph could not be resolved; possibly because of these requirements:    https://github.com/JulianKahnert/TestLib.git @ master

I am a little confused now ...

What happens if you remove that dependency (which depends on swift-log at master )?

You could also try running swift package --enable-pubgrub-resolver update which uses a new dependency-resolution algorithm and has helped me understand conflicts thanks to its helpful error messages too.

1 Like

If I remove either

.package(url: "https://github.com/JulianKahnert/TestLib.git", .branch("master")),   // swift-log@1.0.0...

or

.package(url: "https://github.com/PDF-Archiver/LogModel.git", .branch("master"))    // swift-log.git@master

... everything is fine:

$ swift package update                          
Updating https://github.com/apple/swift-log.git
Updating https://github.com/JulianKahnert/TestLib.git
Completed resolution in 1.52s
Removing https://github.com/PDF-Archiver/LogModel.git

$ swift package update
Fetching https://github.com/PDF-Archiver/LogModel.git
Updating https://github.com/apple/swift-log.git
Completed resolution in 1.92s
Removing https://github.com/JulianKahnert/TestLib.git
Cloning https://github.com/PDF-Archiver/LogModel.git
Resolving https://github.com/PDF-Archiver/LogModel.git at master

But this is obviously no solution for my problem, since I need swift-log in both dependencies.

And the good news: swift package --enable-pubgrub-resolver update fixes the problem!

$ swift package --enable-pubgrub-resolver update
Updating https://github.com/PDF-Archiver/LogModel.git
Fetching https://github.com/JulianKahnert/TestLib.git
Updating https://github.com/apple/swift-log.git
Completed resolution in 3.27s
Cloning https://github.com/JulianKahnert/TestLib.git
Resolving https://github.com/JulianKahnert/TestLib.git at master

Is there any way to set the new resolver globally, e.g. also in Xcode?