SwiftPM: Reason for not allowing a target to depend on a library in the same package?

I recently stumbled across a small issue how to organize code into packages in SwiftPM.

Simplified example: Let's say I have a local package which contains two targets.

  • One target (Authorization) specifies a protocol Authorization to be used by other local packages in the app.
  • The second target (AppAuthorization) contains a type conforming to the protocol Authorization, only to be used in the app itself.

What I would like is to have a package where only the app depends on AppAuthorization, and other local packages on Authorization only.

What I can do is have a package 'Authorization' with two libraries AppAuthorization and Authorization which contain the respective targets. The target AppAuthorization dependends on the target Authorization.

If I understand it correctly, I would then get the binary for the Authorization protocol/module twice: Once through the library Authorization which the other local packages depend on, once through the library AppAuthorization which should contain it as well because of the dependency of target AppAuthorization to the target Authorization.

While this seems to work with local packages (maybe because of static linking), I assume it would blow up if I move the package to non-local and dynamic linking?

If a target could depend on a library in the same package, I could go for:

  • library AppAuthorization with target AppAuthorization
  • library Authorization with target Authorization
  • target AppAuthorization depending on library Authorization in the same package.

Could be there is a reason that is disallowed though. Am I missing something?

1 Like

For this and a variety of other reasons, the distinction between product and target has proven to be mostly counterproductive. Several team members have mused of a hypothetical future where the distinction is removed. Reducing it to a simple public: Bool parameter on .target that mirrored the public ACL token would solve a lot of problems in one fell swoop. Unfortunately the two concepts were designed and implemented separately in the early days of SwiftPM, and thus it would be a massive overhaul to unify their code.

That last italicized sentence is the only reason a target cannot depend on a library. It is not deliberately disallowed; the API for it is just absent. And since the associated implementation would have to stitch together and intertwine what is currently two separate loading phases, the amount of work involved has thus far deterred anyone from attempting it.

7 Likes

Thanks for the insight into how things got the way they are!

I would love to try how far I can get with this. If I can’t put enough time in, it will be a learning opportunity anyway.

As it would be a purely additive change as far as I can tell, would I need to submit an evolution proposal, or would an issue+PR be enough?

Unifying the internal implementation would not have any noticeable effect to users on its own, so it probably does not need to go through evolution, though you should still seek feedback from the team before you start. It will definitely be far more complicated than the sort of thing you tag “good first issue”.

But the final step of actually changing or adding to what the manifest declarations can mean is a user‐facing change to the language and does need to go through evolution.

Thanks @SDGGiesbrecht, I will pitch this in the evolution thread. Code-wise I have an experimental version, the code changes seem to be smaller than expected—or I am missing something which is way more likely ;)