7

为什么当我Xcode 中创建 iOS 静态库项目或框架项目时,我不需要将任何 iOS SDK 框架链接到项目以使用它们的标头和对象——例如,我可以#import <AudioToolbox/AudioToolbox.h>并将AudioToolbox代码放入静态库或框架中,而实际上没有在构建设置中的“Link Binary with Libraries”下添加AudioToolbox或将其显示在文件导航器中,并且项目将毫无问题地构建,这在应用程序项目——但是当开发人员随后在应用程序中使用静态库或框架产品时,他们是否必须链接到框架才能使用相同的标头和对象?

我对为什么会这样有一个模糊的想法,但我真的很想听听肯定知道的人的意见。

4

1 回答 1

11

静态库只是一堆.o文件。它们没有以任何有意义的方式“链接”;只是串联在一起。直到您执行真正的链接步骤才能解析符号。

.a将 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。它保证引用的每个符号都将由这些文件之一提供。它在生成的二进制文件中记下它应该动态加载符号/usr/lib/libc.dylib(这是 libSystem.B.dylib 的符号链接,它本身是一个“伞形框架”而不是一个适当的库,但这有点超出你的需要在大多数情况下要知道;您可以假装它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 文件,没有源代码。只是需要解析符号的目标文件。这就是为什么头文件在这里无关紧要,但在编译时却很重要。

于 2012-04-30T14:29:22.337 回答