SwiftPM: Same sources, multiple targets

I'm looking for a way to build same source files into multiple libraries, but with different Swift Settings.

Let's say I have my sources under:

Sources/MyLib

Then, I'd like to define targets like following:

.target(
    name: "MyLibWithFeatureA",
    path: "Sources/MyLib",
    swiftSettings: [.define("ENABLE_FEATURE_A")]
),
.target(
    name: "MyLibWithFeatureB",
    path: "Sources/MyLib",
    swiftSettings: [.define("ENABLE_FEATURE_B")]
),
...

However, the compiler is throwing an error: target 'MyLibWithFeatureA' has sources overlapping sources.....

What is the reason for this restriction and is there a way to workaround it?

I have a library that should conditionally integrate with a number of features. Ideally, users of the library would pass some configuration to the package dependency which features to enable, but I don't think SwiftPM supports anything like that.

Therefore, my idea is to expose the library as multiple libraries, each building from the same core, but with different combinations of features enabled. I know this doesn't scale well, but seems to be the only way at the moment.

Btw, having MyLib target and then MyLibWithFeatureA that depends on MyLib is not possible in my case since code is not strictly additive. It would be possible to do that if swiftSettings were applied to dependencies, but they are not :cry:

1 Like

Generally, compiling the same files twice leads to duplicated symbols.

I don't understand why you can't just put features A and features B in separate targets with separate files and then put code common to both in a third target which is depended on by the former two.

I can't do that because including one of the features affects how common code works. Of course, I could pass down some configuration flags, but it's not really feasible and changes the end product.

Generally, compiling the same files twice leads to duplicated symbols.

Only if the targets end up in the same product, which is not necessarily the case.


I have found that you can work around this limitation with a symlink to the target's source directory, i.e.:

project-dir
└── Sources
   ├── the-target
   ├── the-target-variation -> the-target
   ├── ...

Though I don't know whether this is supported or only works by accident.

2 Likes

Thanks @woolsweater. Symlink seems like it could do the trick, but Xcode doesn't like it.

WARNING: If you use symlinks, you must make them relative, because when someone else checks out your package, you'll have no idea what the absolute path to the package will be.

I am running into the EXACT same issue. I wish that targets could have variations that could share the same source, but simply defines a macro that would be applied when building that variation.

I have a project that uses a very large common library that needs to have different variations based on platform and usage. #if ing all of the code on a per platform basis is easy; but now I need to accommodate a server variation of the same library that would have no interface on Linux or macOS. So I wanted to design a 'target' that uses all the same code, but as you tried to do simply introduces a .define("SERVER") macro and I ran into the issue that it could not share the same source despite them being mutually exclusive, they would never recursively import each other.

If there is already a pitch to solve this issue, I would love to be pointed towards it --otherwise, it would be great to pitch variations on targets.