日期:2014-05-16  浏览次数:20433 次

GDB中应该知道的几个调试方法
1. 规则:
target ... : prerequisites ...
command // 必须要以[Tab]键开始,注意!由于iteye博客不会显示[Tab]键,所以发文前用四个空格代替了这个[Tab]键。
...
...

2. Makefile 里主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释。
(1、显式规则。显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。

(2、隐晦规则。由于我们的make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。

(3、变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,这个有点你C语言中的宏,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。

(4、文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样;另一个是指根据某些情况指定Makefile中的有效部分,就像C语言中的预编译#if一样;还有就是定义一个多行的命令。有关这一部分的内容,我会在后续的部分中讲述。

(5、注释。Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用“#”字符,这个就像C/C++中的“//”一样。如果你要在你的Makefile中使用“#”字符,可以用反斜框进行转义,如:“\#”。

最后,还值得一提的是,在Makefile中的命令,必须要以[Tab]键开始。


3. 变量:
objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o

edit : $(objects) // edit是第一个目标,也即本makefile的默认的最终目标。
cc -o edit $(objects)
main.o : defs.h
kbd.o : defs.h command.h
command.o : defs.h command.h
display.o : defs.h buffer.h
insert.o : defs.h buffer.h
search.o : defs.h buffer.h
files.o : defs.h buffer.h command.h
utils.o : defs.h

.PHONY : clean  // “.PHONY”表示,clean是个伪目标文件,意味着:要运行“clean”这个目标(“伪目标”并不是一个文件,只是一个标签或目标名称),必须显示地声明出来:“make clean”。这里有个不成文的规矩是——“clean从来都是放在文件的最后”。
clean :
rm edit $(objects)

4. 只要make看到一个[.o]文件,它就会自动的把[.c]文件加在依赖关系中,如果make找到一个whatever.o,那么whatever.c,就会是whatever.o的依赖文件,就会自动加入依赖关系中:
kbd.o : kbd.c defs.h command.h
等价于:
kbd.o : defs.h command.h
注:此规则也就是makefile语法中所谓的“隐晦规则”。

另外,第3条中的也可以写成:

objects = main.o kbd.o command.o display.o \
insert.o search.o files.o utils.o

edit : $(objects)
cc -o edit $(objects)

$(objects) : defs.h // 说明$(objects)表示的每个o都依赖defs.h
kbd.o command.o files.o : command.h // 说明kbd.o, command.o和files.o这三个o都依赖command.h,下同
display.o insert.o search.o files.o : buffer.h

.PHONY : clean
clean :
rm edit $(objects)

5. makefile的文件名默认(没有在make后指定时自动到当前目录去找)为makefile或Makefile,也可以是任意文件名:make -f abc或make --file abc。

6. 把别的Makefile包含进本Makefile中:使用include关键字:
include <filename> // include前面可以有一些空字符,但是绝不能是[Tab]键开始。
filename可以是当前操作系统Shell的文件模式(可以保含路径和通配符)

举个例子,如果你要在当前makefile中包含以下几个Makefile:a.mk、b.mk、c.mk和foo.make,以及一个变量$(bar),该变量包含了e.mk和 f.mk,那么,下面的语句:

include foo.make *.mk $(bar)
等价于:
include foo.make a.mk b.mk c.mk e.mk f.mk

这样,make着先会在当前目录下寻找foo.make,a.mk等,如果当前目录下没有找到,那么,make还会在下面几个目录下找:

1、如果make执行时,有“-I”或“--include-dir”参数,那么make就会在这个参数所指定的目录下去寻找。
2、如果目录<prefix>/include(一般是:/usr/local/bin或/usr/include)存在的话,make也会去找。

如果有文件没有找到的话,make会生成一条警告信息,但不会马上出现致命错误。它会继续载入其它的文件,一旦完成makefile的读取,make会再重试这些没有找到,或是不能读取的文件,如果还是不行,make才会出现一条致命信息。如果你想让make不理那些无法读取的文件,而继续执行,你可以在 include前加一个减号“-”。如:
-include <filename>
其表示,无论include过程中出现什么错误,都不要报错继续执行。和其它版本make兼容的相关命令是sinclude,其作用和这一个是一样的。

7. 注意环境变量MAKEFILES!
如果你的当前环境中定义了环境变量MAKEFILES,那么,make会把这个变量中的值做一个类似于include的动作。这个变量中的值是其它的 Makefile,用空格分隔。只是,它和include不同的是,从这个环境变中引入的Makefile的“目标”不会起作用,如果环境变量中定义的文件发生错误,make也会不理。只要这个变量一被定义,那么当你使用make时,所有的 Makefile都会受到它的影响,这绝不是你想看到的。如果有时候你的Makefile出现了怪事,那么你应当先看看当前环境中有没有定义这个变量。 

8. make的工作方式

GNU的make工作时的执行步骤入下:(想来其它的make也是类似)

1、读入所有的Makefile。
2、读入被include的其它Makefile。
3、初始化文件中的变量。
4、推导隐晦规则,并分析所有规则。
5、为所有的目标文件创建依赖关系链。

6、根据依赖关系,决定哪些目标要重新生成。
7、执行生成命令。

1-5 步为第一个阶段,6-7为第二个阶段。第一个阶段中,如果此前定义的变量被使用了,则make会把该变量的值展开在使用该变量的位置。但make并不会马上完全地展开,make使用的是拖延战术:如果变量出现在依赖关系的规则中,那么仅当这条依赖关系被确定最终确会用到时,变量的值才会在相应地方展开。这样可以省去一些不必要的步骤从而提高整体效率。
当然,这个工作方式你不一定要清楚,但是知道这个方式你也会对make更为熟悉。有了这个基础,后续部分也就容易看懂了。

9. 书写规则
规则包含两个部分,一个是依赖关系