Are both static libraries and dynamic libraries compiled during the build process? - ios

When you build an app,
You have to compile and then link.
Whether you link a framework dynamically or statically, you still have to compile them both.
It’s just that for a static library, you link at build time and pay its price through extra time.
With a dynamic library, you link at launch time i.e. defer the extra cost, but eventually you’ll have to endure the link time…
Like my question is, for dynamic linking, the compilation still happens during build time. It’s not like that the OS has a compiler and compiles and then links app launch time. I imagine if that was correct then app launches for dynamic linking would be terrible…
Do I have it right?
And if a library is pre-compiled, then while you save on the compilation step, it doesn't in any way affect the linking. Still — depending on if it's static vs. dynamic library you will have to pay the cost of linking eventually.

Not an IOS-specific question.
Libraries (static or dynamic) are not necessarily compiled at build time. Many are provided as binary files without source code and simply linked to your program. If you have the source code, you can set up your build process to build the libraries.
Statically-linked libraries are combined into your executable file at build time by the linker. Dynamically-linked libraries are not part of your executable file, and are linked to your program at run time by the operating system's program loader.
Dynamic linking is generally very fast. Modern compile-time linkers can be very sophisticated and can do exotic things like generate and compile code.
So far we're describing classic compilation and linking.
Now, there are newer languages that are a hybrid of compilation and interpretation. In these languages, a library contains an intermediate representation (IL) that is may be interpreted by a runtime, or compiled to native code just-in-time (JIT).
We haven't even discussed interpreted languages like Javascript.
Modern systems often blur the traditional distinctions between interpreted and compiled languages and do "all of the above". Sometimes the code running to accomplish something in an app is not even on your device, but is running on a server "in the cloud".
So, your homework now is to read up on the terms "native code", "assembly code", "intermediate language", "compiler", "JIT", "runtime", and "interpreted language".

Related

Do import statements in Swift have an associated cost?

Reading the String Manifesto, I saw a paragraph about avoiding the Foundation import when not necessary.
Why is this a concern to the Swift team? Apart from aesthetics and code tidiness, do imports come with a cost?
Could importing unnecessary frameworks impact performance, memory usage, packaged app size or build time?
The page you reference is just saying that they'd like to see more String methods built directly into Swift. Currently some tasks like case-sensitive string comparison require importing Foundation.
Ok I'm going to give the rest of your question a shot. The answer is it depends on what you are importing.
Looking at this answer:
Since Xcode 5, there is a new feature introducing precompiled sources database. Xcode 5 basically compiles all the required frameworks just once, saves builds in the database and that already compiled pieces uses while compiling your code
Also looking at this question:
We see that importing UIKit in every file that uses it is necessary. If the above solution is correct than regardless of how many times UIKit or Foundation is imported it is only compiled once. Thus importing a standard library more than once as no affect on compile time.
However, importing something for the first time would affect compile time because that Library now needs to be compiled when it previously was not needed.
Example if I have to import Foundation in a small Swift program the compile time will be slowed down. When it comes to iOS apps it's basically impossible to not import UIKit which also imports Foundation so I don't think this is worth worrying about since every app will have to compile these libraries as well.
Additionally, we need to look at imports that result from things like Cocoa Pods and Carthage:
Looking at this repo:
There are two ways you can embed third-party dependencies in your projects:
as a source that gets compiled each time you perform a clean build of your project (examples: CocoaPods, git submodules, copy-pasted code, internal libraries in subprojects that the app target depends on)
as a prebuilt framework/library (examples: Carthage, static library distributed by a vendor that doesn’t want to provide the source code)
CocoaPods being the most popular dependency manager for iOS by design leads to longer compile times, as the source code of 3rd-party libraries in most cases gets compiled each time you perform a clean build. In general you shouldn’t have to do that often but in reality, you do (e.g. because of switching branches, Xcode bugs, etc.).
Carthage, even though it’s harder to use, is a better choice if you care about build times. You build external dependencies only when you change something in the dependency list (add a new framework, update a framework to a newer version, etc.). That may take 5 or 15 minutes to complete but you do it a lot less often than building code embedded with CocoaPods.
Looking at this blog:
We see that there are more precise imports that can be used if one is concerned about compile time. Such as import UIKit.UITableViewController
As far as performance and binary size goes, any unused symbols are already optimized out of the final binary by the Swift compiler. If there’s no reference to it at compile time then it’s removed, meaning that importing a framework but not using particular parts of it shouldn’t have any negative implications.
Another blog states:
In this WWDC 2016 talk, Apple suggests replacing dynamic frameworks with static archives to mitigate this. To take this approach, we rebuilt as many of our dynamic frameworks as possible statically and then merged them into a single monolithic dynamic framework named AutomaticCore.
The difference was dramatic: our app’s launch time was cut in half.
TLDR: It's not worth worrying about importing standard things like Foundation or UIKit they are only compiled once and just about every app uses them so any performance decrease is shared. However, if you are importing third party Frameworks you might want to use a static archive to help with compile time.
While there is no doubt that importing frameworks increases the raw file size of your app, they are generally very well compressed. And if you need the framework, you have no choice but to import it. Practically, however, file size is not an issue when it comes to frameworks--relatively large ones, like Mapbox, can be included at the cost of just a few MB to your end product. And it's a shared cost by all apps so it's a wash.
Framework code is also stored in shared libraries, not in your executable, which is a very important distinction. Regardless of which Apple platform you're programming for, read Apple's OS X documentation on frameworks because the general concepts are the same. In it, it briefly talks about the relationship between framework inclusion and performance:
If you are worried that including a master header file may cause your
program to bloat, don’t worry. Because OS X interfaces are implemented
using frameworks, the code for those interfaces resides in a dynamic
shared library and not in your executable. In addition, only the code
used by your program is ever loaded into memory at runtime, so your
in-memory footprint similarly stays small.
As for including a large number of header files during compilation,
once again, don’t worry. Xcode provides a precompiled header facility
to speed up compile times. By compiling all the framework headers at
once, there is no need to recompile the headers unless you add a new
framework. In the meantime, you can use any interface from the
included frameworks with little or no performance penalty.
https://developer.apple.com/library/content/documentation/MacOSX/Conceptual/BPFrameworks/Tasks/IncludingFrameworks.html
That said, don't import frameworks that are already imported by default from "umbrella" frameworks. For example, importing UIKit automatically imports Foundation so don't import both. Does this really make a difference? No, but caring about the details, even the unimportant ones, is what will snowball someone into a programmer other people want to hire and work with. I can't tell you how many programmers I've collaborated with in the past who had the "who cares" attitude about things like this. It's no surprise their code was always the sloppiest and they're the ones always out of work.

