Class <X> is implemented in both <Base.framework> and BaseTestSupport.framework>. One of the two will be used

Trying to run my applications unit tests I get the error

Class is implemented in both <Base.framework...> (0x103fa48e8) and <FotosBaseTestSupport.framework...> (0x10b9171b0). One of the two will be used. Which one is undefined.

The basic project setup:

targets:
App + AppTests
iPadApp + iPadAppTests
the test targets run in the host application

Local package with products
Base + BaseTestSupport.
BaseTests testtarget

"BaseTestSupport" provides basic helper methods and Mocks for the classes defined in "Base" and therefore has "Base" as a dependency. It is used by both the testTarget of the Base package, as well as both application test-targets.
Base itself is a dependency AppTargets.
Base and BaseTestSupport are defined as dynamic in the Package.swift file. If I don't define it as dynamic I get linker errors when I try to run the Apps test targets for some of the base-packages dependencies (all of the dependencies that cause errors in that case seem to be binaryDependencies, but not all binaryDependencies are causing the errors). The app-target itself compiles and links fine without defining the base package as dynamic.

Am I doing something conceptionally wrong with the BaseTestSupport framework extending/subclassing types defined in the Base framework?

I'm assuming the Base and BaseTestSupport products share common underlying targets? Those are linked statically into the products and since test bundle are dynamically loaded into the app's address space during testing will mean there are two copies (one from each dynamic product) at runtime, leading to the diagnostic you are seeing.

In principle, we shipped a feature in Xcode 12.5 which can build package targets dynamically in this type of scenario, we would need to take a look at your concrete case to figure out why that isn't happening here. Is the DISABLE_DIAMOND_PROBLEM_DIAGNOSTIC build setting set for any of your Xcode targets by any chance?

DISABLE_DIAMOND_PROBLEM_DIAGNOSTIC is not set in any of our targets.

The issue we have is present on Version 13.0 beta 5 (13A5212g)
With Xcode 12.5 we're running into https://bugs.swift.org/browse/SR-13739 in our project setup.

we would need to take a look at your concrete case

Will try to clarify what I can provide as this is a project for a customer.
For now I hope the redacted Package.swift file helps a little. If necessary I might be able to try and provide the project or at least a more detailed outline as well.

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

import PackageDescription

let package = Package(
    name: "OurAppBase",
    defaultLocalization: "en",
    platforms: [
        .iOS(.v12),
    ],
    products: [
        .library(
            name: "OurAppBase",
            type: .dynamic,
            targets: ["OurAppBase"]),
        .library(
            name: "OurAppBaseTestSupport",
            type: .dynamic,
            targets: ["OurAppBaseTestSupport"])
    ],
    dependencies: [
        .package(name: "InternalPackageThatHasABinaryDependency",
                 url: "git@github.com:<redacted>",
                 .branch("<redacted>")),
        .package(name: "InternalPackageWithMoreExternalDependencies",
                 url: "git@github.com:<redacted>",
                 .upToNextMajor(from: "2.0.0")),
        .package(name: "AnotherInternalPackageWithMoreExternalDependencies",
                 url: "git@github.com:<redacted>",
                 .upToNextMajor(from: "2.1.0")),
        .package(url: "https://github.com/ReactiveX/RxSwift.git",
                 .upToNextMajor(from: "6.0.0")),
        .package(url: "https://github.com/RxSwiftCommunity/RxGesture.git",
                 .upToNextMajor(from: "4.0.0")),
        .package(name: "Amplitude",
                 url: "https://github.com/amplitude/Amplitude-iOS.git",
                 .upToNextMajor(from: "8.0.0")),
        .package(url: "https://github.com/janrose-gcx/RxBluetoothKit", .branch("adapt_to_ios_15")),
        .package(url: "https://github.com/DaveWoodCom/XCGLogger.git", .upToNextMajor(from: "7.0.0")),
        .package(name: "Reachability", url: "https://github.com/ashleymills/Reachability.swift", .upToNextMajor(from: "5.0.0")),
        .package(name: "KeychainAccess", url: "https://github.com/kishikawakatsumi/KeychainAccess", .upToNextMajor(from: "4.2.0")),
        .package(name: "AppAuth", url: "https://github.com/openid/AppAuth-iOS.git", .upToNextMajor(from: "1.4.0")),
        .package(url: "https://github.com/Juanpe/SkeletonView", .upToNextMajor(from: "1.1.15")),
        .package(name: "Firebase", url: "https://github.com/firebase/firebase-ios-sdk.git", .upToNextMajor(from: "8.0.0")),
        .package(url: "https://github.com/Quick/Nimble.git", .upToNextMajor(from: "9.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: "OurAppBase",
            dependencies: ["InternalPackageThatHasABinaryDependency",
                           "InternalPackageWithMoreExternalDependencies",
                           "AnotherInternalPackageWithMoreExternalDependencies",
                           .product(name: "RxSwift", package: "RxSwift"),
                           .product(name: "RxCocoa", package: "RxSwift"),
                           "RxGesture",
                           "Amplitude",
                           "RxBluetoothKit",
                           "XCGLogger",
                           "Reachability",
                           "KeychainAccess",
                           "AppAuth",
                           "SkeletonView",
                           .product(name: "FirebaseCrashlytics", package: "Firebase"),
            ],
            exclude: ["Info.plist"],
            resources: [.process("Resources"),
                        .process("Models/<redacted>.xcdatamodeld"),
                        .process("Models/<redacted>/migration/<redacted>.xcmappingmodel")]
        ),
        .target(
            name: "OurAppBaseTestSupport",
            dependencies: ["OurAppBase",
                           .product(name: "RxTest", package: "RxSwift")],
            path: "Sources/OurAppBaseTestSupport"
        ),
        .testTarget(
            name: "OurAppBaseTests",
            dependencies: ["OurAppBase",
                           "OurAppBaseTestSupport",
                           .product(name: "RxBlocking", package: "RxSwift"),
                           .product(name: "RxTest", package: "RxSwift"),
                           "Nimble"],
            resources: [.process("Resources")]
        )
    ]
)
Terms of Service

Privacy Policy

Cookie Policy