GNU工具链系列(二): 编译调试套装
- 概述
- 运行时库简介
- Binutils 工具集
- GCC C/C++ 编译器
- GDB 调试工具
- IDE 环境
1. 概述
GCC 一般有两个解释(下文中除非特殊说明,GCC 指广义工具链集合):
- GNU Compiler Collection:GNU 编译工具链集合,能编译多种语言
- GNU C Compiler:GNU C/C++ 编译器
同时 GCC 还有 windows 版本:MinWG(Minimalist GNU for Windows)
接下来一共分为个部分总结:
- 运行时库简介
- Binutils 工具集
- GCC C/C++ 编译器
- GNU Project Debugger 调试工具
2. 运行时库简介
2.1 关于库的基础知识
众所周知,库文件有两种:
- 静态链接库(.a,.lib):编译时链接
- 动态链接库(.so,.dll):运行时链接
其中动态链接库也叫共享库,因为其在内存中只有一份副本,所有的程序共用这些函数
2.2 C/C++标准库
参考链接:[理清 gcc、libc、libstdc++的关系 | 唐装鼠的博客 | CSDN]
该文标注了来源,但是源网站似乎已经挂了…
C/C++标准一部分描述了语法定义,一部分定义了标准库的接口(但并没有实现)
而 GCC 库则是对标准中定义的库的实现
库文件 | 描述 |
---|---|
glibc | GNU C 标准库,后成为 Linux 的标准 C 库(动态库) |
libstdc++ | GNU C++标准库,与 GCC 绑定安装 |
eglibc | 一个面向嵌入式系统的 C 库 |
newlib | 另一个面向嵌入式系统的 C 库 |
- C 标准库与 Linux 操作系统高度绑定(Linux 自带 C 标准库)
C 标准库是 Linux 系统中最底层的 API,封装了很多系统调用
同时其也封装了一些上层应用函数的必要功能(如 string,malloc,signal 等)
最开始 Linux 使用的 C 标准库是 libc,后来用过 klibc,uclibc.现在使用最多的就是 glibc(Debian,Redhat 都是 glibc 及其变种) - C++标准库不与操作系统绑定(以下以 libstdc++举例)
libstdc++与 GCC 绑定(安装 GCC 时自动安装 libstdc++)
但是 libstdc++不与内核打交道,而是通过 glibc 调用内核功能
3. Binutils 工具集
参考资料链接:[GCC 工具链基础 | suda-morris 个人博客]
Binutils 是一组二进制程序的处理工具:
工具 | 作用 |
---|---|
addr2line | 可以从程序地址得到源文件中对应的代码行,可以帮助调试器定位代码位置 |
as | 汇编工具 |
ld | 链接工具 |
ar | 用于创建静态库 |
ldd | 可以用于查看一个可执行程序依赖的共享库 |
objcopy | 转换可执行文件的格式(如.bin 转换为.elf) |
objdump | 反汇编工具 |
readelf | elf 文件查看工具 |
size | 列出可执行文件每个部分的尺寸和总尺寸,代码段,数据段,总大小等 |
4. GCC C/C++ 编译器
参考资料链接:[GCC 工具链基础 | suda-morris 个人博客]
4.1 GCC 编译选项
参数 | 功能 |
---|---|
-o | 指定生成文件名 |
-E | 生成.i 格式的预处理文件 |
-S | 生成.s 格式的汇编文件 |
-c | 生成.o 格式的中间文件 |
-g | 生成必要的符号信息(调试时要用) |
-m32 | 生成 32 位程序 |
-I\ |
添加头文件搜索目录 |
-nostdinc | 不使用标准库 |
4.2 gcc 与 g++的异同
有一说一,国内各个博客网站瞎抄严重(csdn,博客园,知乎,甚至包括 github pages)
最后在 stackoverflow 上找到了一个比较靠谱的回答:[What is the difference between g++ and gcc? | stackoverflow]
- gcc 和 g++都是 GCC 的编译器驱动器,他们会根据具体的文件类型调用合适的编译器(可以使用-x language 显式指定语言)
- gcc,g++最大的区别在于其自动链接的库不同
g++
完全相当于gcc -xc++ -lstdc++ -shared-libgcc
(相关资料:link options, how g++ is invoked,参考自最高赞,没有考证)- 对于
.cpp
,二者都看做 c++文件,对于.c
,g++看做 c++文件,gcc 看做 c 文件
5. GDB 调试工具
参考资料:
[GDB 调试指南 | 守望的个人博客]
[gdb 调试利器 | Linux Tools Quick Tutorial]
GDB 全称 GNU Project Debugger,是一个开源调试器
5.1 启动调试
5.1.1 准备被调试程序
GDB 调试会使用到程序的符号表,所有在编译的时候需要添加-g
选项
1 | gcc -g hello.cpp -o hello |
5.1.2 启动并调试一个程序
1 | gdb 直接跟被调试程序名(需要有符号表段) |
5.1.3 根据 core 文件调试
参考资料:
[Linux 下 gdb 调试生成 core 文件并调试 core 文件 | wkd_007 的博客 | CSDN]
[Linux core 文件介绍 | dzqabc 的博客]
程序在崩溃的时候,Linux 系统会把其内存的数据和调试信息保存为一个 core 文件以备后续调试
1 | 使用该命令可以查看系统对core文件的大小设置 |
gdb 可以利用 core 文件进行调试
1 | 1. 直接调试core文件,然后通过查看堆栈来手动定位错误位置 |
5.1.4 连接一个运行中的程序
1 | 以下命令如果出现如下错误提示 |
5.2 GDB 命令
5.2.1 断点命令
查看断点信息
1
info breakpints
设置断点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22# 1. 设置普通断点(break命令可以简写为b)
break [file:]函数名/行号
# 2. 设置条件断点
break [file:]函数名/行号 if <expression>
# 可以使用condition修改条件断点行号(其中断点号属于断点信息)
condition 断点号 <expression>
# 3. 根据规则批量设置断点
# 在所有函数头处设置断点
rbreak [file:].
# 在所有以print开头的函数头处设置断点
rbreak [file:]^print
# 4. 设置单次临时断点
tbreak [file:]函数名/行号
# 5. 跳过指定断点指定次数
ignore 断点号 跳过次数
# 6. 设置变量断点(变量变化时中断)
watch 变量名开启/禁用断点
1
2
3
4# 如果没有指定断点号,则对所有断点生效
# 如果在enable指令中添加了delete选项,在断点触发后删除该断点
enable [delete] [断点号]
disable [断点号]清除断点
1
2
3
4# 如果没有指定断点号,对所有断点生效(清除所有breakpoint)
clear [file:]函数名/行号
# 如果没有指定断点号,对所有断点生效(清除所有breakpoint,watchpoint,catchpoint)
delete [断点号]5.2.2 变量操作
查看普通变量
1
2
3# print可以简写为p
# 可以打印基本数值类型,数组,字符数组
print ['filename'::]变量名打印指针目标内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22# 其中数量可以使一个数值型的变量
# 格式符指定显示格式
# x 按十六进制格式显示变量
# d 按十进制格式显示变量
# u 按十六进制格式显示无符号整型
# o 按八进制格式显示变量
# t 按二进制格式显示变量
# a 按十六进制格式显示变量
# c 按字符格式显示变量
# f 按浮点数格式显示变量
p[/格式符] ['filename'::]*指针名[@数量]
# 可以使用特殊变量 $ 表示上一个变量
(gdb) p *linkNode
(这里显示linkNode节点内容)
(gdb) p *$.next
(这里显示linkNode节点下一个节点的内容)
# 最后,还可以设置shell风格的变量来辅助操作
(gdb) set $index=0
(gdb) p b[$index++]
(gdb) p b[$index++]显示内存操作
1
2
3
4
5
6
7
8# n 为要显示的内存单元数量
# f 为显示格式,同变量查看格式符一致
# u 为单元长度
# b 字节
# h 双字节
# w 四字节
# g 八字节
x/[n][f][u] 内存地址监视变量(每次中断时显示)
1
2
3
4
5
6
7
8
9
10
11
12# 设置监视变量
display 变量名
# 查看监视变量信息
info display
# 禁用/使能监视变量
disable display 监视变量编号
enable display 监视变量编号
# 清除监视变量
delete display 监视变量编号查看寄存器
1
info registers
5.2.3 调试指令
单步调试
1
2# next可以简写为n
next [步数]进入/退出函数
1
2
3
4
5
6
7
8
9# 进入当前函数,step 可以简写为 s
# 需要有这个函数的调试信息,否则会默认跳过(使用默认行为就好)
step
# 退出当前函数
finish
# 还有一个版本的step:stepi(执行一个机器指令),可以简写为si
stepi执行到下一个中断点
1
2# 可以简写为 c ,可以设置忽略下几次中断
continue [忽略断点次数]执行到指定位置
1
2
3# 可以忽略为u
# 和临时断点基本一样
until [目标行数]跳过执行
1
2
3
4
5
6
7
8
9
10# 查看跳过设置信息
info skip
# 设置跳过
skip [file filename|function funcname]
# 禁用/使能/清除
skip disable 跳过设置信息编号
skip enable 跳过设置信息编号
skip delete 跳过设置信息编号5.2.4 查看源码
相关链接:GDB 调试指南 | 守望的个人博客
查看源码,修改源码再用 GDB 可就太费劲了
vscode 加上插件不要太舒服哈哈哈哈(调试控制台可以使用上述的 GDB 操作)
6. IDE 环境
6.1 vscode 套装
vscode 本身配合插件可以当做一个极致精简的 IDE 来用(功能少但是非常轻便)
本来想单独写一个关于 vscode 的总结,但是需要写的东西也只有一个 launch.json 和一个 task.json
发现知乎上有一个很好的总结就直接省了哈哈哈哈
(一定要安装 Native Debug 插件,非常好用)
参考资料: [VScode tasks.json 和 launch.json 的设置 | 雾色 | 知乎]
6.2 CLion
Clion 是一个 Jetbrains 家的 C/C++ IDE,跨平台,收费但是非常好用
网上的破解码感觉不太靠谱(虽然以前用的也是这个…),去淘宝搜了一圈感觉也不太靠谱
最后决定可以先认证一个 Github 的学生包(有 jetbrains 家 ide 的学生认证),以后有钱再搞正版
首先申请 Github 学生包,如果账号里有学校邮箱,两分钟就申请好了:
[Github 学生包申请 | Github Docs]
然后去 Jetbrains 家注册账号,绑定 Github 学生包(或者自己搜一个教程):
[Jetbrains 学生认证 | CSDN]
Clion 的构建系统也是基于 Cmake 的,下一篇就学 Cmake