编译原理以及什么是静态库和动态库
为什么本人将编译原理和静态库,动态库放在一起讲.因为只有理解了编译的原理,才能真正明白什么是静态库和动态库.
1.编译原理
编译分为四大过程:预处理-编译-汇编-链接
1.1预处理:
完成宏替换、文件引入,以及去除空行、注释等为编译做准备。
也就是对各种预处理命令进行处理,包括头文件的包含、宏定义的扩展、条件编译的选择等。
1.2编译:
第二步进行的是编译阶段,将预处理后的代码编译成汇编代码,在这个阶段中,首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,再把代码翻译成汇编语言。
编译程序工作时,先分析,后综合。所谓分析,是指词法分析和语法分析;所谓综合是指代码优化,存储分配和代码生成。为了完成这些分析综合任务,编译程序采用对源程序进行多次扫描的办法,每次扫描集中完成一项或几项任务,也有一项任务分散到几次扫描去完成的。下面举一个四遍扫描的例子:第一遍扫描做词法分析;第二遍扫描做语法分析;第三遍扫描做代码优化和存储分配;第四遍扫描做代码生成。
值得一提的是,大多数的编译程序直接产生机器语言的目标代码,形成可执行的目标文件,但也有的编译程序则先产生汇编语言一级的符号代码文件,然后再调用汇编程序进行翻译加工处理,最后产生可执行的机器语言目标文件。
1.3汇编:
汇编阶段是把编译阶段生成的”.s”文件转成二进制目标代码,也是所谓的机器代码,01序列。不过它还不可以运行。
1.4链接:
链接就是生成可执行目标文件的过程.
链接是处理可重定位文件,把它们的各种符号引用和符号定义转换为可执行文件中的合适信息(一般是虚拟内存地址)的过程。链接又分为静态链接和动态链接,前者是程序开发阶段程序员用ld(gcc实际上在后台调用了ld)静态链接器手动链接的过程,而动态链接则是程序运行期间系统调用动态链接器(ld-linux.so)自动链接的过程。比如,如果链接到可执行文件中的是静态连接库libmyprintf.a,那么.rodata节区在链接后需要被重定位到一个绝对的虚拟内存地址,以便程序运行时能够正确访问该节区中的字符串信息。而对于puts,因为它是动态连接库libc.so中定义的函数,所以会在程序运行时通过动态符号链接找出puts函数在内存中的地址,以便程序调用该函数。
静态链接过程主要是把可重定位文件依次读入,分析各个文件的文件头,进而依次读入各个文件的节区,并计算各个节区的虚拟内存位置,对一些需要重定位的符号进行处理,设定它们的虚拟内存地址等,并最终产生一个可执行文件或者是动态链接库。这个链接过程是通过ld来完成的,ld在链接时使用了一个链接脚本(linker scripq),该链接脚本处理链接的具体细节。
链接器需要把多个可链接目标文件组合形成一个可执行目标文件,它会收集各个模块中相同类型的节然后组成可执行文件的对应的节,比如:收集foo.o和bar.o的.data节,然后合并在一起组成可执行文件的.data节。链接器还需要完成重定位,因为在合并节时,原来模块节的地址会改变,所以重定位就是修改模块中指针的地址。
完成连接之后,在磁盘上就会生成可执行目标文件。要执行一个程序时,必须要把可执行目标文件载入内存。我们知道,进程是程序执行的容器,每个运行的程序都有自己的内存地址空间,需要将可执行目标文件中数据和代码节载入到进程的地址空间。
2.什么是静态库和动态库
2.1什么是库
2.1.1静态库和动态库都是库,那什么是库呢?
库是程序代码的集合,是共享程序代码的一种方式
是编译好的二进制文件,用于在链接阶段同目标代码一起生成可执行文件,或者运行可执行文件的时候被加载,以便调用库文件中的某段代码。它与可执行文件相同之处是:两者都是编译好的二进制文件(在此我们讨论的二进制文件,假设都是Linux上面最常见的ELF格式);与可执行文件不同的是:库文件无法直接执行(直观上来看它的源代码中没有main函数,而只是一些函数模块的定义和实现,没有运行的入口主函数,所以无法直接执行)。我们开发的程序,无论是运行的时候,还是编译、链接的时候,一般都需要借助一些库来实现它们的功能,而很少直接只通过程序源代码生成完全独立的可执行文件。
2.1.2.库的分类
根据源代码的公开情况,库可以分为2种类型
(1)开源库
公开源代码,能看到具体实现
比如SDWebImage、AFNetworking
(2)闭源库
不公开源代码,是经过编译后的二进制文件,看不到具体实现
主要分为:静态库、动态库
2.2什么是静态库
静态库实际就是一些目标文件(一般以.o结尾)的集合,静态库一般以.a结尾,只用于链接生成可执行文件阶段。
在链接步骤中,连接器将从库文件取得所需的代码,复制到生成的可执行文件中。这种库称为静态库,其特点是可执行文件中包含了库代码的一份完整拷贝;缺点就是被多次使用就会有多份冗余拷贝。
2.3什么是动态库
动态库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用。使用动态库的优点是系统只需载入一次动态库,不同的程序可以得到内存中相同的动态库的副本,因此节省了很多内存。