为什么确切是当我在 Xcode 中创建 iOS 静态库项目或框架项目时,我不需要将任何 iOS SDK 框架链接到该项目以利用它们 header 和对象——例如,我可以 #import <AudioToolbox/AudioToolbox.h>
并将 AudioToolbox 代码放入静态库或框架中,而无需在build设置中的“Link Binary with Libraries”下实际添加 AudioToolbox 或将其显示在文件导航器中,并且项目将毫无问题地构建,这在应用程序项目——但是当开发人员随后在应用程序中使用静态库或框架产品时,他们是否必须链接到框架才能使用相同的 header 和对象?
我对为什么会这样有一个模糊的想法,但我真的很想听听确切知道的人的意见。
最佳答案
静态库只是一堆 .o
文件。他们没有以任何有意义的方式“联系”;只是连接在一起。直到您执行真正的链接步骤,符号才会被解析。
将 .a
链接到您的可执行文件与将等效源代码复制到您的可执行文件的项目中基本上没有区别。因此,在那之前无需链接任何其他框架或库。
以下练习可能具有教育意义:
创建以下comptest.c
:
#include <stdio.h>
int main() {
printf("Hello world.\n");
return 0;
}
查看预处理器做了什么:
gcc -E comptest.c > comptest-cpp.c
这会删除 #include
并将其替换为引用文件的内容。这个文件是编译器实际看到的。
现在看看编译器做了什么(我在此处和下面使用 >
语法,以便与 -E
并行):
gcc -S comptest.c > comptest.s
这是预处理和编译后生成的汇编语言。现在我们把它变成一个 .o:
gcc -c comptest.c > comptest.o
现在让我们看看那个 .o 里有什么:
$ nm comptest.o
0000000000000040 s EH_frame0
000000000000002d s L_.str
0000000000000000 T _main
0000000000000058 S _main.eh
U _puts
这里重要的是_main
和_puts
。 _main
在此文件中的地址 0 处定义。_puts
未定义。所以我们链接的东西最好提供它。让我们尝试不带任何链接:
$ gcc -nodefaultlibs comptest.o
Undefined symbols for architecture x86_64:
"_exit", referenced from:
start in crt1.10.6.o
"_puts", referenced from:
_main in comptest.o
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
(_exit
隐含在 C 运行时;它不在 .o 中直接引用)
好的,现在我们已准备好将它们放在一起。我们将明确:
gcc -nodefaultlibs comptest.o /usr/lib/libc.dylib -o comptest
这表示将 comptest.o
和动态库 libc
链接在一起。它 promise 引用的每个符号都将由这些文件之一提供。它在生成的二进制文件中注明它应该从 /usr/lib/libc.dylib
动态加载符号(这是 libSystem.B.dylib 的符号链接(symbolic link),它本身就是一个“伞形框架”而不是一个合适的库,但在大多数情况下,这超出了您需要了解的内容;您可以假装 puts()
在 libSystem 中:
$ otool -L comptest
comptest:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)
如果你链接一个静态库,它等同于在命令行列出它包含的所有.o 文件。
请注意,在链接步骤中,我们只有 .o 和 .dylib 文件(.a 只是 .o 的一个包)。没有 .c 文件,没有 .h 文件,没有 .s 文件,没有源代码。只是需要解析符号的目标文件。这就是为什么头文件在这里不重要,但在编译时很重要。
关于objective-c - 为什么 iOS 框架依赖项在应用程序项目时不需要显式链接到静态库项目或框架项目?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10385331/