How to specify a .product dependency from a particular package dependency in .target in Package.swift using SwiftPM

I want to include the SPMUtility library of the Swift Package Manager (SPM) project as a dependency to my project "ngfz". In doing this, I encounter several problems.

First and foremost, how to I see the list of available semver versions of the SPM project to specify in:

...
dependencies: [
        // Dependencies declare other packages that this package depends on.
        .package(url: "https://github.com/apple/swift-package-manager.git", from: "0.3.0"),
    ]
...

I cannot find this information on the Github page?

Secondly, the SPM documentation says that I should specify a product dependency for my target, optionally including the package name:

.target(
       name: "ngfz",
       dependencies: [
               .product(name: "SPMUtility", package: "SwiftPM") 
       ]),

However, results in the following error:

swift build --product nfgz

'ngfz' /Users/nlykkei/Projects/ngfz: **error:** product dependency 'SPMUtility' in package 'SwiftPM' not found

If I instead remove package: "SwiftPM" from the .target above, then everything works fine, and the dependencies display as follows:

swift package show-dependencies
.
ā””ā”€ā”€ SwiftPM<https://github.com/apple/swift-package-manager.git@0.4.0>
    ā””ā”€ā”€ llbuild<https://github.com/apple/swift-llbuild.git@0.1.1>

So, why can't I specify .product(name: "SPMUtility", package: "SwiftPM") in the .target?

I hope to get the following answered:

  1. How do I see the available semver versions of the SPM project to specify in from: "0.3.0"?
  2. How do I specify the package dependency in .product(name: "SPMUtility", package: "SwiftPM")?

The complete (and working) Package.swift file:

// swift-tools-version:5.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "ngfz",
    products: [
        .executable(
            name: "ngfz",
            targets: ["ngfz"]),
    ],
    dependencies: [
        // Dependencies declare other packages that this package depends on.
        .package(url: "https://github.com/apple/swift-package-manager.git", from: "0.3.0"),
    ],
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages which this package depends on.
        .target(
            name: "ngfz",
            dependencies: [
                .product(name: "SPMUtility") 
            ]),
        .testTarget(
            name: "ngfzTests",
            dependencies: ["ngfz"]),
    ]
)
git ls-remote --tags https://url.of/The/Repository

Oddly product(name:package:) does not actually need the name specified in the package manifest, but rather the name of the repository directory in its URL, so for SwiftPM, the declaration would be:

.product(name: "SPMUtility", package: "swift-package-manager")

SwiftPM is not very clear about which of the two (declared name or directory name) it is willing to accept in different places in its API. Always try the opposite one if something doesnā€™t work the way you expect.

This particular case (selecting a product) seems very counterā€intuitive to me. @Aciid, is there some way this could be mitigated?

1 Like

@SDGGiesbrecht

if the package define with additional version params like from, i can't define the dependency definition like above, any idea ?

.package(url: "https://github.com/pointfreeco/swift-case-paths.git", from: "0.1.0"),
dependencies: [
   .product(name: "CasePaths", package: "swift-case-paths")
]

error
/Users/nakama/code/xcode-project-gen/Package.swift: dependency 'CasePaths' in target 'TKPDGen' requires explicit declaration; provide the name of the package dependency with '.package(name: "CasePaths", url: "https://github.com/pointfreeco/swift-case-paths.git", from: "0.1.0")'

@wendyliga the name of the package is CasePaths (according to that error message) so you need to specify the name in the dependency's array. I wrote about the reasons at Understanding Swift Packages and Dependency Declarations | Tim Condon

1 Like

nice article, thanks @0xTim. everything looks fine now

Also, Iā€™m pretty sure this is out of date and no longer true.

Great article @0xTim, very helpful. I recently solved an issue where I had to resolve dependencies with a local package that had multiple targets!

Saved me!