从C/C++源程序到可执行文件要经历两个阶段:(1)编译器将源文件编译成汇编代码,然后由汇编器(assembler)翻译成机器代码(再加上其它相关信息)后输出到一个个目标文件(object file,VC的编译器编译出的目标文件默认的后缀名是.obj)中;(2)链接器(linker)将一个个的目标文件(或许还会有若干系统库)链接在一起生成一个完整的可执行文件。
C语言提供了一种将多个目标文件打包成一个文件的机制,这就是静态链接库(static library)。开发者在链接时只需指定程序库的文件名,链接器就会自动到程序库中寻找那些应用程序确实用到的目标模块,并把(且只把)它们从库中拷贝出来参与构建可执行文件。
链接器按照所有目标文件和库文件出现在命令行中的顺序从左至右依次扫描它们,在此期间它要维护若干个集合:(1)集合E是将被合并到一起组成可执行文件的所有目标文件集合;(2)集合U是未解析符号(unresolved symbols,比如已经被引用但是还未被定义的符号)的集合;(3)集合D是所有之前已被加入到E的目标文件定义的符号集合。一开始,E、U、D都是空的(注意:U和D集合存储的是符号(变量的名称,函数的名称等),不是变量的定义,或者函数的定义)
(1): 对命令行中的每一个输入文件f,链接器确定它是目标文件还是库文件,如果它是目标文件,就把f加入到E,并把f中未解析的符号和已定义的符号分别加入到U、D集合中,然后处理下一个输入文件。
(2): 如果f是一个库文件,链接器会尝试把U中的所有未解析符号与f中各目标模块(因为库文件往往是多个obj文件打包起来的,例如静态库文件a.lib是 1.obj和2.obj的合并。1.obj和2.obj就是目标模块,a.lib就是一个库文件)定义的符号进行匹配。如果某个目标模块m定义了一个U中的未解析符号,那么就把m加入到E中,并把m中未解析的符号和已定义的符号分别加入到U、D集合中。不断地对f中的所有目标模块重复这个过程直至到达一个不动点(fixed point),此时U和D不再变化。而那些未加入到E中的f里的目标模块就被简单地丢弃,链接器继续处理下一输入文件。
(3): 如果处理过程中往D加入一个已存在的符号(即redefinition symbols ***错误),,或者当扫描完所有输入文件时U非空(即unresolved symbols ***错误),链接器报错并停止动作。否则,它把E中的所有目标文件合并在一起生成可执行文件。
VC带的编译器名字叫cl.exe,它有这么几个与系统库有关的选项: /ML、/MLd、/MT、/MTd、/