Makefile
工程中的源文件不计其数,其按类型、功能、模块分别放在若干个目录中。
Makefile文件定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为Makefile文件就像一个shell脚本一样,也可以执行操作系统的命令。
Makefile带来的好处就是"自动化编译",一旦写好只需要一个make命令,整个工程完全自动编译,提高了软件开发的效率。
Makefile文件命名和规则
文件命名
makefile 或者 Makefile
Makefile规则
- 一个Makefile文件中可以有一个或者多个规则
目标 ...: 依赖 ...
命令 (Shell 命令)
...
目标:最重要生成的文件(伪目标除外)
依赖:生成目标所需要的文件或是目标
命令:通过执行命令对依赖操作生成目标(命令前必须Tab缩进)
- Makefile中的其他规则一般都是为第一条规则服务的。
举例:
创建Makefile文件
通过make直接生成app文件
可以运行
Makefile工作原理
命令在执行之前,需要先检查规则中的依赖是否存在
- 如果存在,执行命令
- 如果不存在,向下检查其他的规则,检查有没有一个规则是用来生成整个依赖的,如果找到了,执行该规则中的命令
检测更新 ,在执行规则中的命令时,会比较目标和依赖文件的时间
如果依赖的时间比目标的时间晚,需要重新生成目标。
如果依赖的时间比目标的时间早,目标不需要更新,对应规则中的命令不需要被执行。
举例:
修改Makefile为以下,此时依赖在文件夹中不存在,因此向下检查其他规则生成依赖。
生成app以后,如果不修改.c文件,再进行make,会提示app已为最新,但如果此时修改.c文件,在main.c中加了个换行,再进行make,会先更新main.o,再重新生成app。
这种写法相对于上一种写法的好处在于,如果只有main.c更新了,那么make的时候,只重新编译make.c,但上一种写法会同时编译所有.c。效率优于上一种。
变量
自定义变量
变量名=变量值 var=hello
预定义变量
AR:归档维护程序的名称,默认值为ar
CC:C编译器的名称,默认值为cc
CXX:C++编译器的名称,默认值为g++
$@:目标的完整名称
$<:第一个依赖文件的名称
$^:所有的依赖文件
获取变量的值
$(变量名)
#自动变量只能在规则的命令中使用
app:main.c a.c b.c
$(CC) -c $^ -o $@ 与gcc -c main.c a.c b.c -o app等价
在Makefile中定义变量,可以在规则的命令中简化语法。
模式匹配
%:通配符,陪陪一个字符串
函数
$(wildcard PATTERN ...)
功能:获取指定目录下指定类型的文件列表
参数:PATTERN 指的是某个或多个目录下的对应的某种类型的文件,如果有多个目录,一般使用空格间隔
返回:得到的若干个文件的文件列表,文件名之间使用空格间隔
示例:
$(wildcard *.c ./sub/*.c)
返回值格式: a.c b.c c.c d.c e.c f.c
$(patsubst <pattern>,<replacement>,<text>)
功能:查找<text>中的单词(单词以"空格"、"Tab"或"回车""换行"分隔)是否符合模式<pattern>,如果匹配的话,则以<replacement>替换。
<pattern>可以包括通配符"%",表示任意长度的字串。如果<replacement>中也包含"%",那么,<replacement>中的这个"%"将是<pattern>中的那个"%"所代表的字串。(可以用"\"来转义,以"\%"来表示真正含义的"%"字符)
返回:函数返回被替换过后的字符串
示例:
$(patsubst %.c, %.o, x.c bar.c)
返回值格式:x.o bar.o
make默认只执行第一条命令 clean这条命令可以通过
make clean执行
GDB调试
- GDB 是由 GNU 软件系统社区提供的调试工具,同 GCC 配套组成了一套完整的开发环境,GDB 是Linux 和许多类 Unix 系统中的标准开发环境。
通常,在为调试而编译时,我们会()关掉编译器的优化选项( -o ), 并打开调试选项( -g )。另外, -Wall 在尽量不影响程序行为的情况下选项打开所有 warning,也可以发现许多问题,避免一些不必要的 BUG。
gcc -g -Wall program.c -o program
-g 选项的作用是在可执行文件中加入源代码的信息,比如可执行文件中第几条机器指令对应源代码的第几行,但并不是把整个源文件嵌入到可执行文件中,所以在调试时必须保证 gdb 能找到源文件。
GDB命令
启动和退出
gdb 可执行程序
quit
给程序设置参数/获取设置参数
set args 10 20
show args
GDB使用帮助
help
查看当前文件代码
list/l (从默认位置显示)
list/l 行号 (从指定的行显示)
list/l 函数名 (从指定的函数显示)
查看非当前文件代码
list/l 文件名:行号
list/l 文件名:函数名
设置现实的行数
show list/listsize
set list/listsize 行数
如果直接用gcc test.c -o test
没有使用-g选项,文件中不会包含源代码的信息,导致gdb test, list时,没有符号被读取。
gcc -g -Wall program.c -o program
断点操作
设置断点
b/break 行号
b/break 函数名
b/break 文件名:行号
b/break 文件名:函数
查看断点
i/info b/break
删除断点
d/del/delete 断点编号
设置断点无效
dis/disable 断点编号
设置断点生效
ena/enable 断点编号
设置条件断点(一般用在循环的位置)
b/break 10 if i==5
调试命令
运行gdb程序
start(程序停在第一行)
run(遇见断点才停)
继续运行,到下一个断点停
c/continue
向下执行一行代码(不会进入函数体)
n/next
变量操作
p/print 变量名 (打印变量值)
ptype 变量名 (打印变量类型)
向下单步调试(遇到函数进入函数体)
s/step
finish(跳出函数体)
自动变量操作
display num(自动打印指定变量的值)
i/info display
undisplay 编号
其他操作
set var 变量名=变量值
until(跳出循环)
学习进度
Linux系统编程入门 04:17:14