Statically linked Library within a Dynamic Framework. Works, but how, and is it valid?

I'm relatively new to Swift and building software for Apple platforms. So far I'm enjoying it, but one of the things that struck me from the beginning was leaky dependencies/imports.

This is something that has been discussed extensively in the community, and some solid proposals have been tabled, kick-started by @jrose on the @_implementationOnly work.

A snippet from the 'exported-and-fixing-import-visibility' post to summarise the problem

Today, if your Swift library "Foo" uses a library "Bar", the headers (or swiftmodule files) of "Bar" must be available to all clients of "Foo". This is clearly undesirable, especially when "Bar" is just an implementation detail. (It may even be linked statically.)

More literature on the topic here:

Another forum post also highlights a setup very similar to the one below and illustrates the problem,

As the above post states (and my early understanding assumes) If we have a setup like so:

Static library named InternalLibrary. InternalLibrary is statically linked into a framework called FrameworkA.

An iOS App Target embeds and links FrameworkA.

At this point, most of the literature I've read about this states that the App Target would now also need to link to InternalLibrary. This is exactly what @ylorn experiences in their post.. This makes sense as to why proposals like @_implementationOnly (and perhaps an internal import) exist. For example, If InternalLibrary was brought in with @_implementationOnly inside FrameworkA, then it would make sense for the App Target to not require an explicit link to InternalLibrary.

I believe I have a good enough grasp of this. However, when the above setup is tried with Xcode 14.1 with the iOS 16.1 App Target, I can omit the need to link to InternalLibrary in the App Target. This works if InternalLibrary is either a Cocoa Touch Static Library or a Swift Package which produces a static library. This seems to go against my understanding and a lot of the discussion around this issue.

To expand a little more, InternalLibrary is still found on the public interface of FrameworkA. And the App Target can still import and use InternalLibrary, so a solution like @_implementationOnly would be better, but my question is, how does the above solution work? And is it a bad idea?

Note: I've build and run on simulator and device.

1 Like