本文内容大部分出自对传智播客linux课程内容的总结和课堂笔记。
1. gdb调试
1.1 使用场景
- 程序编译无误,但是有逻辑错误
- 使用文字终端(shell),实现一个单步调试的功能
生成可执行文件之前必须加参数 -g
-
1.3 查看代码
l — list
l
: 默认打开main函数所在文件,显示前10行l n``[或函数名]
: 显示当前文件的第n行 [ 或某个函数 ]- 如果未打开其他文件,则默认当前文件为main函数所在文件
l filename:n[或函数名]
: 显示文件filename的第n行 [ 或某个函数 ]b — break
- 设置当前文件断点:
b 行号 [ 或函数名 ]
- 设置指定文件断点:
b fileName:行号 [ 或函数名 ]
- 设置条件断点:
b 10 if value==19
- 当value=19时,停止
- 查看断点号:
info break
[i b
]
- 删除指定断点号对应的断点:
d(delete/del)+ 断点号
设置断点是否有效
r(run)
—> 运行程序start
—> 单步执行,运行程序,停在第一行执行语句n(next)
—> 下一行(不会进入到函数体内部)s(step)
—> 下一步(会进入到函数体内部)c(continue)
—> 直接停在断点的位置finish
—> 结束当前函数,返回到函数调用点-
1.7 查看变量的类型
-
1.8 设置变量的值
set var 变量名 = 赋值
作用:比如可以通过给循环控制变量i设置某个值,即可查看循环在i为某个值的执行状态
1.9 设置跟踪变量
追踪变量:
display + 变量名
- 之后每执行一步,该变量值都会被打印出来
-
1.10 退出gdb调试
-
2. makefile的编写
本部分内容只是最基础的makefile的知识,如果有扩展学习的需要,可以参考徐海兵老师翻译整理的GNU make中文手册点此下载
2.1 文件的命名规则
- Makefile
-
2.2 用途
项目代码编译管理
- 节省编译项目的时间
-
2.3 基本规则
三要素:目标、依赖、命令
- 格式:
- 目标 —> 要生成的目标文件
- 依赖 —> 生成目标文件需要的一些文件
- 命令 —> 借助依赖文件生成目标文件的手段
- tab —> 缩进,有且只有一个
- 其他语法:
**#**
是注释**.PHONY**
定义伪目标- 例子:
- 执行伪目标:
make clear
或make clearall
- Makefile会把规则中的第一个目标作为终极目标
- app:all —> all指定生成的最终目标为app
2.4 工作原理
- 若想生成目标,检查规则中的依赖条件是否存在,如果不存在,寻找是否有规则用来生成该依赖文件
- 检查规则中的目标是否需要更新,必须检查它的所有依赖,依赖中有任意一个被更新,则目标必须更新
- 依赖文件比目标文件时间晚,则需要更新
- 生成终极目标的过程:
- 更新目标的工作原理:
- 检查目标和依赖的修改时间,若依赖比目标新,则执行命令更新目标文件
2.5 执行
ma``ke
—> 通过makefile生成终极目标- 直接 make,使用makefile文件
make -f mm
- 指定一个名字不为makefile的文件
make clean
—> 清除编译生成的中间.o文件和最终目标文件普通变量
- 定义变量:变量 = 是替换 变量 += 是追加 变量 := 是恒等于
- 使用变量:$( 变量名 ) 取变量值
- 变量定义及赋值:
obj = a.o b.o c.o
obj += d.o
CC := gcc
- 变量取值:
foo = $(obj)
即foo=a.o b.o c.o d.o
由 Makefile 维护的一些变量
变量(通配符)
- e.g.
main.o:main.c add.c sub.c mul.c dev.c
$@
—> 规则中的目标main.o
$<
—> 规则中的第一个依赖条件main.c
$^
—> 规则中的所有依赖条件main.c add.c sub.c mul.c dev.c
- 都是在规则中的命令中使用
- e.g.
模式规则(隐含规则)
- 在规则的目标定义中使用 %
- 在规则的依赖条件中使用 %
- %.c %.o 任意的.c 或者 .o
- 可以理解为照葫芦画瓢,需要什么,只要格式能对上,%就变成什么
- 比如终极目标依赖./obj/add.o,那么他就会向下查找,找到
%.o:%.c
后,则%=./obj/add,这条规则就变成了./obj/add.o:``./obj/add.c
- 再比如:有一条规则
./obj/%.o:./src/%.c
,则目标依赖./obj/add.o向下查找依赖时,这条规则就变成了./obj/add.o:./src/add.c
,具体应用可参看2.9.3例【3】。有关和%的疑惑可以参考:[makefile的语法及写法(补充:%和的区别)](https://blog.csdn.net/qq_37688116/article/details/68948289)
示例:
makefile中所有的函数必须都有返回值
wildcard + 目录/*.后缀
- 查找指定目录下指定类型的文件,一个参数
src=$(wildcard ./src/*.c)
- 找到./src 目录下所有后缀为.c的文件,赋给变量src
patsubst 格式1, 格式2, 字符串
匹配替换,将字符串中符合格式1的部分用格式2替换
obj = $(patsubst %.c ,%.o ,$(src))
- 从src中找到所有.c 结尾的文件,并将其替换为.o
obj = $(patsubst ./src/%.c, ./obj/%.o, $(src))
- 指定.o 文件存放的路径 ./obj/%.o
dir=$(notdir $(src))
- 去掉src中的路径
- 例子:假设./src中有main.c add.c sub.c mul.c dev.c等
- 像如下图中写的makefile【第一版本】并不好,每次只要有一个.c文件被修改时,都会把所有的.c文件重新编译,会浪费额外的时间,假如项目很大,则效率很低。
- 可以通过添加多条规则解决问题(如下图所示【第二版本】),其中第一条规则中的目标为终极目标,而其他规则中的目标为子目标,子目标是为了生成第一条规则中的依赖条件而存在的。
- 执行make,当要生成第一条规则中的终极目标时,会查找其依赖是否存在;如果不存在,则去下面其他规则中的子目标中查找,看是否有相应子目标可以生成不存在的依赖,有则先执行子目标规则的命令;如果存在,则通过对比目标和所需依赖的修改时间,若所需依赖比目标新,则更新目标文件。
- 执行make结果如下:
- 当只修改add.c文件后,执行make结果如下:
利用变量、隐藏规则、通配符对【第二版本】makefile中冗余的部分改进,使其更精简,生成【第三版本】如下图
利用两个函数将【第三版本】中的obj的写法改进为【第四版本】如下图。如果一个项目很大,含有很多源文件,那么生成可执行文件时,中间就需要生成很多目标文件作为依赖,如果像之前版本中一一列出目标文件,e.g.
obj=main.o a.o b.o c.o ....
很麻烦,可以用查找和匹配替换命令轻松实现。
2.9.2 例【2】
- 我的环境说明:
- 其中已将动态库libmytest.so所在绝对路径追加入到/etc/ld.so.conf文件中
main.c文件中调用位于./lib目录下动态库libmytest.so中的函数add,引用位于./include头文件中的head.h
我编写的makefile文件:
![image.png](https://cdn.nlark.com/yuque/0/2020/png/1912023/1597720448003-97f72f88-9ab4-487b-b610-e0bb2eec0d6b.png#align=left&display=inline&height=278&margin=%5Bobject%20Object%5D&name=image.png&originHeight=278&originWidth=461&size=21079&status=done&style=none&width=461)
2.9.3 例【3】
- 我的环境说明:
- 问题:想要只把src中四个.c文件编译并生成到./obj目录,不生成最终的可执行文件
- 借鉴了别人的方法,使用伪指令的方法实现
- 我编写的makefile文件:
我也是刚刚接触这个东西,自己做了两个小例子,一定不是最优的写法,但是基本上把makefile的基本语法用了一遍,而且效率绝对比写命令行要高的。
3. 简易makefile总结(分五层)
本部分内容为b站某关于makefile的课程笔记,点此查看课程 Makefile是一种脚本语言,Linux C/C++必须使用的一个编译脚本
3.1 第一层:显示规则
[TAB键]指令
说明:第一个目标文件是最终目标,类似递归
例子:
执行:make
- 伪目标:.PHONY :
例子:
执行:make clear 或 make clearall
3.2 第二层:(类似C宏定义)
- 定义变量:变量 = 是替换 变量 += 是追加 变量 := 是恒等于
- 使用变量:$( 变量名 ) 替换
- 示例:
3.3 第三层:隐含规则
%.c %.o 任意的.c 或者 .o
.c .o 所有的.c或者.o
示例:有很多的.o文件待生成 但是其生成规则相同,都是需要gcc -c %.c -o %.o来生成
3.4 第四层:通配符
- 所有的目标文件 $@ 所有的依赖文件 $^ 所有的依赖文件的第一个文件 $<