目录
前言:
Linux调试器-gdb使用:
Linux项目自动化构建工具-make/Makefile:
问题:
为什么makefile对最新的可执行程序,默认不想不想重新形成呢?
make是如何知道到我的程序需要被编译的呢?
能不能简化一下makefile?
总结:
前言:
在学习Linux之前,确切的说是在认识和使用vim之前,我们学习C语言甚至是C++都是在VS2022等Windows的IDE上进行编写代码的,我们之前也讲过,VS2022有两个版本,一个是Debug版本,还有一个是Release版本。Debug版本是给我们来进行调试编译的,那么在Linux下也存在我们的调试工具——gdb。makefile则是一个新的概念,它是Linux项目自动化构建工具。
Linux调试器-gdb使用:
编译器在区别Debug和Release版本的方式,就是编译器在对Debug版本形成可执行程序时,会给Debug版本的可执行程序增添调试信息。 我们在平常输入指令gcc "XXX"的时候默认是形成Release的可执行程序,其实我们只需要在最后加上 -g选项就是Debug版本了。
- list/l 行号:显示binFile源代码,接着上次的位置往下列,每次列10行。
- list/l 函数名:列出某个函数的源代码。
- r或run:运行程序。
- n 或 next:单条执行。
- s或step:进入函数调用
- break(b) 行号:在某一行设置断点
- break 函数名:在某个函数开头设置断点
- info break :查看断点信息。
- finish:执行到当前函数返回,然后挺下来等待命令
- print(p):打印表达式的值,通过表达式可以修改变量的值或者调用函数
- p 变量:打印变量值。
- set var:修改变量的值
- continue(或c):从当前位置开始连续而非单步执行程序
- run(或r):从开始连续而非单步执行程序
- delete breakpoints:删除所有断点
- delete breakpoints n:删除序号为n的断点
- disable breakpoints:禁用断点
- enable breakpoints:启用断点
- info(或i) breakpoints:参看当前设置了哪些断点
- display 变量名:跟踪查看一个变量,每次停下来都显示它的值
- undisplay:取消对先前设置的那些变量的跟踪
- until X行号:跳至X行
- breaktrace(或bt):查看各级函数调用及参数
- info(i) locals:查看当前栈帧局部变量的值
- quit:退出gdb
我们在调试的时候,一定要先设置断点再run起来,输入r。
Linux项目自动化构建工具-make/Makefile:
- 会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力
- 一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作
- makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。
- make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。
- make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构
mytest.exe:test.cgcc test.c -o test.exe
.PHONY:clean
clean:rm -f mytest
以上就是最简单基础的makefile里的代码,这里要特别注意,gcc前面一定要加tab,剩下的也同理,一定一定要加tab,接下来就来创建test.c来实战编写一下。
接下来输入make指令:
make就自动调用makefile里面的指令:gcc test.c -o test.exe
要想清理test.exe ,输入make clean即可。
make会根据makefile的内容,完成编译/清理工作。
一般会先默认形成第一个目标文件,先写可执行程序。
.PHONY : XXX
表示XXX总要被执行,如下图验证:
因为我已经存在了一个test.exe文件,而test.exe作为目标文件 且 没有.PHONY修饰,如果继续make则不会运行。再看看我们的 make clean:
不一样的地方就在于make clean可以一直运行,这是因为在make clean前面加了.PHONY进行修饰。
其实普通的make也可以用.PHONY进行修饰。
这次我把.PHONY提前了。
很明显,这次就没之前的英文:"test.exe is up to data"
问题:
为什么makefile对最新的可执行程序,默认不想不想重新形成呢?
最主要的目的——为了提高编译效率,如果你对gcc或者g++之前添加了.PHONY,那么十几行的代码或者一个.c文件那还好,万一你又200000个.c文件需要被编译呢?这样效率就很低下了。
make是如何知道到我的程序需要被编译的呢?
我先总结一句话:“代码编写完的时间和编译的时间绝对不一样!”
如图,肯定是先编写完代码,才会对代码进行编译。所以不加.PHONY的make就是根据查找时间线之前是否存在编译好的代码,如果存在就不再进行编译了。.PHONY就是让系统别按照时间线来查找,一言不合就是“干”!
能不能简化一下makefile?
当然是可以的,makefile/make会自动根据文件中的依赖关系,进行自动推导,帮助我们执行所有的相关的依赖方法。但必须保证你最终要到的目标文件放在最前面!
@:表示目标文件
^:表示后面的文件
当然makefile中也支持定义变量:
当然如果你不想在执行make后,让屏幕出现执行语句,你可以在gcc前面加个@
总结:
1. make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
2. 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“hello”这个文件,并把这个文件作为最终的目标文件。
3. 如果test.exe文件不存在,或是test.exe所依赖的后面的test.c文件的文件修改时间要比test.exe这个文件新(可以用 touch 测试),那么,他就会执行后面所定义的命令来生成test.exe这个文件。
4. 如果test.exe所依赖的test.c文件不存在,那么make会在当前文件中找目标为test.exe文件的依赖性,如果找到则再根据那一个规则生成test.c文件。(这有点像一个堆栈的过程)
5. 当然,你的C文件和H文件是存在的啦,于是make会生成 test.exe 文件,然后再用 test.c 文件声明make的终极任务,也就是执行文件test.exe了。
6. 这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文件。
7. 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。
8. make只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,我就不工作啦。