编译器和自动化构建工具
- 一、编译器——gcc、g++
- 1. 安装 gcc/g++
- 2. 使用
- 3. 链接库
- 4. 拓展命令:od/file/ldd/readelf
- 二、自动化构建项目——make、makefile
- 1. 介绍
- 2. 使用
- 例子
- touch——change file timestamps
- stat——display file or file system status
- 修改时间
- .PHONY和makefile中常用符号@
- 引入.PHONY
- 使用
- makefile中常用符号
- 3. 原理
- 三、调试器——gdb
- 1. 安装
- 2. 使用
- 背景
- 准备工作
- 调试
一、编译器——gcc、g++
gcc和g++的用法一样。主要就是gcc编译C语言的代码,g++编译的C++代码(也可以编译C语言,但是不建议)。所以下面的介绍以gcc为例。
1. 安装 gcc/g++
安装gcc
yum install -y gcc
安装g++
yum install -y gcc-g++ libstdc++-devel
2. 使用
语法:gcc [选项] [要编译的文件] [选项] [目标文件]
选项:
- -o:生成的可执行文件,指定名称
- -static:对生成的文件采用静态链接(链接库讲)
- -E:让gcc在预处理结束后停止编译,生成的后缀为.i的文件是经过预处理的原始程序
- -S:进行编译不进行汇编,生成的后缀为.s的文件是编译生成的汇编语言
- -c:进行汇编操作,生成的后缀为.o的目标文件(可重定位目标二进制文件)是汇编后生成的二进制语言
在之前的程序运行和预处理博客中介绍了改内容,可以回顾一下。
直接编译生成:
预处理:
编译:
汇编:
链接:
说明:既然是链接形成,那需要链接什么呢?将函数的声明和函数的定义联系起来。例如在我们的代码中调用printf函数,但是在stdio.h中只有函数的声明,而函数的实现定义在链接函数库中。
软件:
3. 链接库
源文件在生成可执行程序时,这一步中重要步骤就是链接函数库。而链接库一般分为两种:静态链接库和动态链接库。
C/C++静态库安装:
C语言静态库安装:
yum install -y glibc-static
C++语言静态库安装:yum install -y libstdc++-static
静态链接库:
编译链接时,把库文件的代码全部加入到可执行文件中,因此生成的文件比较大。生成后链接库被删除依旧会正常运行。其后缀名一般为".a"
动态链接库:
编译连接时没有把库文件的代码加入到可执行文件中,而是程序运行时链接文件加载库。节省了系统开销,但是一旦链接库被删除,程序无法运行。其后缀名一般为".so"
产生的可执行文件体积比较:
后缀:
动态库后缀 | 静态库后缀 | |
---|---|---|
Linux | .so | .a |
Windows | .dll | .lib |
拓展:
libname.so.xxx
其中name就是库的名称- C语言标准库:本质就是文件
- 在CentOS7.6,库文件存放在
/usr/lib64
路径下
注意:
- Linux默认生成的二进制程序是使用动态库(共享库),想要使用静态库,则在选项中加-static选项。eg:
gcc [源文件] -o [目标程序] -static
这个目标程序体积会变大。- 如果没有动态库,只有静态库,不加-static,也可以编译生成可执行文件。
-static: 本质改变优先级- 一个程序可以混合使用动静态库,但是加-static所有链接库要求全变成静态库。
4. 拓展命令:od/file/ldd/readelf
od [filename]
命令是一个在Linux系统上用于查看文件的八进制或十六进制表示的工具。它可以读取filename并以指定格式呈现filename内容,用于分析filename的二进制表示,特定的文件分析和调试任务,比如查看文件的特定字节、检查文件的编码或字符集等
file [filename]
命令用于确定给定文件的类型。它通过检查文件的魔术数字(magic number)或文件内容的特征来推断文件的类型。这对于确定一个文件是文本文件、二进制文件还是可执行文件非常有用。可以判断是静态链接还是动态链接。
ldd [filename]
命令用于显示一个可执行文件或共享库所依赖的共享库。可以列出一个二进制文件运行所需的所有动态链接共享库,并提供它们的路径。可以解决缺失的动态链接库或版本冲突的问题。
readelf [选项] [filename]
命令用于显示一个可执行文件或共享库的ELF(可执行与链接格式)格式信息。可以获取有关目标文件(例如二进制文件或库)的很多信息,如文件类型、机器体系结构、节头表、符号表等。readelf命令用于调试和分析目标文件,了解文件的内部细节和元数据。
注意: 可执行程序形成的时候,不是无序的二进制构成,有自己的格式—ELF格式
二、自动化构建项目——make、makefile
1. 介绍
make是一条命令,makefile是一个文件,两者搭配使用完成项目自动化构建。
- make这一命令的作用是解释makefile中指令的命令工具。
- makefile作用就是“自动化编译”,因为一个工程中源文件很多,其按类型、功能和模块分别放在若干目录,makefile制定了一些列的规则来指定,文件编译的先后顺序,是否需要重新编译等功能。一旦写好makefile一个make指令,整个工程完全自动完成编译
2. 使用
例子
makefile文件包含:依赖关系和依赖方法
touch——change file timestamps
stat——display file or file system status
语法:
stat [文件]
展示信息:包括文件的跟踪信息、大小、链接数、所有者、组、权限、状态更改时间、访问时间等,快速了解文件的基本属性
修改时间
语法:
touch [选项] [filename]
选项:
- -a:修改Access时间
- -m:修改Modify时间
- -d:设定时间与日期,可以使用各种不同的格式
- -t: 设定档案的时间记录,格式与 date 指令相同
1. 更新Access时间:
touch -a [filename]
2. 更新Modify时间:
touch -m [filename]
3. 修改Access和Modify为指定时间:
touch -d [filename]
touch -t [filename]
点到为止,这是为下一个.PHONY知识点服务的内容
.PHONY和makefile中常用符号@
引入.PHONY
1. 现象: 连续的make没有被执行
2. 实验:
3. 结论:
当test的Modify时间比依赖关系的源文件test.c的Modify时间更新,make就不会执行,反之就会继续执行。(注意:这里时间比较方式使用时间戳来比较)
使用
如果不通过更改源文件Modify时间的方式,能不能持续make呢?答案:肯定是可以的。
那就需要把它设置成为目标,用
.PHONY
修饰。为目标的特性:总是被执行的
语法:.PHONY [目标文件]
演示:当然具体使用时不是这样去使用
一般使用:这样clean就总是被执行了
makefile中常用符号
$@
替换了依赖关系中:
左侧的内容
$^
替换了依赖关系中:
右侧的内容
注意:我们日常需要编译的源文件可能很多,如果自己添加会很麻烦,使用符号代替就算新增或删除源文件等行为,都不需要进行修改
在依赖方法前添加
@
符号,是在make执行是,不在屏幕上进行回显
使用效果:
3. 原理
当只输入make指令时的工作原理
- make命令会在当前目录下寻找makefile/Makefile(这两个文件名都可以找得到)文件。
- 找到之后,会找makefile中第一个目标文件,也就是上例中的test,并把这个文件当作最终的目标文件
- 如果这个最终文件不存在,并且所依赖的test.c文件的Modify的时间要比test文件新,则它就会执行后面定义的依赖方法来生成test文件
- 如果test所依赖的test.c文件不存在,那么make会在当前文件找test.c文件的依赖性,如果找到则生成,然后返回到上一步骤(有点像堆栈调用)
注意:在寻找过程中,如果依赖文件找不到则直接报错,对于所定义的命令错误,或编译不成功,make根本不理。如果不需要依赖文件,就如同上例中的clean,就直接执行依赖方法。
三、调试器——gdb
1. 安装
yum install -y gdb
2. 使用
背景
- 程序的发布方式有两种:debug模式和release模式。
Linux gcc/g++默认生成的二进制程序就是release模式 - 要使用gdb调试,必须在源代码生成二进制程序时,加上
-g
选项
准备工作
安装gdb:yum install -y gdb
被调试的代码:
makefile中的代码:
查看可执行程序debug信息:
调试
语法:
gdb [可执行文件]
调试时使用的命令:
- Ctrl + d 或 quit(q):退出
- list(l) [行号]:显示改行前后的代码,一次显示十行。下次不输入指令直接回车,接着上次的位置往下列。
- list(l) [函数名]:列出该函数的源代码
- break(b) [行号]:在改行设置断点
- break(b) [函数名]:在函数开头设置断点(有效代码处)
- info break(b):查看断点信息
- disable breakpoints:禁用断点(注意breakpoints是查看断点信息最前面Num那一列的数字)
- enable breakpoints:启用断点
- run( r ):运行程序(相当于vs 2019中的F5)
- continue( c ):执行到下一个断点
- next(n):单条执行(相当于vs 2019中的F10) 逐过程
- step(s):进入函数调用(相当于vs 2019中的F11)逐语句
- print( p ) [变量名]:打印表达式的值,通过表达式可以修改变量的值或调用函数
- display [变量名]:跟踪查看变量,每次停下来都显示它的值(监视窗口)
- undisplay:取消对先前设置变量的跟踪(可以指定编号——也是在最前面一列)
- until [行号]:执行到改行
- breaktrace(bt):查看函数栈帧
- delete breakpoints:删除所有断点(可以跟序号,指定删除某一断点)
- finish:执行到当前函数返回
-
list(l)
-
break(b) / info break(b) / disable breakpoints / enable breakpoints / run( r ) / continue( c )
-
next(n) / step(s)
-
print( p )
-
display / undisplay
-
until
-
breaktrace(bt)
-
delete breakpoints
-
finish