Package Names in Swift 5.2

I’m worried I’m losing my mind. Can someone else confirm? What is the correct spelling of what used to be done like this?:

.product(name: "SwiftSyntax", package: "swift-syntax")

With Swift 5.2, that still works on the command line with swift build, but when I open Xcode 11.4, I get this error:

product dependency 'SwiftSyntax' in package 'swift-syntax' not found

Changing it to this does not help:

.product(name: "SwiftSyntax", package: "SwiftSyntax")
unknown package 'SwiftSyntax' in dependencies of target 'MyModule'
2 Likes

Actually it was swift package describe that worked.

swift build hits the same two errors.

Supposedly giving a name to the package in your dependency list helps these situations, using the .package(name:url:_:) or .package(name:url:from:) methods

5 Likes

You’re right and I knew that, at least in theory. I shouldn’t be trying to work when I’m so tired.

I understand why this change was made, but gosh it made writing more complicated Package descriptions a bit of a nightmare.

6 Likes

I mostly just confused myself because I was off on a rabbit trail.

Until 5.1, SwiftPM had a bug where you needed to call the package by its last URL component instead of its declared name. (Hence the first example above.) I knew it had been fixed in master, but I wasn’t sure which release it would end up in. So when I updated to 5.2, the first thing I did was experiment to see which I needed to be using now. The old was now correctly failing (it was relying on a bug), but since I hadn’t updated the tools‐version yet, SE‐0226 had not even entered my mind. I had already forked several repositories to “repair” their names and make them usable by the time I saw @Mordil’s post and did a facepalm. (Thanks for replying so quickly, @Mordil)

If I weren’t tracking the development of SwiftPM so closely, I likely wouldn’t have made the mistake in the first place. I don’t think it will confuse the average user, but this thread can stick around in case it does. The complete solution is this:

// Add the name parameter to the package dependency:
.package(
  name: "SwiftSyntax",
  url: "https://github.com/apple/SwiftSyntax",
  .exact(Version(0, 50200, 0)
)
// And use the name in the target dependency:
.product(name: "SwiftSyntax", package: "SwiftSyntax")
2 Likes

Is this expected behavior if the library's Package.swift has a name defined for the package? It seems REALLY weird to me that you need to redefine this if it's already defined in the package manifest, and in practice I'm only seeing some libraries (including mine :sob:) that aren't having this picked up automatically.

I even tried changing the name of my package and while the Package.resolved picks up the new name, I'm still getting the Unknown package ____ error message.

To add insult to injury, if I comment out the .product(name: "Thing", package: "PackageNameDefinedInPackageDotSwift") line, the error goes away and I get the warning dependency "PackageNameDefinedInPackageDotSwift" is not used by any target. :upside_down_face:

Is this expected behavior if the library's Package.swift has a name defined for the package?

If the name is different than the URL (e.g. SwiftSyntax vs https://github.com/apple/swift-syntax, then the dependency declaration now needs the name. When both are the same, you can leave out the name, and SwiftPM will derive the name from the URL.

It seems REALLY weird to me that you need to redefine this if it's already defined in the package manifest

The whole point is that SwiftPM doesn’t need to fetch and load a dependency just to figure out whether or not it actually needs that dependency for the task you asked it to do. That allows SwiftPM to short‐circuit a lot of unnecessary work that it used to do.

You can read more about it in SE‐0226. (Sorry, my last link pointed in the wrong place.)

Where what you're saying falls apart for me is that at least the Package.swift for my library is getting pulled to the extent that the name defined there is showing up in the executable's Package.resolved.

Although...I have to comment out the .product which uses it in order to get the packages to resolve it all, so maybe it's an order-of-operations issue?

Either way, it still seems fragile to me to have that defined both in the library's Package.swift and then in each user's executable Package.swift.

1 Like

SE-0226 allows SwiftPM to know which dependencies are used by which targets, without pulling those dependencies. This allows, for example, an optimization to disregard test-only dependencies from non-root packages. And there are more optimizations that can come in the future. The proposal explains this in more detail.

Can you explain what you mean by that? If you mean that the name has to be redefined, that should not be necessary when it is the same as the repository name.

+1

Understood. But why should such internal optimisation decision affect the surface area of a declarative API?

1 Like

Since SE-0226 is aiming to not even resolve unneeded dependencies, the information needs to be provided in another way. I think we discussed at the time that in the future, a package index could provide this bit of information and at that point we could walk back this requirement.

I see. Thanks for making this clear. I'd love to start contributing back to the open source effort if I can. Maybe trying to help roll back this requirement could be a starting point for me? Could you (or anyone) point me in a direction where I can learn more? Also (for the long term), is/was there a discussion on making package/target/product names type safe (i.e. non-stringy)? Is that even a practical option?

1 Like

To be clear, we just introduced this in 5.2 and today we don't have a package index at all, so this is something that can only happen at a later point in the future.

I ran into the same problem. Is there a good solution?

I have to use .package(name:url:_:)

The solution is the one you showed - fully qualify the package name. I wrote about the differences for all the different scenarios here which hopefully explains it for you