Linux基础(2)
六、编译与调试
1、gcc , g++ , gdb 的安装
1.1 gcc 的安装
1.2 g++ 的安装
1.3 gdb 的安装
和上述擦操作一致。
2. gcc 分步进行编译
在 C 语言中,“ .c ”文件如果想直接去运行,首先需要将源文件变成可执行文件,此过程细分为4个过程:预处理(预编译),编译,汇编,链接。
这4步命令分别为:
(1)预编译(-E:预处理指定的源文件,但是不进行编译)。
gcc -c main.s -o main.o
(2)编译(-S:编译执行的源文件,但不进行汇编)。
gcc -S main.i -o main.s
(3)汇编(-c:编译,汇编指定的源文件,但不进行链接)
gcc -c main.s -o main.o
(4)链接(-o:指定生成文件的文件名)
gcc main.o -o main
3. 一步编译
上述四个步骤可以通过一行代码,直接将源文件变成可执行文件,命令如下:
gcc main.c
如果不给 -o,系统会默认生成可执行文件 a.out,如果想自定义最终生成的可执行文件的文件名,可以通过 -o:
gcc main.c -o main
前三个步骤,可以通过一行代码直接将源文件变成目标文件 “ .o ”,命令如下: gcc -c main.c
4. 编译后执行
通过路径 + 文件的方式可以启动一个程序,主要的目的可以准确的找到指定文件。
例如:可以通过 “ ./main ” 和 “ ./a.out ”的额=方式启动了刚才生成的这两个文件,这里的 “ ./ ”可不可以省略,像 pwd,ls 这些命令一样,不需要路径就可以执行呢?
可以发现,测试是不可以的,系统反馈信息,不加路径的话,系统将其看做是一个命令,而且并不是在我当前相对目录下找 main 或者 a.out ,而是默认直接去标准路径下找 main 和 a.out,当然找不到的话,就会报错,说在 /usr/bin 里面找不到对应的命令。
然后可以将我们生成的 main 和 a.out 放到 /usr / bin 里面,此时系统不会报错了,像 pwd ,ls 这些命令一样,不需要路径也可以执行。
5.编译链接过程
6. g++
gcc 主要处理 C语言的“ .c ” 文件
g++ 主要处理C++ 的 “ .cpp ” 文件
例如:现在有一个 main.cpp 文件,如果通过 g++ 去编译:
这里有两种方法可以对 main.cpp 进行编译:
-
第一种:通过 g++ 去进行编译
-
第二种:通过 gcc 去进行编译
之前我们认为 gcc 主要处理C语言的“ .c ” 文件,但是其实也可以用来编译“ .cpp ” 文件,只不过 gcc 默认链接的是C语言的标准库,并没有链接C++的标准库,则可以通过 gcc 去编译了(g++ 默认链接c++的标准库)
-l(-library):其中library表示库文件的名称,改选项用于动手指定链接环节中程序可以调用的库文件,-l和库文件名不使用空格,例如 -lstdc++
7.makefile和make
7.1 make的安装
7.2 makefile和make命令的介绍
- makefile文件:Linux上的项目工程管理工具,可以实现自动化编译。
后期一个项目工程里面的源文件可鞥不计其数,他还可以根据类型、功能、模块,将这些源文件分到好些目录里,makefile文件里面就可以定义一系列的规则来指定哪一些文件先需要进行编译,哪一些后编译,哪些需要重新编译,甚至更复杂的操作,makefile文件就像一个shell脚本一样,可以执行自定义好的一系列命令。
- make:是一个命令,可以解释makefile文件中的指令
从另一个角度来说,会不会写makefile,说明其是否具备完成大型工程的能力。
例如:现在有3个文件main.c max.c add.c
通过gcc执行一下:
但如果有很多的源文件,或者想修改其中几个源文件的数据,其他大部分的源文件是没有被修改的,这时如果按照上面的说法,没有修改过的文件还需要编译一下,太费事费力。
这时我们就可以使用makefile 文件,提高编译效率,通过make命令执行makefile文件,这是只会将修改过的文件或者依赖改过的文件的文件,不受影响的文件不会重新编译。
makefile 文件示例如下:
使用make 命令根据makefile 文件的规则生成对应的可执行文件:
现在修改main.c中的数据,则未收到影响的源文件不会重新编译,示例如下:
如果make完想保持整洁,可以通过make clean:
8.gdb 调试
8.1 Debug 版本和Release 版本
Debug 版本叫做开发版本或者可调试版本,生成的可执行文件里面包含调试到需要用到的信息。作为开发人员 ,最常用的就是Debug版本产生的可执行文件。
**Release 版本是发行版本 **,面向用户,里面没有调试信息,体积相较于Debug版本非常的小,gcc 默认生成的是Release 版本。
8.2 gcc如何生成Debug版本的可执行文件
Debug 版本的生成:因为调试信息是在编译阶段加入到可重定向的目标文件(.o)中的,所以必须在编译阶段就让它添加调试信息进来。
命令如下:
- 第一种方式:首先 gcc-c main.c -g(生成的中间文件main.o 这时包含调试信息),然后再通过gcc -o main.o(生成了Debug 版本的可执行文件)
- 第二种方法:一步生成,gcc -o main.c -g
8.3 通过gdb进入调试
首先需要将源文件编译,链接生成 debug 版本的可执行文件,然后通过“ gdb debug版本的可执行文件名”,就可以进入到gdb调试模式。
演示示例1:
执行起来:
执行起来后,发信**输入end,不能正常结束循环,**这是则可以进入到gdb模式如查看问题所在。
示例如下:(先生成 debug 可执行文件)
- l // 显示当前文件的源代码
- list filename :num // 显示 filename 文件中第 num 行附近的的源代码
- b 行号 // 给指定行添加断点
- info break // 显示所有断点信息
- delete 断点编号 // 删除对应断点
- r (run) // 启动程序
- q // 退出调试
- p buff // 临时打印数组所有元素的值
- p val // 临时打印变量 val 的值
- p &val // 临时打印变量 val 的地址
- p a+b // /临时打印表达式的值
- p *parr@num // 通过指向数组的指针打印数组的元素值
- display buff // 自动显示监视对象,操作格式和 p 一致
- info display // 显示所有自动显示监视对象的信息
- undisplay 编号 // 删除对应的自动显示监视对象
- n (next) // 单步执行 逐过程(vs里面F10)
- s // 进入到将被调用的函数中(逐语句 vs里面F11)
- finish // 跳出函数(跳出 vs里面shift+ F11)
- c (continue) // 继续执行,直到执行到下一个断点出
- ptype val // 显示变量的数据类型