c++ 编译过程

2023-05-16

c++ 编译过程引入

常见:
用gcc、g++指令生成可执行文件,对于大点的项目,则是:

$ ./configure
$ make  
$ make install

这背后。到底发生了什么?
当然,纯粹的编译过程就是老生常谈的编译四部曲,configure这个也可以理解成一种软件构件过程,但毕竟和编译息息相关,说白了configure这一套操作就是帮助编译的管理,所以就放一起谈也能解惑不少
以下主要参考:阮一峰大神的编译器的工作过程http://www.ruanyifeng.com/blog/2014/11/compiler.html
Linux编译安装中configure、make和make install各自的作用详解:
https://blog.csdn.net/qq_27825451/article/details/102605219

看看这些命令

https://blog.csdn.net/stone_fall/article/details/108602898

configure干的事情

第一步 配置(configure)

编译器在开始工作之前,需要知道当前的系统环境,比如标准库在哪里、软件的安装位置在哪里、需要安装哪些组件等等。这是因为不同计算机的系统环境不一样,通过指定编译参数,编译器就可以灵活适应环境,编译出各种环境都能运行的机器码。这个确定编译参数的步骤,就叫做"配置"(configure)。

这些配置信息保存在一个配置文件之中,约定俗成是一个叫做configure的脚本文件。通常它是由autoconf工具生成的。编译器通过运行这个脚本,获知编译参数。

configure脚本已经尽量考虑到不同系统的差异,并且对各种编译参数给出了默认值。如果用户的系统环境比较特别,或者有一些特定的需求,就需要手动向configure脚本提供编译参数。

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

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

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

源码肯定会用到标准库函数(standard library)和头文件(header)。它们可以存放在系统的任意目录中,编译器实际上没办法自动检测它们的位置,只有通过配置文件才能知道。

编译的第二步,就是从配置文件中知道标准库和头文件的位置。一般来说,配置文件会给出一个清单,列出几个具体的目录。等到编译时,编译器就按顺序到这几个目录中,寻找目标。

第三步 确定依赖关系

对于大型项目来说,源码文件之间往往存在依赖关系,编译器需要确定编译的先后顺序。假定A文件依赖于B文件,编译器应该保证做到下面两点。

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

编译顺序保存在一个叫做makefile的文件中,里面列出哪个文件先编译,哪个文件后编译。而makefile文件由configure脚本运行生成,这就是为什么编译时configure必须首先运行的原因。
在确定依赖关系的同时,编译器也确定了,编译时会用到哪些头文件。

然后是第四步编译过程了,这也是make命令的作用,这里编译过程我单独截取处理放到后面再谈

第五步安装和操作系统链接

编译完成即make之后,就是安装了,编译生成了可执行文件,但如果要做的方便使用,何妨把一些可预知的步骤做完。
这也是make install的作用了:
表面上,这一步很简单,就是将可执行文件(连带相关的数据文件)拷贝过去就行了。但是实际上,这一步还必须完成创建目录、保存文件、设置权限等步骤。这整个的保存过程就称为"安装"(Installation)。
可执行文件安装后,必须以某种方式通知操作系统,让其知道可以使用这个程序了。比如,我们安装了一个文本阅读程序,往往希望双击txt文件,该程序就会自动运行。
这就要求在操作系统中,登记这个程序的元数据:文件名、文件描述、关联后缀名等等。Linux系统中,这些信息通常保存在/usr/share/applications目录下的.desktop文件中。另外,在Windows操作系统中,还需要在Start启动菜单中,建立一个快捷方式。
这些事情就叫做"操作系统连接"。make install命令,就用来完成"安装"和"操作系统连接"这两步。

第六步 生成安装包

这步开始还么搞懂,什么生成安装包了?,,
写到这里,源码编译的整个过程就基本完成了。但是只有很少一部分用户,愿意耐着性子,从头到尾做一遍这个过程。事实上,如果你只有源码可以交给用户,他们会认定你是一个不友好的家伙。大部分用户要的是一个二进制的可执行程序,立刻就能运行。这就要求开发者,将上一步生成的可执行文件,做成可以分发的安装包。

所以,编译器还必须有生成安装包的功能。通常是将可执行文件(连带相关的数据文件),以某种目录结构,保存成压缩文件包,交给用户。

第七步 可能存在的动态链接

正常情况下,到这一步,程序已经可以运行了。至于运行期间(runtime)发生的事情,与编译器一概无关。但是,开发者可以在编译阶段选择可执行文件连接外部函数库的方式,到底是静态连接(编译时连接),还是动态连接(运行时连接)。所以,最后还要提一下,什么叫做动态连接。

前面已经说过,静态连接就是把外部函数库,拷贝到可执行文件中。这样做的好处是,适用范围比较广,不用担心用户机器缺少某个库文件;缺点是安装包会比较大,而且多个应用程序之间,无法共享库文件。动态连接的做法正好相反,外部函数库不进入安装包,只在运行时动态引用。好处是安装包会比较小,多个应用程序可以共享库文件;缺点是用户必须事先安装好库文件,而且版本和安装位置都必须符合要求,否则就不能正常运行。
现实中,大部分软件采用动态连接,共享库文件。这种动态共享的库文件,Linux平台是后缀名为.so的文件,Windows平台是.dll文件,Mac平台是.dylib文件。

