为什么导入.m
文件会导致链接器错误?
PS :如果您发现此问题太小[或摘要]无法解答,请在评论中发帖。我会尝试发布几个场景。但是,这是iOS开发人员很容易熟悉的一般行为。
答案 0 :(得分:0)
以下是构建过程的简要概述。编译器的输入称为"翻译单元"。翻译单元是.m
文件,其中包含所有包含/导入的头文件的内容。它将每个翻译单元分别编译为目标文件(.o
)。每个目标文件都有一个符号表,其中包含在关联的转换单元中定义的所有符号。在此阶段,符号只是可以从生成的代码中引用的名称。然后,链接器的工作是将地址与每个符号相关联,然后通过其地址替换生成的代码中的符号的每个引用,以生成最终的可执行文件。在目标文件的符号表中,您可以使用已定义或未定义的符号。未定义的符号是在目标文件中引用但未在其中定义的符号。链接器需要在此过程的后期在另一个目标文件中找到合适的定义。定义的符号表示目标文件提供符号的定义。当链接器在目标文件的符号表中遇到这样的符号时,它可以立即将其分配给地址。如果稍后它找到另一个具有相同名称的已定义(全局)符号的目标文件,它将以重复的符号错误停止。
我们以下列.m
个文件为例:
A.M:
int my_global;
b.m:
#include "a.m"
my_global = 3;
编译器会看到以下两个翻译单元:
一个:
int my_global;
B:
int my global;
my_global = 3;
它单独处理它们,并发出a.o和b.o,它们的符号表中都有符号my_global
作为定义的符号。当链接器遇到两者中的第二个时,它会抱怨重复的符号。
要解决此问题,您可以创建一个名为a.h
的头文件,其中包含my_global
的外部声明,并包含b.m
中的声明:
A.H
extern int my_global;
b.m
#include "a.h"
my_global = 3;
b翻译单位现在是:
extern int my_global;
my_global = 3;
现在符号将在b.o中未定义,链接器会将其解析为a.o中定义的符号。
有关链接器的更多信息,请阅读this excellent article。