Xcode Framework Modules - ios

I'm having an issue implementing modules for my particular build configuration. I have a bunch of dynamic frameworks that I would like to add module map files to so that they can be naturally imported into Swift without having to use Objective-C Bridging Header files. The issue that I'm having is as follows:
I have multiple modular frameworks:
Framework.framework (base framework, required by all components)
Framework.Component1.framework
Framework.Component2.framework
... etc
I would like to be able to write a module map for each framework that uses this dot notation for the module naming (for backwards compatibility, among other reasons) but Xcode isn't allowing me to name whole modules with the dot syntax since the dot syntax is reserved for Submodules.
I've tried creating an umbrella framework that contains all of different components and writing a single module map for that, but given that the frameworks are dynamic this necessarily bloats the final binary size if the user isn't using all of the frameworks inside of the umbrella framework.
Are there any solutions that would allow me to use this dot syntax while having separate module map files for each of the frameworks?
Thanks!

Go with the umbrella framework strategy.
Then, for submodules that are "optional" in your umbrella framework (maybe even all or most of them) set the submodule declaration to explicit. This means the consumer must import the submodule explicitly in order for it to be loaded. This is what I've done in the past to import a very large C library into Clang's module system and it worked well enough.
The docs are okay, but not great. However, they do go over this case pretty well: https://clang.llvm.org/docs/Modules.html#submodule-declaration

Related

How to combine fat static libraries for use in an iOS 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 this one (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.
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.
This answer was copied from the Apple Developer Forums.

How to package module.modulemap into CocoaTouch Swift Framework?

I am trying to create a CocoaTouch Swift Framework which I can then distribute to 3rd parties for them to use, and I can build it and use it ok on my machine.
The issues arise when I give it to other people.
My framework uses C code, which I make available for use with Swift within my framework via a module.modulemap file as such:
And I am able to use such module in a Swift file, within the framework, ok, as such:
However, when I build the framework and give it to other people to use, their compiler complains that the Minzip module is missing with the message Missing required module 'Minizip'.
Having investigated, it seems like I'd have to make the users of my framework modify their Swift Compiler - Search Paths -> Import Paths the same way I have to do it to have my compiler find the module.modulemap.
Is there a way that I can build the framework so that I don't have to do this?

Include of non-modular header inside framework error

I realize this is a common error and has been asked several times but I am unable to resolve it after trying several different things based on others' answers.
I am creating a framework project (Obj-c) which uses another third-party framework. In MyFramework's umbrella header, I have the import statement of third-party framework. When I packaged my framework and included it in another iOS project, it fails to build with this error.
Things I tried:
Turned ON "Allow non-modular includes in Framework modules"
Added the umbrella header of the third-party framework as a "Public" header
Please advise what is missing here. Thanks in advance!
Here's the Exact Error:
Include of non-modular header inside framework module
'MyFramework.TestManager':
'/TestApp/WindowsAzureMessaging.framework/Headers/WindowsAzureMessaging.h'
Also, from the path it looks like it is trying to search for it in the TestApp project, whereas it should refer from the Framework.
I imported the Azure Messaging Framework in the Umbrella header as shown below:
#import <WindowsAzureMessaging/WindowsAzureMessaging.h>
I was able to reproduce your error. I looks like the WindowsAzureMessaging header and all other headers it refers are not made to be used in a modular framework umbrella header, because it uses "user" imports instead of "system" imports relative to the framework, and also it doesn't have the modulemap file.
You have several options:
adapt their code and make it build as a module (make it "modular").
not include it in the umbrella header (avoid referencing things from it there), but link it and use directly in the app and your framework.
instead of using the file framework as a separate entity, you could take (copy) their source code (m and h files) and compile into your framework, and then expose some headers as your own headers.
I think that option 1 is the right way to go. It is not hard, and if you manage to do that, think about making a pull request for their repo, because this is going to benefit everyone.

linking custom framework to library in xcode

I want to include Microblink's PDF417 framework into my library. Library project compile and work fine but when I use MyLibrary.a file in my application I've got "undefined symbols for architecture armv7" error. Any ideas? Can I include custom framework to library or this isn't possible.
Trojanfoe's answer is correct for your case. But in general, the answer depends on the type of the library inside the framework.
iOS/MacOS framework is a just a collection of a library together with all relevant header files. This makes including the library into other projects much easier, because the whole framework can be included at once, thus eliminating the need to modify linker and header search paths and linker flags.
Library itself can be either a static library or a dynamic/shared library. Framework can contain the library of any type, there are no limitations in that regard.
If the library in framework is static, then all the objects from that library are copied into target product at compile time. If the target product is a static library (MyLibrary.a in your case), additional linking with the framework in the application is not needed, because all the objects are contained in MyLibrary.a
If the library in the framework is dynamic, then objects from that library are loaded at load-time or run-time, not at compile time. Because of that, frameworks of that type need to be linked with end applications also.
In your case, pdf417 framework contains a dynamic library, which means you will also have to include that framework into your end application.
I'm a developer on Microblink's PDF417 SDK. The thing is, we can provide our library in any format. The format we have chosen in our Github repository is an .embeddedframework which contains a dynamic library together with all resource files because that makes including the framework into Application projects very simple. If you have a use case which requires a different format, we invite you to contact us on https://help.microblink.com/hc/en-us
A static library is just a collection of object files (a bit like a zip file without compression or hierarchy) and cannot hold information about any dependencies it might have.
Therefore you have to link the final executable binary against both your library and the dependent framework. The same applies if the dependency was a static library, dynamic library or framework.

How to create & configure a (mix & match) framework as module?

I've read the "Using Swift with Cocoa & Objective-C" a few times, and I've tried every possible combination of project type (framework, static lib & Swift first, Obj-C first, the lot) but I simply can not get modules to work. I've spent more than 2 hours on this, and it shouldn't be that difficult. Chosing a module name and setting Defines Module to 'yes' doesn't do it.
My goal: to create a module that makes the Apple System Logging service available in Swift code. I've got an objective-c wrapper library lying around that I thought I'd make available as a module to import into my Swift framework, but so far the only luck I've had is it exposing only one of the many classes publically in Swift code. The rest simply aren't available. It's also exposed the 'asl.h' C functions, which is cool, but I have no idea how that happened. I tried creating several sparce frameworks/static libs with the sole goal of making 'asl.h' functions available in Swift. If someone knows how to do that (for any C headers that are part of iOS) without the need to create an Objective-C framework as a module to import into Swift, I'd love to hear about it. Or even just as a framework to make any c headers available in Swift that would be awesome.
So! I create a workspace with an app project in it, and then I create a framework project at the same root level in the workspace as the app project. On the framwork target I set the Product Module Name and Defines Module to 'Yes'. I update my My App's Scheme build target to include the framwork above the app target. I ensure the Link Binary With Libraries build phase contains the framework. Build the app target after adding an 'import MyFramework' line in a Swift file and boom. Failure.
Obviously I've tried clean builds, deleting Derived Data for all projects, hopping one leg and trashing everything and starting again. Someone, anyone, had success with modules yet?

Resources