7

I have 2 local Swift Packages: LibA and LibB. Both LibA and LibB depends on a same framework(AmazonIVSPlayer). I want to add both of the into my Project but I got the below error:

Multiple targets named 'AmazonIVSPlayer' in LibA and LibB

the Package.swift of both libraries are like below:

import PackageDescription

let package = Package(
    name: "LibA",
    products: [
        // Products define the executables and libraries a package produces, and make them visible to other packages.
        .library(
            name: "LibA",
            targets: ["LibA","AmazonIVSPlayern"]),
    ],
    dependencies: [
        // Dependencies declare other packages that this package depends on.
        // .package(url: /* package url */, from: "1.0.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 this package depends on.
        .target(
            name: "LibA",
            dependencies: []),
        .binaryTarget(
            name: "AmazonIVSPlayer",
            url: "https://player.live-video.net/1.8.1/AmazonIVSPlayer.xcframework.zip",
            checksum: "8256f9f580fdb09b156afad43cd17dd120091c794e848b27aad83c1a098ecc7f")
    ]
)

I read

  1. Swift Package Manager: "multiple targets named..."
  2. Swift Package Manager (SPM) and Cocoapod Dependency Conflict
  3. Swift packages and conflicting dependencies
  4. https://forums.swift.org/t/multiple-target-issue-with-spm/16696
  5. https://www.reddit.com/r/swift/comments/d4wwbk/question_about_dependency_conflicts_in_swift

Since none of them offer any solution and all posts are old, I am wondering is there any new way to solve this issue?

Hamed Ghadirian
  • 6,159
  • 7
  • 48
  • 67

3 Answers3

3

The error you are getting indicating that you are using two products that have module that conflicts with another products module name. The solution you could try:

  1. If the module causing the name conflict are same (contain the same code and files), then you can create a separate package for the module, in this case a separate package for AmazonIVSPlayer could be created:

    import PackageDescription
    
    let package = Package(
        name: "AmazonIVSPlayer",
        products: [
            .library(
                name: "AmazonIVSPlayer",
                targets: ["AmazonIVSPlayern"]),
        ],
        dependencies: [],
        targets: [
            .binaryTarget(
                name: "AmazonIVSPlayer",
                url: "https://player.live-video.net/1.8.1/AmazonIVSPlayer.xcframework.zip",
                checksum: "8256f9f580fdb09b156afad43cd17dd120091c794e848b27aad83c1a098ecc7f")
        ]
    )
    
  2. Alternatively, you can combine the package manifest of LibA and LibB into a single package and expose both of them as multiple products:

    import PackageDescription
    
    let package = Package(
        name: "LibAB",
        products: [
            .library(
                name: "LibA",
                targets: ["LibA","AmazonIVSPlayern"]),
            .library(
                name: "LibB",
                targets: ["LibB","AmazonIVSPlayern"]),
        ],
        dependencies: [],
        targets: [
            .target(
                name: "LibA",
                dependencies: []),
            .target(
                name: "LibB",
                dependencies: []),
            .binaryTarget(
                name: "AmazonIVSPlayer",
                url: "https://player.live-video.net/1.8.1/AmazonIVSPlayer.xcframework.zip",
                checksum: "8256f9f580fdb09b156afad43cd17dd120091c794e848b27aad83c1a098ecc7f")
        ]
    )
    
  3. Now for the scenarios where both modules are actually different, with swift 5.7 you will be able to differentiate them with module aliases. So with your current package description, when consuming:

    targets: [
      .executableTarget(
        name: "App",
        dependencies: [
          .product(name: "LibA", package: "LibA"),
          .product(name: "LibB", package: "LibB", moduleAliases: ["AmazonIVSPlayer": "AmazonIVSPlayerFromLibB"]), 
        ])
    ]
    

    When importing module you have to provide the alias name that you have specified:

    import AmazonIVSPlayer // imports from LibA
    import AmazonIVSPlayerFromLibB // imports from LibB
    
Soumya Mahunt
  • 2,148
  • 12
  • 30
1

I am also searching for a solution for this problem. The only way I found to work around this, is to create a git repository, put the xcframework (in your case AmazonIVSPlayer) there and a Package.swift. The Package.swift in the newly created repo would look like that:

let package = Package(
    name: "AmazonIVSPlayer",
    products: [
        .library(
            name: "AmazonIVSPlayer",
            targets: ["AmazonIVSPlayer"]
        )
    ],
    targets: [
        .binaryTarget(name: "AmazonIVSPlayer", path: "AmazonIVSPlayer.xcframework")
    ]
)

Then remove the binaryTarget from LibA and LibB and add the following to the dependencies:

.package(url: "https://github.com/foo/bar.git", from: "1.8.1")

Don't forget to create a tag for the version number.

Then add the following to the target dependencies:

.product(name: "AmazonIVSPlayer", package: "bar"),

That way you can use AmazonIVSPlayer in LibA and LibB and can add both Libs to the same project without getting an error. Not the easiest solution, but the only one which works for me.

Apfelsaft
  • 5,766
  • 4
  • 28
  • 37
0

I've just edited project.pbxproj, and find the target that has the framework added with SPM inside packageProductDependencies list, and I've copied that line to the target that's missing that.

Something like:

    name = "Target 1";
        38D300792549B0C600FDEFA8 /* UIKit Extensions */,

Copied that line of the framework in the other target

    name = "Target 2";
        38D300792549B0C600FDEFA8 /* UIKit Extensions */,
southfox
  • 321
  • 5
  • 16