iOS App is including ALL symbols from static library - ios

I have a problem that I haven't been able to resolve in regards to when I link my iOS App against one or more static libraries. Here is the issue:
I am creating several static libraries (MACH-O type: Relocatable Object File) each of which contain a large number of symbols. Each of these static libraries are FAT libraries, containing a slice for each iOS/Simulator architecture. From my understanding, when I compile my iOS Application only the symbols that are used by my App should be compiled into and included in my App, however, ALL of the symbols are being included.
I've done some testing using otool, nm, and other tools and can see that when I link against any of these libraries, even if I don't call any of the code in the libraries, ALL of the symbols are being compiled into the App. It takes my App from 42kB all the way to 3+MB.
Any ideas on why this is happening?

Objective-C is a dynamic runtime; it is permissible e.g. to perform:
NSString *classToUse = ["MPViewController" stringByAppendingString:class];
return [[NSClassFromString(classToUse) alloc] init];
... and furthermore this is more or less exactly what happens when you load a NIB — string class and property names are loaded from disk, the backing classes are then found via the runtime and properties applied by key-value coding. So dynamic lookup is not an edge case.
A linker can therefore not make any assumptions about which symbols are used from an Objective-C static library, unlike e.g. a C linker.

Yes,It can be done by stripping static libraries, but if post-processing is enabled. Set Xcode build setting "Deployment Postprocessing" to yes. (DEPLOYMENT_POSTPROCESSING=YES). Also make sure that "Use separate strip" is set to Yes. You can check this
You can also achieve what you are expecting by using Dynamic Library, there is a very nice article here
Extra Tip
* While creating library set Debug Symbols to NO in your build settings. This can reduce the size of your static library by up to 30%.

Related

Why should I create Dynamic frameworks for iOS Project?

I have main application target. And I'm moving some code into frameworks to reduce compile time of the huge project.
Default framework type is Dynamic (BuildSettings -> Mach-O Type). I understand benefits of using Apple's dynamic frameworks as several apps will use the same framework and each application size will be lower (because the app size doesn't include this dynamic frameworks).
But if I'm using my own frameworks and only in my application, why should I choose dynamic frameworks.
It looks like the app size will be bigger with dynamic frameworks Source and application start time will be longer (because it needs to connect all these dynamic libraries, but with static they are already a part of app executable).
App store size probably will be bigger as well with dynamic frameworks as well.
Would be helpful if somebody can fill me in what benefits can we get using dynamic frameworks 🤝
Your assessment is mostly correct.
It is possible to not directly link against frameworks, but instead load them on demand with dlopen.
This can be used both for a plugin system where only one of many available libraries will be needed, or to defer the loading of particularly heavy frameworks, which would actually reduce the launch time of your app.
Further reasons I can think of for using dynamically linked frameworks are:
Licensing reasons.
If you're developing a closed-source library for other developers to use, then a static library normally has a lot more information still embedded than a dynamic library and with a static library you can easily conceal the fact that you're using it, both of which you might not want.
If you have symbol clashes (e.g. due to linking against a static library multiple times, as might be the case with the Rust standard library), then you can split the different codebases into frameworks in order to separate the namespaces.

iOS Static Library | Linking only USED symbols

I am using some third party iOS Static Libraries and am having some trouble keeping the binary size small. The libraries that I am using have an Objective-C interface that is backed by native C/C++ code. The issue is that ALL of the symbols from the library (checked with nm) are being included in my App when linked (even if I don't reference any of the code in the library). This is contrary to my understanding of static libraries where only the code that your application (or other linked libraries) reference is pulled into your application.
I've done a bunch of reading and have found that due to the dynamic nature of Objective-C, there are particular issues that can arise from linking object files or static libraries containing only Objective-C category methods. Because of this, you can pass the -ObjC flag to the linker to have the linker pull in ALL object files containing Objective-C classes or categories. This ensures that all classes and categories are defined at runtime, but bloats your App's binary with unused Objective-C classes/categories/method definitions.
Strangely enough, I am seeing the effects of adding the -ObjC linker flag while not using it anywhere in my build. ALL of the Objective-C symbols are being included, and as a consequence, ALL of the native C/C++ symbols that the Objective-C code references, whether or not my App references any of the code in the library. Has anyone else experienced this problem or found a solution to it?
OS X 10.11.4 and Xcode 7.3.
First, a disclaimer: I haven't personally tried the solution I describe here (all the projects I've worked on just use the -ObjC flag indiscriminately), so YMMV.
That said, this might be of use: https://github.com/CocoaPods/CocoaPods/issues/712
Basically, the idea is, rather than using the -Objc carpet bomb, you can do a slightly more targeted load on a per-library basis: -force_load $(TARGET_BUILD_DIR)/lib<yourLibName>.a.
The author of the referenced link specifically mentions CocoaPods as the culprit for a specific problem he encountered, but I would think (hope) that this solution would apply to the more general question you're asking.
As to the question of why you even have to bother, the only thing I can find that even comes close to an actual explanation can be found here: https://developer.apple.com/library/mac/qa/qa1490/_index.html. This post describes an "impedance mismatch" between Unix (BSD) static libraries and the more dynamic Objective-C based libraries (even static ones) containing e.g. categories. Current linkers can't make the required connections at compile/link time for methods that are essentially bound at runtime, so these linker flags are a workaround to that problem.

