Sharing sources between different targets

I would like to have the following structure:

Sources/Target1/main.swift
Sources/Target2/main.swift
Sources/Shared/Shared.swift

If in Package.swift if I configure Target1 to use Sources/Target1 and Sources/Shared, and Target2 to use Sources/Target2 and Sources/Shared, I get an error that the same source is present in 2 different targets, and thus I can't generate an Xcode project.

Is there any reason for this limitation? I can understand that the ideal setup would be to create a new Shared target and make that as a dependency of Target1 and Target2, but sadly the Shared code is generated, and it doesn't include the appropriate visibility modifiers for the classes to be accessible by dependents.

My workaround is generating the files into each of Target1 and Target2, but this is obviously way dirtier than sharing the sources between multiple targets.

3 Likes

I think you can create symlinks in the targets to share the files.

1 Like

That's another valid workaround, but I'm still intrigued on the original limitation

IIRC the idea was to prevent users from accidentally sharing source files between targets.

1 Like

Why is that a bad thing? Is it to prevent prevent people from shooting themselves in the foot because it could lead to duplicate symbol errors if not done correctly?

Yeah, it can create different types of build issues. You can end up mixing Swift and C sources which SwiftPM can't even handle, or it can lead to duplicate symbols if you mix two C targets and try to form a product with those targets, or the target dependencies (imports/includes) may not be available in one of the target.

Just to note this caused us an issue too. We needed to compile the same source twice with different Swift flags. Using symlinks causes problems with saving etc in Xcode my colleague informs me.

There's also the option to exclude specific files or directories. This was useful in a project with Objective-C and Swift where I was able to exclude the Swift files. This isn't your exact use case but should work the same. :)

I too have historically encountered problems with using symlinks in my project build setups, so am not a fan of that approach.

I'm currently trying to solve a related problem right now (see ios - Swift package manager: How best to indicate platform dependent code? - Stack Overflow). From what I can tell, my best path forward is to add conditional compilation into the source code and have a single target for both of my platforms.

While in my specific case, this may work-- as there are few files that differ across platforms. If I have a larger project, with many shared files and many non-shared files, this approach seems limiting. It seems natural that SPM would provide a way to share files across targets. It seems a common use case.

Thanks.