XCode-iOS : What does this linker warning mean "file was built for unsupported file format "

I am trying to get some a medium-to-large sized code base that is, frankly, well written with a high degree of portability.
I decided to package it as a loadable bundle (plugin) and piggy-backed off of one of the template app projects and followed some tutorials about adding a target for loadable bundles within an app.
Also, this loadable bundle depends on a custom framework which I built for iOS and added it as a dependent for the loadable bundle. ie. The plugin links to a framework wrapper for a static lib.
The custom framework built successfully. Granted I have not yet verified that it works. The idea is to test the integrated functionality.
My build settings are largely defaults with the exception of some preprocessor defines.
Because I don't really understand the code base yet, I am literally adding one file-at-a-time to the plugin target and building cleanly every 3-4 files added.
The build completes successfully but with many, many warnings as follows, with paths to intermediate build results...etc.:
"file was built for unsupported file format with a series of hex characters () which is not the architecture being linked (armv7s)". When I converted the hex chars to ascii it just showed "#1 /Users/my-username/? ".
When I do a 'file' on any .o in the intermediate build results, I get "ASCII c program text, with very long lines"
What am I doing wrong? What does that mean?
Thank you so much for your time.
The short answer is this:
If you get this message, then your project settings are messed up.
If you are linking your app against custom frameworks, make sure they are built as fat binaries
You will need to know very clearly the meanings of active architecture and how it is used and whether or not you want to only build the active architecture for your app, or all of the possible architectures.
If you are, like me, inheriting a slew of portable code that depended heavily on gcc and its extensions, expect to make changes around builtin* attributes and to make heavy use of __clang to make available macros that used to be defined through the GNUC et al.
Also, you will need to use the -E for clang to debug/understand the preprocessing and the file inclusion. That said, don't forget to take it out because effectively what will happen is that your .o will just contain text and the build may succeed, but the linker will give you the odd message subject of this question.
Finally, do understand that Xcode, like any piece of complex software, is buggy. Sometimes, it will keep settings that you get rid off. In my case, I included custom frameworks which I built after placing them in a local dir. Then I deleted them from the project and opted to trash when prompted. The build kept failing because the linker for some reason was looking for the local directory. You would have to edit the *.pbxproj and manually remove them.

Statically linking against non-pic 3rd party library

I am building an iPhone application that I need to be position-independent. I am linking against third-party libraries to which I do not have source code.
If such a library has not been compiled with -fPIC and therefore is not position-independent, can I still link against it to produce a valid PIE binary?
Will the dynamic loader handle any text relocations that occur due to code from this library.
If not, what are my possible options to resolve this situation and still produce a PIE binary?
As far as I know, whether a source file was built with -fPIC or not, is not important unless you plan to create a dynamic library out of its object file. Actually most static libraries aren't built in a position independent manner. Not that that this would be forbidden, but it will result in a slightly bigger and slower binary later on (as the compiler/linker will not be able to perform certain types of optimizations).
And a binary runs in an address space of its own, it doesn't have to be position independent at all. That's the reason why dynamic libraries must be position independent as they are shared among different binaries that all require different memory positions for themselves, so it must be possible for the dynamic linker to move the library elsewhere in the process space of a binary at runtime.
Or to say it in even simpler words: Just link against that static library and everything will be fine.

