Makefile
Make工程管理器的优越性具体体现在以下两方面:
(1)使用方便
通过命令“make”就可以启动Make工程管理器对程序进行编译,所以不再需要每次都输入gcc命令行。Make启动后会根据Makefile文件中的编译规则命令自动对源文件进行编译和链接,最终生成可执行文件。
(2)调试效率高
为了提高编译程序的效率,Make会检查每个源文件的修改时间(时间戳)。只有在上次编译之后被修改的源文件才会在接下来的编译过程中被编译和链接,这样就能够避免多余的编译工作量。为了保证源文件具有正确的时间戳,必须保证源文件具有正确的时间戳,必须保证操作系统时间的正确性
Make工程管理器完全根据Makefile文件中的编译规则进行编译,Makefile由以下三项基本内容组成:
1)需要生成的目标文件(target file)
2)生成目标索取要的依赖文件(dependency file)
3)生成目标文件的编译规则命令行(command)
这三项内容按以下格式进行组织:
target file :dependency file
(TAB)command
Make工程管理器在编译程序时会检查每个以来文件的时间戳,一旦发现某个依赖文件的时间戳比目标文件要新,就会执行目标文件的规则命令来重新生成目标文件。这个过程称为目标文件的依赖规则的检查。
make编译文件的流程如下:
1)Make工程管理器首先会在当前目录下读取Makefile文件
2)查找Makefile文件中的第一个目标文件,这也是Make工程管理器本次编译任务的最终目标。
3)把目标文件的依赖文件当作目标文件进行依赖规则检查,Make工程管理器会根据以下三种情况进行处理
1.如果当前目录下没有或缺少依赖文件, 则执行其规则命令生成依赖文件(比如缺少 a.1文件,则执行命令“cc-c a.c”生成a.o)
2. 如果存在依赖文件, 则把其作为目标文件来检查依赖规则(假设 a. c比 a. o新, 则执行命令“cc-c a. c”更新 a. o)。
3.如果目标文件比所有依赖文件新,则不做处理。
4)递归执行第三步后, 就会得到目标文件 test所有最新的依赖文件了。接着 Make会根据以下三种情况进行处理:
1. 如果目标文件 test不存在(比如第一次编译), 则执行规则命令生成 test。
2. 如果目标文件 test存在, 但存在比 test要新的依赖文件, 则执行规则命令更新 test。
3. 目标文件 test存在,且比所有依赖文件新,则不做处理。
Makefile特性介绍:
1)变量
使用方式为$(变量名)
定义变量的方式由以下几种:
1.“=”
如 a1=$(a2)
2.":="
如 a1:=a.o
3."+=" 通过此方法可给变量追加值
4.“?=” 通过此方法,如果该变量在前面已经定义,则此次定义无效
2)自动推导
为了进一步简化 Makefile的书写, Make工程管理器提供了自动推导的功能。 自动推导功能默认每个目标文件都有一个与之对应的依赖文件。比如 a. o文件有依赖文件 a. c与之对应)。这样在 Makefile中就不需要指定与目标文件对应的依赖文件名了。此外,自动推导功能还能推导出与目标文件对应的基本编译规则命令。
3)伪目标
伪目标不是真正的目标文件,所以通过伪目标可以让Make工程管理器只执行命令,而不用创建实际的目标文件,使用方法为:
make 伪目标名
为了不和真实文件进行混淆,最好用.PHONY对伪目标进行标记。
4)文件查找
为了便于管理和组织,程序的源文件都根据功能的不同放置在不同的子目录中。Makefile提供了一下两种查找方法;
1.VPATH
Make在当前目录找不到源文件的情况下就会自动到VPATH指定的路径中去寻找
VPATH = 目录 : 目录 … (会在目录中依次查找)
2.vpath
与VPATH不同,vpath并不是变量而是关键字。
vpath 模式 目录: 目录
例如: vpath %.c /a :/b
按顺序依次查找a,b目录下所有C文件
5)嵌套执行
把所有源文件的编译规则放在一个Makefile内会让文件显得过于臃肿,所以可以将Makefile分解成多个子Makefile文件,并放置到程序的每个子目录中,,每个子Makefile文件负责每个子目录下的文件编译。Make会先读取总Makefile文件,再调用各个子Makefile文件。这个过程即为嵌套执行。
使用方法: cd 子目录 && $(MAKE)
或
$(MAKE) -c 子目录
6) 条件判断
使用方法: 条件表达式
如果真时执行的文本段
endif
或者:
条件表达式
如果真执行的文本段
else
如果假执行的文本段
endif
条件表达式有四种格式:
1.ifeq(参数1,参数2):比较参数1,参数2是否相同,相同为真
2.ifneq(参数1,参数2):比较参数1,参数2是否不同,不同为真
3.ifdef(参数):参数非空为真
4.ifndf(参数):参数空为真
7)参数
使用方法: $ (函数名 参数 参数)
GDB调试器
GDB是GNU开源组织发布的一个强大的UNIX下的程序调试工具,GDB主要可帮助工程师完成下面4个方面的功能:
1.启动程序,可以按照工程师自定义的要求随心所欲的运行程序。
2.让被调试的程序在工程师指定的断点处停住,断点可以是条件表达式。
3.当程序被停住时,可以检查此时程序中所发生的事,并追索上文。
4.动态地改变程序的执行环境。
通过运行命令“gcc -g test.c -o test”对test.c进行编译,其中参数g的作用是把调试信息加入生成的test可执行文件中,否则GDB就无法对test进行调试。
接下来可以使用命令“gdb app”启动GDB对test进行调试了。
GDB中几个常用的命令如下,格式:(gdb) XXX
1. list(l) :显示程序中的代码,常用使用格式有:
list 输出从上次调用list命令开始往后的10行程序代码。
list - 输出从上次调用list命令开始往前的10行程序代码。
list n 输出第n行附近的10行程序代码。
list function 输出函数function前后的10行程序代码。
2. run (r):启动程序,在run后面带上参数可以传递给正在调试的程序。(gdb) r
3.break(b):在程序中设置断点,当程序运行到指定行上时,会暂停执行。使用格式:break +要设置断点的行号 (gdb)b 15
4.info b:显示断点的情况 (gdb) info b
5.print(p) :打印变量或表达式的值。使用格式: (gdb) print n
6.continue ©:使程序在暂停在断点之后继续运行。(gdb)c
7.step/next:在程序逻辑比较复杂的时候需要程序一步一步的往下运行。在GDB中通过命令”s“(step的缩写)和”n“(next的缩写)让程序一步一步的往下运行。其中s可以发生函数调用时进入函数内部运行,而n不会进入到函数内部运行。