Can the -ObjC flag be applied selectively to static libraries? - ios

TL;DR
How can I make the -ObjC linker flag target a specific static library and not all the static libraries I am linking against in order to avoid unused object files being linked in with my app?
Too Long; Did Read
So you are developing a new iOS app and you add in your homegrown "objcutil" static library which contains a variety of useful Objective-C classes (not implemented as categories) to do various things that have been useful in the past. So far, so good, and only those object files that are being referenced in the utility library are being linked with the app.
Then you decide to integrate the Google Maps SDK which wants you to use the -ObjC Other Linker Flags and all of a sudden dependencies in the utility library fail to be resolved, because you haven't configured Xcode to link to those libraries.
OK I can resolve the missing dependencies easily enough, however you now have unused object files and library dependencies that you don't need and you'd like to be a bit tidier than that.
So how do you avoid OCD overload?
Some reference from the ld manpage:
-ObjC Loads all members of static archive libraries that define an Objective C class or a category. This option does not apply to dynamic
shared libraries.
Xcode Version: 5.1.1
OSX Version: 10.9.4

OK so the answer is to use -force_load instead of -ObjC as -force_load is more focused.
So WRT to the Google Maps SDK, if you followed the instructions and copied the static framework into the app project directory, then the framework will be in the project root directory and you can remove -ObjC from the Other Linker Flags and replace it with
-force_load GoogleMaps.framework/Versions/Current/GoogleMaps:
Nothing else needs changing.
For other libraries you will need to use the full static library path as the argument to -force_load.

Related

Symbols not found for architecture when building Cocoa Framework used in Static Library subproject

I built a pretty simple Cocoa Framework in Xcode for use on an iOS device (not simulator). I dropped this framework into another project that builds a static library. When I build this static library it succeeds without error. No problems yet.
NOW:
I have an actual iOS app project that includes the static library project as a subproject.
When I try building this app I get 'no symbols found for architecture' errors regarding the two classes I am trying to use that are defined in my cocoa framework:
I'm not only building the framework for the active architecture:
I've verified that it is indeed built for both armv7 and arm64 in Terminal:
Kevins-MBP-2:ASI.framework kevin$ lipo -info ASI
Architectures in the fat file: ASI are: armv7 arm64
The only way to get this building successfully is if I also drop my cocoa framework into the iOS app project, in addition to it already existing in my static library project. I feel like I shouldn't have to have the framework in both projects. Only the static library actually uses the framework. The iOS app project does not need to know about the framework.
Static libraries don't contain dependent libraries, so whenever you link against a static library you need to supply the dependent libraries they use to the linker.
Basically you do need to also link the executable against this Cocoa Framework as you have stated in the last sentence of your question.

Explaining Clang dynamic/static library linking process

I'm building my own library and I'm quite confused with how does the final executable linking process work.
I have a MyLibrary.framework which uses CoreLocation header.
When I set Mach-o type to static the framework builds without problem, even though I didn't link the CoreLocation.framework in "Linked Frameworks and Libraries".
When I link MyLibrary.framework to my iOS test project, I have to add CoreLocation.framework, because otherwise I get unreferenced symbols errors.
Question
Why doesn't building my static library need the reference the CoreLocation, and why does building my app require linking to CoreLocation ? What happens there ?
The answer from Mecki here:
Objective-C categories in static library
Explains the compiling/linking process very well. A .a file is an (.a)rchive of .o files.
each .o files contains not only the symbols it has, but also the symbols it needs.
Only during the executable linking process the linker resolves all the symbols in the executable file, which references a static library, which references the CoreLocation library.

why CocoasPod increase IPA size? how to reduce the size?

CocoasPod is good, But sometimes it's not.
Why? Because there is a flag call "-ObjC" in your project.
It will pull ALL OBJECT FILES into your resulting binary.
For example, an empty project with "pod 'AFNetworking'" and the flag "-ObjC" is on, that will cause the binary will be 7MB. 7MB for an empty project, that's suck.
Some frameworks like Google Map SDK need the flag "-ObjC" is on.
So, if your project with "AFNetworking pod" and "Google Map SDK", it will cause the binary will be 17MB.
So my question is:
How can I turn off the "-ObjC" flag for special Library?
For example, just keep the "-ObjC" for Google Map SDK, but turn it off on AFNetworking.
You should try the answer to this question so as to reduce the .ipa size.
In general, adding a static library to your project in Objective-C
will pull ALL OBJECT FILES into your resulting binary because cocoa
pods installation adds -ObjC flag to your linker settings, and as
stated in linker manual:
-ObjC Loads all members of static archive libraries that implement
an Objective-C class or category.
This flag included to solve problem with linking categories, because
by default linker will not include object files containing only
categories into resulting binary.

Xcode -dynamic not specified static library error

I have a sub project within Xcode which creates a static library referenced by the parent project. All has been well until the release of iOS 7.1 and Xcode 5.1, suddenly I'm getting the following warning.
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool: -dynamic not specified the following flags are invalid: -ObjC
warning: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool: file: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk/usr/lib/libsqlite3.0.dylib is a dynamic library, not added to the static library
Does anybody know what I need to do to fix this warning?
I think the solutions lies in the basic concept of dynamic and static libraries. as far as libraries go, dynamic libraries (libsqlite3.0.dylib in your case) are system libraries and you do not need to add them to your static library! all you need to do is to add their reference in your final Target you want to use them in (your application).
so, in short: Try removing the reference to sqlite3.0.dylib from your static library (I'm guessing another project you are using inside your top level application) and add it to your application (not static library) and you're probably good to go. (solved my problem)
[Edit]:
please commit your project's git or do whatever you do to make a backup from your project, there is a chance that Xcode may break your project with no reason after removing these dynamic libraries and NO, deleting project's Derived data won't solve the problem.

RestKit in a Workspace

I have a workspace set up in Xcode. It contains a number of static library projects that I link to in my main project.
The process of linking to these projects is much longer than it should be. But the key for me in getting this to work was removing the -ObjC linker flag from my build settings. This kept me from getting duplicate files when I used a library in more than one place.
But this gave me a problem when trying to include RestKit in my project, because the documentation says that the -ObjC linker flag is necessary, which I have found to be the case.
Is there a way of including RestKit in a workspace like this and linking to it like any other static library? Without having to use the -ObjC linker flag?
If you are planning to target your app for IOS 5 and above then you can try using the built-in NSURLConnection along with NSJSONSerialization class (If you return JSON response) for the purpose.

Resources