目录
一、工具准备
gcc是GNU的C编译器(GNU C Compiler)
g++是GNU的C++编译器(GNU C++ Compiler)
gdb是Linux下常用的调试工具,主要功能如下
- 启动你的程序,可以按照你的自定义的要求随心所欲的运行程序。
- 可让被调试的程序在你所指定的调置的断点处停住(断点可以是条件表达式)。
- 当程序被停住时,可以检查此时你的程序中所发生的事。
- 你可以改变你的程序,将一个BUG产生的影响修正从而测试其他BUG。
Makefile文件:Makefile是程序编译的规则,makefile记录着整个工程的编译规则(如源文件的编译顺序、依赖关系等),通过make工具进行编译。make根据makefile定义的规则将源代码编译成二进行文件。在跨平台(特别是类Unix系统中)的程序中,一般都会通过makefile来进行编译。
二、程序的编译及调试
1、程序的编译及常用命令
$ g++ main.cpp #编译程序,在当前目录自动生成一个a.out
的可执行文件
$ ./a.out # 执行可执行文件,即运行程序
$ g++ main.cpp -o test # 指定自己想要生成的可执行程序的别名 (test)
$ g++ -c main.cpp # 将源代码编译成目标文件(main.o),不进行链接
$ g++ main.o -o test1($ g++ -o test1 main.o) #g++接编译后的(*.o)文件进行链接,生成可执行程序 (test1)
$ ldd test1 #该命令可以看到可执行程序 (test1)所链接的库
$ g++ -o test1 main.cpp -L /usr/Lib -l /usr/include #将依赖的函数库和库路径加入
-
-L 指定连接的动态库或者静态库路径 ;
-
-I(大写i) 指定头文件路径 ,即include文件(也就是包含的*.h头文件)所在的目录;
-
-l(小写L) 指定需要链接的库的名称
$ gcc -g main.c -o test #使用gdp调试C/C++程序, 在编译时,必须要把调试信息加到可执行文件中
$ g++ -g main.cpp -o test
注: 编译过程包括预处理、编译,链接 ;linux系统上的编译生成.o文件,windows系统上的编译生成.obj文件 ;linux系统上生成没有后缀的可执行文件,windows系统中生成.exe文件 ; linux系统下的静态函数库的后缀是.a,动态库是.so ; windows系统下的静态函数库的后缀是.lib,动态库是.dll。
2、gdb调试
GDB是一个由GNU开源组织发布的、UNIX/LINUX操作系统下的、基于命令行的、功能强大的程序调试工具。可以用来调试C,C++程序。
gdp功能及其常用命令
命令形式 | 功能解释 |
---|---|
gdb -g main.cpp -o test | 编译代码时的命令,要把调试信息加到可执行文件中 |
gdb | 进入gdb调试命令 |
help | 显示帮助信息,例:help quit,显示quit命令的信息 |
q/quit | 退出GDB调试 |
file test | 加载被调试的可执行程序文件test;或者直接使用gdb ./test进行debug调试命令 |
l/list | 列出文件的内容 |
b/break <line number> | 在某一行设置普通断点,运行到该行即停止,例:b 7 |
b/break <line number> if condition | 在某一行设置条件断点,运行到该行满足条件即停止,例:b 7 if index=2 |
b/break <function name> | 在某一个函数调用处设置断点,运行到函数调用出即停止,例:b getSum |
r/run | 运行调试的程序(如果程序中没有设置断点,则程序会一直运行到结束或者出现异常结束,如果设置断点,则会在断点处停止) |
d/delete <break number> | 删除断点编号对应的断点,例:d 1 |
clear | 清空所有的断点信息 |
start | 开始调试 |
c/continue | 继续执行程序直到下一个断点或者程序结束 |
n/next | 逐行调试 |
s/step | 遇到函数时进到函数内部调试 |
p/print <value> | 显示变量的值,即查看变量数据,例:p index |
三、Makefile文件基础
1、Makefile介绍
Makefile文件关系到了整个工程的编译规则,它定义了一系列的规则来指定哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作,因为 makefile就像一个Shell脚本一样,其中也可以执行操作系统的命令。
Makefile带来的好处就是“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
make是一个命令工具,是一个解释makefile中指令的命令工具, 在终端中输入make命令,会自动搜索当前路径下的makefile或者是Makefile文件 。
2、Makefile编写
(1)Makefile示例1及分析
edit:main.o test.o #需要生成的目标:生成目标的依赖项
g++ main.o test.o -o test #以Tab键开始,具体要执行的命令
test.o:
g++ -c test.cpp
main.o:
g++ -c main.cpp
clean:
rm main.o test.o
- makefile书写规则包含两个部分,一个是依赖关系,一个是生成目标的方法。
- 我们可以把这个内容保存在文件为“Makefile”或“makefile”的文件中(最好使用 “Makefile”这个文件名),然后在该目录下直接输入命令“make”就可以生成执行文件edit。
- 如果要删除执行文件和所有的中间目标文件,那么,只要简单地执行一下“make clean”就可以。
- 在Makefile中使用“#”字符,表示注释。
通过示例1看make的工作过程:
- 首先,输入make命令,make会在当前目录下找名字叫“Makefile”或“makefile”的文件;
- 如果找到,它会找文件中的第一个目标文件,即“edit”文件,并把这个文件作为最终的目标文件;
- 如果edit文件不存在,或是edit所依赖的后面的 .o 文件的文件修改时间要比edit这个文件新,那么,他就会执行后面所定义的命令来生成edit这个文件;
- 如果edit所依赖的.o文件也不存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。(这有点像一个堆栈的过程);
- 然后再用 .o 文件生成make的终极任务,也就是执行文件edit。
这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。在寻找的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make 就会直接退出,并报错,而对于所定义的命令的错误或是编译不成功,make根本不理。make 只管文件的依赖性。
(2)Makefile示例2及分析
#################################################
# Example for call LTP libraries under UNIX #
#################################################
cc=g++
ccflags=-O2
all: cws \
pos
cws: cws.cpp
${cc} ${ccflags} -o cws cws.cpp -I./ \
-I../include/ \
-I../thirdparty/boost/include \
-L../lib/ -lsegmentor -lboost_regex
pos: pos.cpp
${cc} ${ccflags} -o pos pos.cpp -I./ \
-I../include/ \
-L../lib/ -lpostagger
.PHONY: clean
clean:
rm cws
rm pos
- 反斜杠(\)是换行符的意思。这样比较便于Makefile的阅读;
- -I../include/表示依赖的头文件路径,-L../lib/表示依赖的库路径;
- -O2:表示编译时使用二级优化
- makefile中使用变量,比如:cc=g++,makefile中以“$(cc)”的方式来使用这个变量;变量的命名字可以包含字符、数字,下划线(可以是数字开头),但不应该含有“:”、“#”、“=”或是空字符(空格、回车等)。变量是大小写敏感的,“foo”、“Foo”和“FOO”是三个不同的变量名。
- 清空目标文件的规则:为了避免和文件重名的这种情况,我们可以使用一个特殊的标记“.PHONY”来显示地指明一个目标是“伪目标”,向make说明,不管是否有这个文件,这个目标就是“伪目标”。只要有“.PHONY : clean ”这个声明,不管是否有“clean”文件,要运行“clean”这个目标,只需“make clean” 即可。
(3)Makefile编写规则
- 显式规则。显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。
- 隐晦规则。由于make有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make所支持的。
- 变量的定义。在Makefile中我们要定义一系列的变量,变量一般都是字符串,当Makefile被执行时,其中的变量都会被扩展到相应的引用位置上。
- 文件指示。其包括了三个部分,一个是在一个Makefile中引用另一个Makefile,就像C语言中的include一样;另一个是指根据某些情况指定Makefile中的有效部分,就像C语言中的预编译#if一样;还有就是定义一个多行的命令。
- 注释。Makefile中只有行注释,和UNIX的Shell脚本一样,其注释是用“#”字符,这个就像C/C++中的“//”一样。如果你要在你的Makefile中使用“#”字符,可以用反斜框进行转义,如:“#”。
注:在Makefile中的命令,必须要以[Tab]键开始。
(4)make工作时执行过程
- 读入所有的Makefile;
- 读入被include的其它Makefile;
- 初始化文件中的变量;
- 推导隐晦规则,并分析所有规则;
- 为所有的目标文件创建依赖关系链;
- 根据依赖关系,决定哪些目标要重新生成;
- 执行生成命令。
(5)makefile文件中使用通配符
我们想定义一系列比较类似的文件,可以使用通配符。make支持三种通配符:“*”,“?”和“[...]”;通配符可以代替一系列的文件,如“*.cpp”表示所有后缀为cpp的文件。一个需要我们注意的是,如果我们的文件名中有通配符,如:“*”,那么可以用转义字符“\”,如“\*”来表示真实的“*”字符。
(6)Makefile中的-Wall -O2 -Os -g等选项介绍
- -Wall:选项可以打印出编译时所有的错误或者警告信息。这个选项很容易被遗忘,编译的时候,没有错误或者警告提示,以为自己的程序很完美,其实,里面有可能隐藏着许多陷阱。变量没有初始化,类型不匹配,或者类型转换错误等警告提示需要重点注意,错误就隐藏在这些代码里面。没有使用的变量也需要注意,去掉无用的代码,让整个程序显得干净一点。下次写Makefile的时候,一定加-Wall编译选项。
- -O0: 表示编译时没有优化。
- -O1: 表示编译时使用默认优化。
- -O2: 表示编译时使用二级优化。
- -O3: 表示编译时使用最高级优化。
- -Os:相当于-O2.5优化。
3、make的运行和退出
(1)make的运行
直接在命令行下输入make命令,make命令会找当前目录的makefile来执行,一切都是自动的。
(2)make的退出
make命令执行后有三个退出码:
- 0 —— 表示成功执行。
- 1 —— 如果make运行时出现任何错误,其返回1。
- 2 —— 如果你使用了make的“-q”选项,并且make使得一些目标不需要更新,那么返回2。