老生常谈的编译四部曲

c++ 编译分为四步,编译预处理、编译、汇编、链接。
阮一峰大神这里有个头文件的预编译剥离开,倒是不一样的细节。有的文章直接把预编译和预处理放一块,亦或者称预处理也是预编译,无所谓了,总而言之是编译的前奏。
在这里插入图片描述

预处理(Preprocessing)

预处理又称为预编译,是做些代码文本替换工作。编译器执行预处理指令(以#开头,例如#include),这个过程会得到不包含#指令的.i文件。这个过程会拷贝#include 包含的文件代码,进行#define 宏定义的替换 , 处理条件编译指令 (#ifndef #ifdef #endif)等。
预处理的总结,还未写

编译、汇编

这里也是,在阮一峰大神的文章中说,编译可看成两步,由编译得到汇编码,然后再有汇编码得到机器码,这里其实也无所谓,对于我们理解编译过程来说,只要最后知道是机器码就好了
编译得到汇编码,但其中设计很多优化工作,如删除公共表达式、循环优化(代码外提、强度削弱、变换循环控制条件、已知量的合并等)、复写传播,以及无用赋值的删除,等等,对于硬件,如何充分利用机器的各个硬件寄存器存放有关变量的值,以减少对于内存的访问次数,具体不展开
总的来说,编译程序所要作得工作就是通过词法分析和语法分析,在确认所有的指令都符合语法规则之后,将其翻译成等价的中间代码表示或汇编代码。

汇编过程实际上指把汇编语言代码翻译成目标机器指令的过程。对于被翻译系统处理的每一个C语言源程序,都将最终经过这一处理而得到相应的目标文件。目标文件中所存放的也就是与源程序等效的目标的机器语言代码。

链接

由汇编程序生成的目标文件并不能立即就被执行,其中可能还有许多没有解决的问题。

例如,某个源文件中的函数可能引用了另一个源文件中定义的某个符号(如变量或者函数调用等);在程序中可能调用了某个库文件中的函数,等等。所有的这些问题,都需要经链接程序的处理方能得以解决。

链接程序的主要工作就是将有关的目标文件彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体。

根据开发人员指定的同库函数的链接方式的不同,链接处理可分为两种:

  1. 静态链接

在这种链接方式下,函数的代码将从其所在的静态链接库中被拷贝到最终的可执行程序中。这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。静态链接库实际上是一个目标文件的集合,其中的每个文件含有库中的一个或者一组相关函数的代码。

  1. 动态链接

在此种方式下,函数的代码被放到称作是动态链接库或共享对象的某个目标文件中。链接程序此时所作的只是在最终的可执行程序中记录下共享对象的名字以及其它少量的登记信息。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。

对于可执行文件中的函数调用,可分别采用动态链接或静态链接的方法。使用动态链接能够使最终的可执行文件比较短小,并且当共享对象被多个进程使用时能节约一些内存,因为在内存中只需要保存一份此共享对象的代码。但并不是使用动态链接就一定比使用静态链接要优越。在某些情况下动态链接可能带来一些性能上损害。

这里浅谈一下理解,其实对于怎么用静态库和动态库而言,无非就是,生成可执行文件时,链接的时候,静态库动态库都得有,生成完之后,静态库可以不要了,但是如果链接时用了动态库,那么运行可执行文件时也会需要它,可以看成是一种依赖,其中关系也很好理解

关于动态链接库、静态链接库

静态库(.a、.lib)和动态库(.so、.dll)。 windows上对应的是.lib .dll linux上对应的是.a .so

主要就是区别,而主要区别在于:
二者的不同点在于代码被载入的时刻不同。
1.静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库,因此体积较大。
2.动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在,因此代码体积较小。

动态库和静态库的生成和使用可参考

最后引申一下动态库的显示链接和隐式链接,以及对应的.dll .lib .h文件怎么放,见

与cmake的区别

区别
实际上都是为了生成Makefile文件,然后make编译。

参考:https://www.cnblogs.com/mickole/articles/3659112.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c++ 编译过程 的相关文章

随机推荐

  • 一小时学会Python3爬虫基础(二)基础语法 输入输出 关键字 注释

    目录 前言集成环境 编辑器基本语法缩进换行标识符关键字注释输入 输出总结 前言 python作为一门编程语言 xff0c 也跟其他语言一样有自己的逻辑语法 xff0c 那什么是语法 xff1f 跟人一样每个人都有自己说话一套方法 集成环境
  • windows 生成self-sign证书

    打开powershell 管理员身份运行 New SelfSignedCertificate CertStoreLocation Cert LocalMachine My DnsName 34 mysite local 34 Friendl
  • 一小时学会Python3爬虫基础(四)完整解析格式化输出和数据类型转换

    目录 前言格式化输出格式化符号 s格式化函数format格式化表示 f string 转义符和结束符 n意思就是 换行 new line t 叫做水平制表符 tab xff0c r 是回车符carriage return结束符 数据类型转换
  • 一小时学会Python3爬虫基础(七)高级数据的全部操作:字典

    目录 前言字典1 字典格式2 创建有效字典2 创建空字典3 字典类型转换 字典增加和修改1 增加2 修改 字典查找1 key键查找2 get 3 keys 4 values 5 items 字典循环遍历1 遍历字典的key值2 遍历字典的v
  • Python处理异常代码的基本操作,原来都大同小异!

    目录 什么是异常 xff1f 如何捕获异常 xff1f 1 异常的写法2 捕获指定异常3 捕获多个异常4 捕获异常的描述5 捕获所有异常6 异常的else7 finally8 自定义异常模块9 异常传递思路 总结 什么是异常 xff1f 简
  • python的模块与包的关系

    模块和包的概念 python中的模块 xff0c 其实就是一个python的文件 xff0c 包含了很多类和函数 xff0c 基本上都是可以向外调用的 xff0c 或者整个文件都用来处理某个操作 xff0c 我们使用库和框架就是由模块和包构
  • 一小时学会Python基础练习的十四个练手题

    目录 1到100的加法搬家具办公室人员分配猜拳游戏乘公交车吃苹果九九乘法表烤地瓜奇偶100内相加三角形正方形文件备份学员管理系统 xff08 函数版 xff09 学员管理系统 xff08 面向对象版 xff09 mainmangerSyst
  • ROS Topic (话题通信总结)

    拿到一个功能包 xff0c 先运行一下 xff08 以turtlesim为例子 xff09 xff1a rusrun turtlesim turtlesim node 然后使用 rqt graph 和rostopic list 大致了解有哪
  • vector函数用法

    一维 基本用法 xff1a 1 头文件 include lt vector gt 2 创建vector对象 xff0c vector lt int gt vec 3 尾部插入数字 xff1a vec push back a 4 使用下标访问
  • Jetson nano串口的使用——UART

    UART串口使用两条杜邦线就可以实现数据发送和接收 xff0c 可以很方便的与其他扩展进行数据连接 xff0c 比如微雪的L76X GPS HAT就可以直接连接40Pin的GPIO接口通过UART串口进行数据传递 接下来具体说明Jetson
  • Python中[-1]、[:-1]、[::-1]、[n::-1]、[:,:,0]、[…,0]、[…,::-1] 的理解

    在python中会出现 1 1 1 n 1 0 0 1 xff0c 他们分别是什么意思呢 xff0c 这里就来详尽的说一下 xff1a 下面的a 61 1 2 3 4 5 1 xff1a 列表最后一项 1 xff1a 从第一项到最后一项 原
  • 贴片电阻字码阻值对照表

  • 使用sphinx生成python项目文档

    1 pip install sphinx 2 sphinx quickstart 3 修改 conf py import os import sys sys path insert 0 os path abspath 39 39 确保mod
  • 免费商用字体有哪些

    免费商用字体有哪些 一 思源字体 xff0c 可以免费商用的有 思源黑体 xff0c 思源宋体 xff0c 思源柔黑体 二 方正字体 xff0c 方正类字体可以免费商用的有 xff1a 方正仿宋 xff08 简 xff0c 繁 xff09
  • Qt:16进制字符串数据转整数数值函数

    span class token comment 16进制字符串数据转整数数值 span span class token keyword int span Setting span class token operator span sp
  • ESP-12F开发环境

    ESP 12F可以使用arduino IDE快速开发 1 首先安装arduino IDE xff1a 搜索直接下载即可 2 在文件 gt 首选项 gt 附加开发板管理器网址中添加ESP8266开发板 xff1a 网址 xff1a http
  • 第1章 电子设计与制作基础

    1 电子系统的分类 模拟电子系统数字电子系统模拟 数字混合系统微处理器 xff08 单片机 嵌入式 xff09 电子系统 2 电子系统的定义 通常 xff0c 将由电子元器件或部件组成的能够产生 传输 采集或处理电信号及信息的客观实体称为电
  • python requests timeout参数

    首先发一下牢骚 xff1a 不管是抄袭还是转载 xff0c 有点新东西行不行 xff0c 一味的转载有什么用呢 xff1f 东西还以那点东西 xff0c 让想解决问题的人查看一些一摸一样的文章 xff0c 只会浪费查询者的时间 况且 xff
  • c++配置http/post请求接收json数据

    照着教程编译操作都没问题 首先是配置curl库 给一个别人的编译链接curl库 vs2017 xff1a 亲测可用 c 43 43 编译curl库 测试代码 xff1a span class token macro property spa
  • c++ 编译过程

    c 43 43 编译过程引入 常见 xff1a 用gcc g 43 43 指令生成可执行文件 xff0c 对于大点的项目 xff0c 则是 xff1a configure span class token function make spa