Why exactly is it that when I create an iOS static library project or framework project in Xcode, I don’t need to link any iOS SDK frameworks to the project in order to make use of their headers and objects — for example, I can #import <AudioToolbox/AudioToolbox.h> and put AudioToolbox code in the static library or framework without actually having AudioToolbox added under “Link Binary with Libraries” in build settings or having it present in the file navigator, and the project will build without issue, something that wouldn’t work in an app project — but when a developer then uses the static library or framework product in an app, they do have to link to the framework in order to use the same headers and objects?
I have a vague idea of why this would be, but I’d be really interested in hearing from someone who knows for sure.
Static libraries are just a bundle of
.ofiles. They’re not “linked” in any meaningful way; just concatenated together. It’s not until you perform a real link step that symbols are resolved.There is basically no difference between linking a
.awith your executable and copying the equivalent source code into your executable’s project. So there’s no need to link with any additional frameworks or libraries until that time.The following exercise may be educational:
Create the following
comptest.c:See what the pre-processor does:
This removes the
#includeand replaces it with the contents of the referenced file. This file is what the compiler actually sees.Now see what the compiler does (I’m using the
>syntax here and below so that things are parallel with-E):This is the generated assembly language after pre-processing and compilation. Now we turn that into a .o:
Now let’s see what’s in that .o:
The important things here are
_mainand_puts._mainis defined in this file at address 0._putsis undefined. So something we link with had better provide it. Let’s try linking without anything:(
_exitis implicit from the C runtime; it’s not directly referenced in the .o)OK, so now we’re ready to put it all together. We’ll be explicit:
This says to link together
comptest.oand the dynamic librarylibc. It promises that every symbol referenced will be provided by one of these files. It makes a note in the resulting binary that it should dynamically load symbols from/usr/lib/libc.dylib(this is a symlink to libSystem.B.dylib, which is itself an “umbrella framework” rather than a proper library, but that goes a little past what you need to know in most cases; you can pretend thatputs()is in libSystem):If you link with a static library, it’s identical to listing all the .o files included in it on the command-line.
Notice that at the link step, we just have .o and .dylib files (.a is just a package of .o). There are no .c files, no .h files, no .s files, no source code. Just object files that need symbols resolved. This is why header files don’t matter here, but do matter when you’re compiling.