zoukankan      html  css  js  c++  java
  • 编译器的工作过程

    目录

    • 为什么需要编译?
    • 第一步 编写配置(configure)文件
    • 为什么需要 configure ?
    • 如何配置?
    • 第二步 确定标准库和头文件的位置
    • 第三步 确定依赖关系
    • 为什么需要确定依赖关系?
    • 为什么先有 configure 脚本,再有 makefile 文件?
    • 第四步 头文件的预编译(Precompilation)
    • 为什么需要进行头文件的预编译?
    • 是不是所有的头文件内容都会被预编译的?
    • 第五步 预处理(Preprocessing)
    • 第六步 编译(Compilation)
    • 这种转码后的文件,称为什么?
    • 第七步 连接(Linking)
    • 静态链接是什么?
    • 动态链接是什么?
    • make 命令的作用是从哪一步到哪一步?
    • 第八步 安装(Installation)
    • 第九步 操作系统连接
    • make install 命令是干啥子用的?

    为什么需要编译?

    源码要运行,必须先转成二进制的机器码。

    这是编译器的任务。

    第一步 编写配置(configure)文件

    为什么需要 configure ?

    编译器在开始工作之前,需要知道当前的系统环境,比如标准库在哪里、软件的安装位置在哪里、需要安装哪些组件等等。

    这是因为不同计算机的系统环境不一样,通过指定编译参数,编译器就可以灵活适应环境,编译出各种环境都能运行的机器码。

    这个确定编译参数的步骤,就叫做"配置"(configure)。

    如何配置?

    这些配置信息保存在一个配置文件之中,约定俗成是一个叫做configure的脚本文件。

    通常它是由autoconf工具生成的。

    编译器通过运行这个脚本,获知编译参数。

    configure脚本已经尽量考虑到不同系统的差异,并且对各种编译参数给出了默认值。

    如果用户的系统环境比较特别,或者有一些特定的需求,就需要手动向configure脚本提供编译参数。

    例如:

    ./configure --prefix=/www --with-mysql
    

    上面的代码的意思是,用户指定安装后的文件保存在www目录,并且编译时加入mysql模块的支持。

    第二步 确定标准库和头文件的位置

    源码肯定会用到标准库函数(standard library)和头文件(header)。

    它们可以存放在系统的任意目录中,编译器实际上没办法自动检测它们的位置,只有通过配置文件才能知道。

    编辑好 configure 文件后,编译的第二步,就是从配置文件中知道标准库和头文件的位置。

    一般来说,配置文件会给出一个清单,列出几个具体的目录。

    等到编译时,编译器就按顺序到这几个目录中,寻找目标。

    第三步 确定依赖关系

    为什么需要确定依赖关系?

    对于大型项目来说,源码文件之间往往存在依赖关系,编译器需要确定编译的先后顺序。

    假定A文件依赖于B文件,编译器应该保证做到下面两点。

    (1)只有在B文件编译完成后,才开始编译A文件。
    (2)当B文件发生变化时,A文件会被重新编译。

    编译顺序保存在一个叫做makefile的文件中,里面列出哪个文件先编译,哪个文件后编译。

    为什么先有 configure 脚本,再有 makefile 文件?

    而makefile文件由configure脚本运行生成,这就是为什么编译时configure必须首先运行的原因。

    在确定依赖关系的同时,编译器也确定了,编译时会用到哪些头文件。

    第四步 头文件的预编译(Precompilation)

    为什么需要进行头文件的预编译?

    不同的源码文件,可能引用同一个头文件(比如stdio.h)。

    编译的时候,头文件也必须一起编译。为了节省时间,编译器会在编译源码之前,先编译头文件。

    这保证了头文件只需编译一次,不必每次用到的时候,都重新编译了。

    是不是所有的头文件内容都会被预编译的?

    不过,并不是头文件的所有内容,都会被预编译。用来声明宏的#define命令,就不会被预编译。

    第五步 预处理(Preprocessing)

    预编译完成后,编译器就开始替换掉源码中bash的头文件和宏。

    编译器在这一步还会移除注释。

    这一步称为"预处理"(Preprocessing),因为完成之后,就要开始真正的处理了。

    第六步 编译(Compilation)

    预处理之后,编译器就开始生成机器码。

    对于某些编译器来说,还存在一个中间步骤,会先把源码转为汇编码(assembly),然后再把汇编码转为机器码。

    这种转码后的文件,称为什么?

    这种转码后的文件称为对象文件(object file)。

    第七步 连接(Linking)

    对象文件还不能运行,必须进一步转成可执行文件,因为还有一些外部的函数库代码没有集成进去。

    静态链接是什么?

    编译器的下一步工作,就是把外部函数的代码(通常是后缀名为.lib和.a的文件),添加到可执行文件中。这就叫做连接(linking)。这种通过拷贝,将外部函数库添加到可执行文件的方式,叫做静态连接(static linking)

    动态链接是什么?

    其实就是共享库的应用。

    make 命令的作用是从哪一步到哪一步?

    make命令的作用,就是从第四步头文件预编译开始,一直到第七步连接。

    第八步 安装(Installation)

    上一步的连接是在内存中进行的,即编译器在内存中生成了可执行文件。

    下一步,必须将可执行文件保存到用户事先指定的安装目录。

    表面上,这一步很简单,就是将可执行文件(连带相关的数据文件)拷贝过去就行了。

    但是实际上,这一步还必须完成创建目录、保存文件、设置权限等步骤。

    这整个的保存过程就称为"安装"(Installation)。

    第九步 操作系统连接

    可执行文件安装后,必须以某种方式通知操作系统,让其知道可以使用这个程序了。

    比如,我们安装了一个文本阅读程序,往往希望双击txt文件,该程序就会自动运行。

    这就要求在操作系统中,登记这个程序的元数据:文件名、文件描述、关联后缀名等等。

    Linux系统中,这些信息通常保存在/usr/share/applications目录下的.desktop文件中。

    另外,在Windows操作系统中,还需要在Start启动菜单中,建立一个快捷方式。

    这些事情就叫做"操作系统连接"。

    make install 命令是干啥子用的?

    make install命令,就用来完成第八步"安装"和第九步"操作系统连接"这两步。

    第十步 生成安装包

    写到这里,源码编译的整个过程就基本完成了。

    但是只有很少一部分用户,愿意耐着性子,从头到尾做一遍这个过程。

    事实上,如果你只有源码可以交给用户,他们会认定你是一个不友好的家伙。

    大部分用户要的是一个二进制的可执行程序,立刻就能运行。这就要求开发者,将上一步生成的可执行文件,做成可以分发的安装包。

    所以,编译器还必须有生成安装包的功能。

    通常是将可执行文件(连带相关的数据文件),以某种目录结构,保存成压缩文件包,交给用户。

    ——

    本文整理自阮一峰的博客

  • 相关阅读:
    dom操作
    今天学到的知识点
    3.26随笔
    dom操作
    Ajax
    JSP、EL、JSTL
    Cookie和Session
    HttpServletResponse
    Servlet
    tomcat
  • 原文地址:https://www.cnblogs.com/0x1D/p/4712706.html
Copyright © 2011-2022 走看看