make是Linux下的一条指令,而Makefile是一个文件,可以简单理解为make就是执行Makefile里面写的目的。
会不会去写Makefile可以侧面的看出一个人是否具备完成大型工程的能力
假设现有一个工程里面有上千上万个源文件,那么就可以使用Makefile定义一系列的规则来指定,哪些文件需要先编译,哪些文件后编译。当我们写好Makefile后,只需要一个make命令就可以让整个工程完全自动编译,极大地提高了效率
也就是说,make是一个解释Makefile中指令的命令工具,两者搭配使用就可以完成项目自动化构建
那么Makefile应该怎么样去写呢,那就得先了解一下Makefile的原理了。
在Makefile里面我们需要去定义一个方法时,就得考虑到两个因素,依赖关系、依赖方法。举例:当我们编写好一个源文件时,我们需要对它进行编译生成可执行文件,那么可以把这个可执行文件看做是目标文件,想要生成它就得依赖我们写好的源文件,那么我们就可以把源文件看做是依赖文件。那有了源文件后,我们需要通过编译工具编译的方法才能生成可执行文件,那这个方法我们就可以看做是依赖方法。
首先我写好了一个.c源文件,并且创建了一个makefile文件,按照之前学的,这是我们可以用gcc直接去编译生成可执行文件,但是如果每一次都去写gcc的指令就会很麻烦,因此我们可以考虑将这条指令放进makefile里面,我们只需要执行一下make指令就可以自动调用了。
编写的格式就跟上面所讲,需要有依赖关系、依赖方法。目标文件的后面必须要有跟上一个冒号,并且依赖方法另起一行必须以Tab键开头,不能是几个空格
当我们写好之后,make一下看看效果
可以看到当我们make一下后,系统会自动执行在makefile里面的指令,生成一个可执行文件。但是现在当我们再make一下,还会再次执行吗?
报错了,这是为什么呢?
make指令这点就带来了好处,当我们的源文件没有被修改时并且可执行文件已经生成时,make就会禁止你的再一次编译,那么问题来了make怎么知道源文件有没有被修改呢,这就得说到文件的属性了。
当我们去查看文件的属性时会发现,文件都会有三个时间属性,那么这三个分别代表什么呢
当我们的源文件没有被修改时并且可执行文件已经生成时,此时我们在make一下,make会去比较源文件和已有的可执行文件的被修改时间,如果可执行文件的比源文件的要晚,那么make不再执行编译指令,反之同理
那如果我就想让它执行呢,这时候就引入了一个makefile中的一个关键字:.PHONY(伪目标,该目标总是被执行)
可以看到此时,该条指令就可以无限执行了。
make是如何工作的呢
众所周知,当我们使用C/C++语言写好代码后,我们的先让源文件经过预处理,编译,汇编,链接几个步骤后才会生成一个二进制机器语言,这样计算机才能看得懂并且执行。那么在Windows下我们可以利用集成开发软件去帮我们完成这几个步骤,同理在Linux下我们就需要借用gcc/g++工具来帮我们完成。
预处理的主要功能包括宏定义,文件包含,条件编译,去注释等操作。
我们在编写代码时包含的头文件就会在这个步骤进行展开,宏定义会进行替换,我们写的注释也会在这个步骤去除
在Linux中该步骤生成的文件一般以.i为后缀,我们可以通过命令去完成这个步骤,需要用到-E选项
gcc -E main.c -o main.i
这个步骤,首先gcc/g++会检查代码是否有错误,以及确定代码的实际要做的工作,如果一切正常无误后,gcc/g++就会把代码翻译成汇编语言
在Linux中该步骤生成的文件一般以.s为后缀,我们可以通过命令去完成这个步骤,需要用到-S选项
gcc -S main.c -o main.s
汇编阶段就是把生成的.s文件转为目标文件也就是生成机器可以识别的二进制语言
在Linux中该步骤生成的文件一般以.o为后缀,我们可以通过命令去完成这个步骤,需要用到-c选项
gcc -c main.c -o main.o
这个阶段,目标文件会和系统库进行连接生成一个可执行程序
Linux中库的命名:去掉前缀lib,去掉后缀.so,剩下的就是库的名称
这个链接方式下,代码会将静态链接库拷贝一份到最终的可执行程序中,这样虽然提高了效率但是会是可执行程序的空间变得很大,不利于大型项目
在linux下想要生成静态链接就要在后面加上 -static选项,并且要确保已经安装了C/C++的静态库
sudo yum install glibc-static//安装C静态库
sudo yum install libstdc++-static//安装c++静态库
这个链接方式下,在可执行程序执行的时候,会将动态链接库映射到一块虚拟空间中,然后根据需要再去找对应的函数代码,这样可以极大地缩小可执行程序的空间。
Linux下默认的链接方式是动态链接,依赖的动态库一般为.so为后缀
对比上面的静态链接明显大小小很多
在平时Windows下我们使用想vs2019这样的话编译器时都会有一个调试的功能,让我们发现代码的错误之处。
同理在Linux下也有,这个调试工具就叫gdb,首先我们要安装一下gdb
sudo yum install gdb
安装好之后当我们直接运行gdb调试我们的可执行代码时会发现出问题了
因为程序会分为两个版本,一个是Debug版,一个是Release版
在debug模式下我们才可以对代码进行调试,但是Linux默认的模式是release,所以在生成可执行文件时需要加上-g选项,让它生成的可执行程序是debug模式才可以进行调试
自此我们才算是正式进入到了gdb中
那么对于gdb而言也有属于自己的指令
接下来我们一个一个看
首先显示我们的代码,需要用到l指令
该指令后面也可以加上行号或者函数名,显示指定内容
接下来我们需要为程序设置一个断点,如果不设置直接执行程序就会跑完,这是要用到b + 行号指令,设置好之后我们可以通过info b查看我们已经设置好的断点
还可以通过d + 序号删除对应的断点,注意这里的序号不是行号,而是我们设置好断点后每个断点通过info b查看之后每个断点对应的序号
设置好断点后此时我们就可以运行起来了,输入r运行程序(对应VS2019F5),如果执行到某行,该行有函数我们想进入函数调试就需要输入s(对应vs2019的F11),不想进入函数就输入n(对应vs2019F10)
那么现在如果我进入到函数里面了,但是函数里有千次的循环怎么直接执行完函数退出呢,需要输入finish
那么当我们进入到一个函数时,我们查看函数的变量值和变量的地址,这时候需要输入p + 变量名或p + &变量名
如果想每次执行完一条语句就显示出想查看的变量值,就需要用display + 变量名,不想看了想删除掉就使用undisplay + 变量名
剩下的一些可以自己去探索了,在上面所讲的都是一些比较常用的。
学习到这里已经是可以再Linux下进行代码编写了
接下来就得学习一些系统底层的知识了
每天进步一点淡👍