Two Libraries with Shared Source...Overlapping Error

Hello, I am trying to build two libraries which share common code, preferably having a subfolder with the shared code and another with the code that is target specific.

I was looking for something like the following, but the syntax seems to make it so you can only have one path.

let package = Package(
    name: "Cores",
    platforms: [
        .iOS(.v12), .macOS(.v10_14)
    ],
    products: [
        .library(
            name: "ACore",
            targets: ["ACore"]
        ),
        .library(
            name: "BCore",
            targets: ["BCore"]
        )
    ],
    targets: [
        .target(
            name: "ACore",
            path: ["Sources/Common", "Sources/ACore"] // NOT VALID SYNTAX, what I was looking to do
        ),
        .target(
            name: "BCore",
            path: ["Sources/Common", "Sources/BCore"]  // NOT VALID SYNTAX, what I was looking to do

        ),
)

Also, when I try to do something like this I get "has sources overlapping sources" as the error message. I could put the common code in a "CommonCore" library but then I have lots of modules and this may have performance implications. Is the common library approach the recommended way of doing this? Using a common library means that now users of the library must use a different module for the shared code. So they would have to import ACore and import CommonCore. This is undesirable.

Having a "Common" target that both "ACore" and "BCore" depend on is what you want in this case. SwiftPM doesn't let you share source files like this to avoid the potential of someone importing both "ACore" and "BCore" and having duplicate symbols.

OK makes some sense but aren't they namespaced based upon the module?

If they are Swift yes! But SwiftPM can also build C, C++, Objective-C and Objective-C++ all of which donā€™t have the same benefits of module namespacing (well they use clang modules but the languages donā€™t differentiate them on those).

So they opted into a more consistent build structuring for all the targets. There are almost certainly other reasons as well but we would need input from someone like @Aciid to know any of those reasons.

@_exported import aims to solve this. It is underscored because it isnā€™t finished yet, but it already works for this use case. Be wary that its syntax may change with any update. But since its effect is only at compile time, you donā€™t have to worry about system updates breaking preā€existing binaries. (And the App Store cannot tell whether you used it or not.)

Ah I see! All my code is Swift but I could see how this could become a problem for Objc sources.

@_exported import

Interesting! Was not aware of this, is there a commitment to support a feature like this? I don't want to use this and have it taken away. I am fine with changing syntax but worry about support being dropped later.

Technically there is no official commitment, but given the heavy use across the Swift projectā€™s own repositories, it is very unlikely that it will just be dropped.

However, it is probable that the syntax will evolve. More information is available in this thread:

1 Like

Also it can be important to know that when using @_exported that operators arenā€™t exported.

2 Likes