Invalid Executable Size - From iTunes Connect

I am uploading my iOS application on iTunes. I am using MonoTouch for compiling my LibGdx Game for iOS. In Android it is hardly 7-8mb. But When I upload on iTunes AppStore then its goes to 78 mb. I dont know why ? Please Let me know.
I have also received this error from Apple.
Dear developer,
We have discovered one or more issues with your recent delivery for "Run Panda Run: Racing". To process your delivery, the following issues must be corrected:
Invalid Executable Size - The executable size of 72037504 bytes exceeds the maximum allowed size of 60 MB.
It's hard to give a definite answer without more details. There's a lot of things that can affect the size of the applications. Let's start with the basic.
What you should check:
First, ensure that your application is not being build with Don't link. That will create very big applications since you'll be AOT'ing nearly the full .NET framework that Xamarin.iOS ships;
Second, make sure you're building for a single architecture (ARMv7). FAT binaries (e.g. ARMv7 and ARMv7s) are build two times and needs twice the space;
Third make sure you have not enabled the Debug build (it's possible to do so in Release build, it's a checkbox). That will create larger binaries to support debugging;
Fourth make sure you're using the LLVM compiler. It takes more time to compile but it generates better (and smaller) code;
Those initial checks are pretty easy to do and are the most common reasons for getting very large binaries.
To understand where the size come from you need to know how the application are built.
The main difference between the Android and iOS version is that JIT'ing (just-in-time compilation) is not allowed on iOS (Apple's rules).
That means the code must be AOT'ed (ahead-of-time compilation) and that process creates much larger executables (because IL is way more compact than native code);
If your code is generic-heavy then the final binary can get quite large since it will need to natively compile every generic possibilities (many cases can be shared, but value-types cannot).
What you can do to reduce size:
First try to reduce your managed code size. The easy way to do this is the enable the linker on every assemblies, i.e. Link all assemblies in your project options.
Many people think it's not worth linking their own code - because they know it will be needed at runtime (so the linker cannot remove it) or else they would not have written that code.
That's half true. The linker might not be able to remove most of your application code but if you're using 3rd party assemblies they are not likely 100% used. The linker can remove that extra code (and also remove, from the SDK, all the code that is kept to support that unneeded code). The more shared code you have the more the linker can help you.
Less IL code means faster AOT time, which translate to faster builds and smaller final binaires (including the executable size).
Note: there's a lot of documents and blog entries on how you can control the linker to skip some assemblies, some types or method from being processed/removed.
Second try to reduce your native size. If you're building native libraries then have a second look at them as they will be statically (not dynamically) linked to your final binary (another rule for iOS applications). Some of them might not be worth (feature wise) their weight in your final binary (and there might be lighter alternatives).
Debugging should not be enabled, as it will make the build unnecessarily large.
For more information refer : https://learn.microsoft.com/en-us/xamarin/ios/deploy-test/app-distribution/app-store-distribution/publishing-to-the-app-store?tabs=windows
I had the same problem but in my case I had minimum os version set to 8 in the info.plist causing a larger .ipa file. I changed this to version 10 and was able to pass the size requirements. Even 10 is a bit generous

is it prohibited using of JIT(just-in-time) compiled code in iOS app for AppStore?

I heard that JIT compiled code is not allowed in iOS AppStore because placing executable code in heap is prohibited. It that right? Or just a rumor?
Installable code isn't allowed ("or" is the key word in 3.3.2). Everything (except Javascript) has to be statically linked.
JIT compiling into Javascript source code text appears to be allowed. (Not a joke, there is a commercial compiler that does this.) Compiling into bytecode for execution by an interpreter written Javascript and running in a UIWebView may confuse the reviewers enough to possibly reject an app doing that.
The iOS security sandbox will likely kill any app that tries to jump into any dynamically generated data.
That is right.
You can read in the iOS standard agreement, which you need to accept when setting up your developer enrollment:
3.3.2 An Application may not download or install executable code.
Interpreted code may only be used in
an Application if all scripts, code
and interpreters are packaged in the
Application and not downloaded. The
only exception to the foregoing is
scripts and code downloaded and run by
Apple's built-in WebKit framework.
JIT compiling into Javascript source code text appears to be allowed. (Not a joke, there is a commercial compiler that does this.) Compiling into bytecode for execution...
I also made my thoughts about a compiler (not JIT but real programming language) running on iOS. My idea was using addresses to assembler-written functions implementing pseudo-opcodes as instructions instead of "traditional bytecode" (1 byte per pseudo-opcode).
One ARM register is reserved as "code pointer" (here named "rCP") pointing into my "bytecode". The last instruction of a pseudo-opcode-function is "ldmfd rCP!, {pc}". This means the last instruction of the function is not a "return" but a jump into the next opcode.
Using this method you get very fast "bytecode". Maybe the commercial compiler works like this. I cannot believe that there is a JIT compiler running native code on iOS.

Resources