How to combine fat static libraries for use in a Swift application?

I got very confused when reading about static libraries and dynamic libraries and then finally about frameworks, Cocoa Touch Frameworks and Cocoa Touch Static Libraries.

The only thing I understood is that static libraries (frameworks?) are added at compile time, whereas dynamic libraries aren't; they're loaded dynamically during runtime.

Q:

I'd like to add several static libraries (they end with ".a", universal fat binaries, compiled for a bunch of iOS architectures such like armv7 and arm64) to my iOS application. Preferably, if possible, that'd be done by combining all of those libraries together (...to a framework?). I also want to write a Swift wrapper around those C libraries. This wrapper shall finally be used in my application. However, the wrapper shall not be part of my app, I want a separate project (again, a framework?) for that (can the libraries and the wrapper be combined together?).

What I'm currently trying to do is to write the Swift wrapper. So I've started with a Cocoa Touch Framework (because I thought that would be the best idea), added the C libraries and headers (actually via a podspec, I don't think that matters though as I could also add them manually), added a bridging header (although some other users reported frameworks don't work with bridging headers, mine does build successfully). Is this the correct way to go?

The first article I read was called "Static and Dynamic Libraries and Frameworks in iOS".

Then, I read lots of articles on stackoverflow about how to compile static libraries, how libraries & frameworks are structured, that frameworks are really just a bundle of libraries and their headers (or so).
I also feel like things have changed over the years at Apple, like they changed the names and possibilities (the Cocoa Touch Framework (is that a dynamic framework?) seems to have been introduced on the release of iOS 8 etc.), which made it even more difficult for me to understand how things work.
Don't get me wrong, I'm just saying this because I want to make clear that I have indeed done some research (quite a lot I think), but I really need some help to get everything right. Basically, I'm just looking for the next step I should take in order to import all those libraries to my app.

Accepted Reply

althouth, if I got you correctly, I'd have to build at least two frameworks for both iOS and iOS Simulator as they're different platforms -- assuming I use Xcode 10

That’s correct.

Would you be so kind and elaborate on how to build a Cocoa Touch Framework for iOS from multiple existing static libraries? Is that possible?

That should be feasible, although it’s not exactly trivial. There two parts to this:

  • Creating the framework Mach-O image

  • Sorting out the headers

The first part should be relatively straightforward. If you create a framework target and add a bunch of static libraries to it, the resulting framework will include all of those static libraries.

The only complication is Objective-C. If any of your static libraries contain Objective-C code, the linker may end up stripping that out. There’s a linker flag,

-ObjC
, that disables this.

Sorting out the headers is a bit more challenging. Frameworks have their own view of how headers should be organised, and this generally doesn’t line up well with UNIX traditions (which is what you seem to have). The critical question is how your client code uses these headers. If the client code does stuff like:

#include <lib_1/----1.h>

you have to preserve that layout on disk, and there’s no obvious way to do that when working with a framework. OTOH, if you have control over the client code, and can change it to just do this:

#include <MyFramework/MyFramework.h>

you could create an umbrella header in your framework, have it include all of your public headers, and away you go.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Replies

Static libraries and frameworks are very different things:

  • Static libraries are linked in to your app at build time.

  • Frameworks are a form of dynamic library. These exist independently of your app and your app is linked to the library at runtime via the dynamic linker.

  • A frameworks is different from dynamic library in that the framework is packaged such that it can contain resources.

The distinction between static and dynamic libraries is less relevant on iOS, where a third-party framework can only ship embedded within an app.

I’d like to add several static libraries (they end with ".a", universal fat binaries, compiled for a bunch of iOS architectures such like armv7 and arm64) to my iOS application.

Be aware that universal libraries (static or dynamic) can only support a single platform, and that iOS and the iOS simulator are different platforms. See this thread for more details.

However, the wrapper shall not be part of my app, I want a separate project … for that

Why? Create a separate project for your wrapper makes things more complex, and it’d be best to avoid that unless absolutely necessary.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks for your response eskimo.

Would you be so kind and elaborate on how to build a Cocoa Touch Framework for iOS from multiple existing static libraries? Is that possible?

To be more precise, I actually have a folder structure for the static libraries that looks like this:



root/
|----lib_1/
     |----lib/
          |----1.a
          |----2.a
     |----include/
          |----1.h
          |----2.h
|----lib_2/
     |----lib/
          |----1.a
          |----2.a
     |----include/
          |----1.h
          |----2.h
|----lib_3/
     |----lib/
          |----...
     |----include/
          |----...
|----...

All of the headers and libraries need to be included into the framework. The wrapper wraps around all those libraries.



Why? Create a separate project for your wrapper makes things more complex, and it’d be best to avoid that unless absolutely necessary.


Well, as I tried to explain, it'd be great if I could build a framework that includes the wrapper and the static library with the corresponding headers (althouth, if I got you correctly, I'd have to build at least two frameworks for both iOS and iOS Simulator as they're different platforms -- assuming I use Xcode 10).

althouth, if I got you correctly, I'd have to build at least two frameworks for both iOS and iOS Simulator as they're different platforms -- assuming I use Xcode 10

That’s correct.

Would you be so kind and elaborate on how to build a Cocoa Touch Framework for iOS from multiple existing static libraries? Is that possible?

That should be feasible, although it’s not exactly trivial. There two parts to this:

  • Creating the framework Mach-O image

  • Sorting out the headers

The first part should be relatively straightforward. If you create a framework target and add a bunch of static libraries to it, the resulting framework will include all of those static libraries.

The only complication is Objective-C. If any of your static libraries contain Objective-C code, the linker may end up stripping that out. There’s a linker flag,

-ObjC
, that disables this.

Sorting out the headers is a bit more challenging. Frameworks have their own view of how headers should be organised, and this generally doesn’t line up well with UNIX traditions (which is what you seem to have). The critical question is how your client code uses these headers. If the client code does stuff like:

#include <lib_1/----1.h>

you have to preserve that layout on disk, and there’s no obvious way to do that when working with a framework. OTOH, if you have control over the client code, and can change it to just do this:

#include <MyFramework/MyFramework.h>

you could create an umbrella header in your framework, have it include all of your public headers, and away you go.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"