How to weaken strongly linked symbols in a mach-o static library?

Our app supports iOS5 however one of our 3rd party static libraries has started strongly linking against iOS6 symbols in UIKit. I'd like to change this linkage to weak and disable the library on iOS5 (assuming the library doesn't use the symbols in load).
I'm looking for something like what I imagine objcopy --weaken-symbol from linux does, so does anyone know of any likely tools or will this involve learning the mach-o format?
I'm none the wiser on mach-o, but I realised that static libraries can't actually decide on how they link against my frameworks. Only I can do that.
So I went into Target > Build Phases > Link Binary With Libraries and set UIKit to Optional. Now the app launches on iOS5 and I can simply (I think!) not call the offending library.
I'm only slightly disappointed I didn't get to write a re-linking tool

Keeping Xcode from stripping out unused symbols from a static library

I've built a static library that I'm my iOS binary is linking in. Code stripping is off, etc. for the static library, and I can see the symbols in the archive (via nm).
So, I link that library into my application as a framework. But, I'm not actually calling that function directly. As a result, I can see the symbols that I'm calling directly in my binary, but not the ones that aren't called. But, since I actually want these symbols to be there at runtime, I'm compiling with -all_load.
But, this seems to place an unnecessary burden on the users of the library. Is there something I can add in the static library that enforces this, rather than relying on the user of the library?
Depending on what you are trying to accomplish, you can precisely control which symbols are dead-stripped and which are always loaded, even if the user of the library doesn't actually use them.
The easiest way is to create a library initialization function that references the exact symbols you don't want dead-stripped. This is precise, and saves you the burden of wrestling with the linker command-line options, which may insulate you from (unlikely) tool behavior changes down the road.
Frameworks have automatic initializers (quite handy) that can be called automatically when the framework is loaded at runtime, right after any static variables are initialized.
__attribute__((constructor))
static void MyModuleInitializer()
{
static BOOL initialized = NO;
if (!initialized) {
// References to symbols that should be kept around.
initialized = YES;
}
}
Just for grins, automatic finalizers are also supported using the __attribute__((destructor)) decorator.

Controlling export of third party symbols in an iOS / iPhone SDK

If you're building a commercial iOS SDK that will be included in other people's code and you have third party libraries that you have a license to, is there an effective way to simplify the library / framework structure by not exporting those 3rd party symbols in a static lib?
I appreciate I could instruct developers to check for overlapping symbols, but I'd like to minimize instructions. Ie, just want them to drop the lib into their project and off they go. I also do not want to export my third party symbols as they may change in later projects.
Unfortunately, there isn't a lot to be done here very easily. A static library is just a bunch of .o files glued together. There is no linker step to determine what pieces are actually needed between .o's. That's not done until the final link step (by your customer).
That said, there are some things you can think about:
First, whenever possible, avoid including sub-libraries inside of a static library. This is really dangerous if it's possible for the customer to have other copies of the same sub-library. Your situation seems to be difference since your sub-library is licensed, so the customer is unlikely to have multiple copies, but for example, you should never include a static copy of libcurl in your static library. You must ask the customer to link libcurl themselves, or else things will explode quite badly for them. (See Linking static libraries, that share another static library.) Again, this sounds like it may not apply to you, but keep it in mind if you have common open-source libraries in the mix.
An old-school solution for dealing with visibility is to glue together your compile units. This is a fancy way of saying "concatenate all your .c/.m files into one massive file and compile that." Any function you mark "static" will not be visible outside this compile unit, and so shouldn't be exported. This also happens to increase the possibility of compiler inlining and other optimizations (particularly without fancy link-time optimization) inside of your library.
See Symbol Exporting Strategies. You have several options:
marking symbols as static (probably not possible in this case since they come from a 3rd party)
Use an exported symbols list or an unexported symbols list
Set the visibility attribute of the symbol directly (again, probably not possible in this case)
Use -fvisibility command line option when compiling (probably your best bet here)
Use weak imports
Use a weak library
These are explained at the link above.

Resources