Linux基础开发工具(3)
1.复习
上一篇博客我们讲解了Linux下一些开发工具,vim编辑器,知道了vim的一键化配置和一些指令。
还知道了gcc和g++编辑器可以把我们在vim中写的代码变成可执行程序跑起来。
我们上篇博客最后写到gcc编辑器进行处理的四个步骤。分别是预处理,编译。汇编,链接。
下面我们书接上文继续介绍一下gcc具体的编辑过程。
2.预处理
在我们vscode中,我们进行编译直接帮助我们进行,但是在Linux下我们从操作系统层面去理解还需要知道更多,实际上我们vs下的直接执行就是预处理编译汇编链接。
Linux下我们可以让它一个一个过程的进行。
gcc -E code.c -o cide.i
-E选项是进行预处理
-o选项是形成指定的文件
预处理我们有以下工作需要完成,头文件展开,宏替换,条件编译,去注释。
头文件展开就是把头文件中的相关内容拷贝到我们的源文件中。
预处理完毕之后就可以不用头文件了。
条件编译是对代码进行裁剪,这个功能我们可以类比一下一些软件同时提供免费版和付费版,免费版就是把付费版的一些功能进行裁剪。
3.编译
我们的-E是预处理,那么-S就是进行编译。
gcc -S code.i -o code.s
这样作的结果是生成汇编语言。
4.汇编
-C是进行汇编
gcc -C code.c -o code.o
但是这个时候生成的code.o是可重定位的二进制目标文件。无法直接执行。因为它还没有与我们的外部库进行链接。
像printf这样的函数,具体的实现是在C标准库当中的,汇编之前我们编译的都是自己的代码,所以我们还需要与标准库进行链接才可以。
有的同学就要问了那头文件中不是包含了printf函数吗?是的,但是它只包含了我们的声明,具体的实现并没有在头文件中。
所以想让我们的代码跑起来还需要第四部链接
5.链接
链接的作用是与外部库进行链接,比如printf的声明在头文件,实现在C标准库中,我们需要将他们进行链接才能让我们的printf进行实现。
6.发展过程
那么我们有没有想过为什么程序的翻译过程是这样的?
这就涉及到我们计算机语言发展的历史了,我们的计算机其实只认识二进制编程,所以最开始的编程就是开关代表01,然后到了打孔编程,再然后人们觉得打孔编程不方便,就实现了汇编语言,但是计算机是不认识汇编语言的,所以我们就需要编译器,但是刚刚开始我们的汇编语言无法实现编译器,就需要用别的语言写一个汇编语言的编译器,等到汇编语言成熟之后,再用汇编语言就编写汇编语言的编译器这个过程叫做编译器的自举,再然后呢,就发展到了我们的C语言,然后觉得C语言还不够,就发展了C++,再然后就发展了JAVA等等多种多样的语言。
那么还有一个问题是:
先有语言还是先有编译器?
我们得来梳理一下脉络:第一个汇编语言的编译器是怎么做的?
答案是二进制来写,然后对汇编语言进行编译,再对老的编译器实现重构,最后就可以用新的汇编语言写编译器,这个过程叫编译器的自举。
汇编形成的.o文件为什么叫可重定位的目标文件?
我们的头文件中只有printf等函数的声明,并没有具体的实现,我们的实现在标准库中,所以需要找到相应函数的地址才可以,重定位的意思就是重新填写目标函数在库中的地址,这样我们就可以实现库中的函数了,因此叫做可重定位。
细节:系统必须提前有库和头文件
库里有函数的实现,头文件有函数的声明,但是我们windows做这个工作了吗?没有,所以我们得安装对应的IDE来帮助我们完成这个工作才能实现。
细节:如何题解库
为什么要有库呢?我们不可以自己写函数的实现吗?当然可以,但是在历史长河中,有些功能是大量重复使用的,如果每个人都去写一遍,会做大量重复冗余的工作,我们就把一些常用的函数写到库中,提高开发的效率,说白了就是一些常用方法的集合。
库分为动态库和静态库
Linux下.a结尾的是静态库。.so结尾的是动态库
库的命名是:lib.XXX.so去掉前缀lib和后缀so就是库真正的名字。
动态库和静态库各有优缺点
动态库是可以节省资源,缺点是动态库丢失之后所有依赖动态库的程序都会崩掉,而且它的运行速度较慢
静态库是直接把方法拷贝到可执行文件中,所以它就不依赖任何库了,自己就可以独立运行,但是与此同时,它的体积也比较大,占据资源多,加载速度受影响。
7.make和makefile
在Linux中,make和makefile是比较重要的工具。先简单介绍一下
通俗理解:make是一个命令,类似于ls ,mkdir,touch,但是makefile是一个文件需要自己去创建。
makefile中我们引申出一个概念叫做依赖关系和依赖方法。
、
我们的makefile文件中第一行的code是目标文件,code.c是依赖文件。code的实现依赖code.c
然后我们返回目录直接make会帮助我们直接执行我们makefile里第一个目标
那么我们的.PHONY是什么意思呢?
它的意思是伪目标,什么是伪目标呢?表示被修饰的目标是一个伪目标,可以总是被执行。
什么叫总是被执行,这就要提到什么是不被执行。
、可以看到我们在make以后再次make是不被执行的是因为我们的可执行文件已经有了,所以不会再次形成可执行文件。
但是clean是总是被执行的所以我们可以多次进行clean
所以叫做总是被执行的,
这是为什么呢?这就要提到我们stat code.c查看文件的属性了
我们的时间有3个,分别是change access Modify
access:最后一次被访问的时间
Modify:最后一次被内容修改的时间
change:最后一次内容或属性被修改的时间
我们有一个时间轴,通过对比可执行文件和源文件的时间属性进行判断是否需要进行重新编译,不然我们的文件过多,修改一个文件要全部文件重新编译会十分浪费时间。