Is it possible to build a dynamic framework without the symbols of a static library that it links to?

I have an app that links to two dynamic frameworks which both link to the same static library, as follows:

|--App
  |--DynamicFramework1      
    |--StaticLibrary   
  |--DynamicFramework2      
    |--StaticLibrary <- the same library that DynamicFramework1 links to

The static library's symbols are included in each framework's binary because of the way dynamic frameworks are built by default. The app therefore finds duplicates of the static library's symbols at runtime.

Is it possible to link a dynamic framework to a static library (and to still be able to call on the classes and methods of the static library within the dynamic framework) in a manner that symbols from the static library are excluded from the dynamic framework's binary?

My hope in doing this is that the binary of each of the two dynamic frameworks will exclude the symbols of the static library. I will then make it the responsibility of the app to link to the static library directly.

Notes

  1. I have tried linking my dynamic framework with the static library in two different ways thus far: (1) I added the static library to my framework's "Link Binary with Libraries" Build Phase; and (2) I referenced the static library in my framework's "Other Linker Flags" Build Setting. Both result in the static library's symbols being included in the framework's binary.
  2. I am aware that changing a framework target's "Mach-O Type" from "Dynamic Framework" to "Static Library" will build the framework's binary without the symbols of the static libraries that it links to. I want to keep my frameworks as dynamic frameworks so that (1) I can benefit from how Xcode bundles together resources (strings, storyboards etc) automatically for dynamic frameworks; and (2) users of my framework can benefit from Mergeable Libraries in the near future.
  3. I am aware that I can solve this problem by changing the static library to a dynamic framework. I want to avoid this as much as possible since the static library is from a third-party. I want to avoid forking the static library's source code and messing with its build scripts if I can.

Accepted Reply

I am grateful to MobileTen and eskimo for their suggestions and advice in this thread 🙏

MobileTen's three suggestions didn't quite fit my setup but the first one gave me confidence in the solution that I had been converging towards.

The best solution that I have been able to come up with is as follows:

  1. Create a new dynamic framework DF.
  2. Link DF to StaticLibrary with the -all_load linker flag.
  3. Link App, DynamicFramework1 and DynamicFramework2 to DF instead of StaticLibrary.

The linking structure, in pictorial form, of this solution is as follows:

App
 |--> DF1 --> DF --> SL   
 |--> DF2 --> DF --> SL
 |--> DF --> SL

For a minimal but concrete Xcode project that demonstrates this setup, see here.

If somebody can suggest a better solution which does not involve housing the static library's symbols within a dynamic framework, I am open to it.

Replies

You will have to readjust your dependencies.

|--DynamicFramework1      
   | --DynamicFramework2     
       | --StaticLibrary   

Or

Readjust your dependencies by responsibility.

|--DynamicFramework1      
       |--StaticLibrary_A
|--DynamicFramework2    
       |--StaticLibrary_B

Where the public APIs of StaticLibrary_A and StaticLibrary_B are mutually exclusive.

Or

Create an Xcode project for each framework.

  • Thanks for the suggestions 🙏 The three suggestions don't quite work for my setup but the first one gives me confidence that the solution which I have been converging towards isn't all too bad. The best solution that I have been able to come up with – which is similar to your first suggestion – is to create a new dynamic framework DF, link it to StaticLibrary with the -all_load linker flag and then link App, DynamicFramework1 and DynamicFramework2 to DF instead of StaticLibrary.

Add a Comment

It might be possible to get around this by hiding the static library’s symbols in each framework. However, I recommend MobileTen’s approach because:

  • This duplication is wasteful in both disk space and memory.

  • In some cases it won’t work. The most notably example of this relates to Objective-C, which all the classes live in a flat global namespace. If you have duplicate copies, you’ll see weird results (in the best case it’s just a runtime warning, in the worst case the code won’t work).

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

  • Thanks for the advice 👍 MobileTen's suggested fixes don't quite work for my setup but the first of his/her suggestions has given me confidence in the solution that I have been converging towards. I'll post an answer in this thread that summarises my solution.

Add a Comment

I am grateful to MobileTen and eskimo for their suggestions and advice in this thread 🙏

MobileTen's three suggestions didn't quite fit my setup but the first one gave me confidence in the solution that I had been converging towards.

The best solution that I have been able to come up with is as follows:

  1. Create a new dynamic framework DF.
  2. Link DF to StaticLibrary with the -all_load linker flag.
  3. Link App, DynamicFramework1 and DynamicFramework2 to DF instead of StaticLibrary.

The linking structure, in pictorial form, of this solution is as follows:

App
 |--> DF1 --> DF --> SL   
 |--> DF2 --> DF --> SL
 |--> DF --> SL

For a minimal but concrete Xcode project that demonstrates this setup, see here.

If somebody can suggest a better solution which does not involve housing the static library's symbols within a dynamic framework, I am open to it.

Hi @MobileTen.

Could you please elaborate on why...

Create an Xcode project for each framework.

...would work in this case?