程序编译过程

来源:互联网 发布:java semaphore 实现 编辑:程序博客网 时间:2024/05/17 20:29

程序编译过程

摘要:本文主要基于linux架构,介绍程序编译的主要过程。希望可以对程序的编译过程有简单清楚的解释,方便大家理解。并在这个过程中,对makefile,.so,.o,config等文件与make,make config, make install等过程有更形象的理解。本文完全按照自己的思路整理,如果有某些地方欠妥,希望指出,能有更好的改进。


写程序阶段

当我们编写程序时,首先要确定我们使用的编程语言。比如:C,C++,Python,Java等。在确定的编程语言下,我们使用其特定的编写规范,完成我们程序的编写。这当中主要有两个问题:1.我们需要链接哪些库函数。2.我们要使用遵循语言哪个版本的标准。

通常,我们不会关注版本问题,因为不同版本支持的不同特性基本都很偏。但是,我们在Linux下经常遇到的问题是,我们所调用的一些库文件没有安装。这个时候,我们会根据缺失或报错信息,安装对应的包,如:apt-get install lib***-dev。这个过程就是将我们需要的库文件配置到我们系统中(通常放到usr/lib目录下,现在usr全称为Unix System Resource,专门存放各种软件程序以及共享文件,以前为user的简称,相当于HOME目录),让我们可以使用这些库函数。

 

编译阶段

编译过程就是将源码生成可执行文件。首先,我们这里针对的是较多文件的工程,所以,如何编译整个工程是我们要面对的首要问题。不像Windows中可以在编译器中创建工程,直接编译整个工程。Linux下,我们需要一个模块去组织我们编译工程的工作 —— makefile文件。Makefile文件主要表达了我们编译工程中所有文件的顺序,以及相互依赖关系,最后组成一个 ***.o对象文件。而我们所需要做的操作就是进入到工程主目录,在命令行运行make命令,完成这一过程。

编译阶段是很复杂的,包括:编译预处理,编译优化,汇编三个主要过程。Make过程中,编译器会先进行编译预处理,编译预处理主要做两件事:

l  处理#include。看我们依赖的头文件是否都存在。并把他们的内容插到相应位置。

l  处理#define。将定义的宏用实际字符串代替。

之后为编译过程,主要查看代码是否符合规范,以及是否有语法错误。如果都正确,就将其翻译为汇编代码。

最后为汇编过程,将汇编代码转换为二进制文件 ***.o。

 

链接阶段

虽然我们成功编译了,但这时只是说我们的程序没有问题了,并不代表我们的程序是可以运行的。因为,我们在编译过程中只是链接了各个库函数的头文件,但头文件中一般只是写了函数的声明,并没有实际的函数定义。而这些函数库要么是放在工程目录下,要么是放在系统usr/lib目录下。我们必须确定我们能找到所有依赖的库文件,才能保证程序的正常运行。

所以这就是链接阶段要解决的主要问题。链接方式有两种:静态链接与动态链接。

静态链接指编译过程中,已经把库文件的内容加入到了可执行文件中。这样做使运行时无需再链接库文件。但弊端是导致可执行文件太大。

动态链接就是我们上述所说编译过程,所以链接阶段需要先根据链接文件加载所需要的库文件。系统会从相应的库文件目录下寻找,如果找齐,则运行成功。如果有些库文件不存在,则需要我们安装相应库文件。

 

相关内容

至此,通常的工程编译运行过程已经叙述完了。但我们可以发现,对于一些大型的工程文件,比方典型的Linux内核代码。初始时,文件中是没有makefile文件的。而是有大量的config文件。这是因为这些工程在编译前,可以设定一些参数,以及选择编译哪些模块内容。所以在config文件中进行设定选择,再通过make menuconfig 等类似过程生成对应你设定选择的makefile文件。同样make 之后,可能会需要将大工程的一些文件放到系统文件中,方便调用,make install就是该过程(可以理解为Windows下***.exe安装游戏的过程….),为大量的文件拷贝。

 

致谢

感谢伙伴们与我的分享总结,当然本文肯定还不完善,希望大家可以提供更好的讲解,一同进步。