Linux中的开发工具--make/makefile
1. 背景介绍
在我们写c/c++代码较多的demo时,我们通常会创建三个文件(一个 .h 的自定义库,二个以.c或.cpp结尾的代码文件)。在Windows系统下,我们可以通过vs这个集成开发环境,直接把这三个文件编译整合,形成一个可执行文件。那么下Linux系统下我们可以通过gcc/g++来编译文件,当时我们需要对多个文件进行多次编译时,我们就需要多次gcc/g++这样做太繁琐,那么在Linux系统下是否有这么个东西来帮助我们来简化多文件的编译呢?
答案是有的,这便是,今天我们要介绍的make/makefile(自动化构建代码).
2.认识make/makefile
- make是一条命令,makefile是一个文件(由用户自己创建的文件),两个搭配使用,完成项目自动化构建。
注:
- make后面的文件只能是makefile或Makefile
- makefile是一个具有特定格式的文本文件
2.1如何使用makefile
这里我们通过一个例子来解释。
首先创建一个以test.c文件,用vim打开,写一个正确的程序。
然后再创建一个makefile文件,用vim打开makefile写入一下内容
先不要问这段代码什么意思后面会解释(makefile的特定格式)。 注:这里第二行和第四行是以TAB键开头的(这里我把TAB键改成了两格)
写好后在底行模式下用wq保存并退出
当想自动化构建代码是只需要:
使用指令:make
当像删除这个可执行程序时:
使用指令: make clean
2.2 makefile的特定格式与如何使用makefile里面的内容
这里,我们要想了解makefile文件里面写的内容,我们就不得不将makefile的特定格式了:
- makefile文件里大部分内容是由依赖关系和依赖方法组成的(这里的第1,3行是依赖关系。第2,4行是依赖方法)
一般来说一个依赖关系下面一定跟着一个依赖方法。
依赖关系的格式:
目标文件 :依赖文件列表
这里我们说目标文件依赖于依赖文件列表(在我们上面写的可以说,test依赖于test.c)
注:这里的目标文件是必须要指明的,不能不写。而对于依赖文件来说就要根据目标文件的具体需求来写了,它可以不写,也可以写一个或多个。(会在后面解释为什么会这样设计)
依赖方法
通常来说依赖方法上面必定伴随着依赖关系,而依赖方法就是为了实现依赖关系的,它就是一条指令。
2.3对makefile里面内容的理解
这里我是这样理解的makefile是通过依赖关系与依赖方法对处于在同一目录下的文件进行操作的。
而依赖关系与依赖方法的关系我是这样理解的:
每一个依赖关系与对应的依赖方法就是一个动作,
而这个动作的别名就是目标文件,这个动作的实现就要靠依赖方法对依赖文件列表进行处理。
这里我们之所以把依赖关系 :左边的叫目标文件的原因就是:
依赖关系与依赖方法一起组成的动作的目标一般是产生一个可执行文件,这里为了我们后续方便执行那个文件,我们把动作的别名与可执行文件名相同。
2.4使用make调用makefile里的内容
在上面我说过makefile里面相当于存储的是一个一个的动作,那么我们如何在makefile外调用我们想要执行的动作呢?
这里我们make就要登场了。
使用格式:make 目标文件 或 make
作用:调用对用的依赖关系与依赖方法,来达到生成目标文件或完成其要求。
当我们第一次编译之后再次编译会有什么结果呢?
这里我们可以看到提示了,因为这个文件已经已经经过编译存储数据了,而使指令执行失败。
当我们在修改一下test.c文件里的内容之后再执行。
我们可以发现指令执行成功。
这两种执行场景对我们来说也是正常的,毕竟一个已经编译的东西,没有再次执行的必要,但改过之后是有必要的。
那么再Linux系统下,又是如何如何区分这两种情况的呢?
这里我们就不得不要提文件三个时间。
指令:
stat test
注:(Modify)修改文件内容往往也会改成Change的改变。原因:Modify往往会造成文件大小的改变,而文件大小属于文件内容。(文件内容:文件的权限,文件的大小等)
系统就是通过比较test文件与test.c文件的Modify的大小来区分的。
我们可以很好的知道在一次编译后test的文件的Modify是永远新与test.c的Modify的,而修改一次后,便会相反。
那么有什么方法可以使我们不用修改test.c文件仍可以多次编译吗?
2.5 伪文件的定义以及属性
在这里我们可以通过用.PHONY将目标文件修饰成伪文件,
如:
那么修饰前与修饰后有什么区别呢?
修饰后:
我们可以发现在修饰成为伪指令后每一执行都会成功。
有目前经验可以得出两个结论:
1.被修饰成伪文件后,次文件总是被执行
2.make总是不让重新编译代码
2.6make的工作原理
make是如何工作的,在默认的方式下,也就是我们只输入make命令。那么,
- make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
- 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“test.c”这个文件, 并把这个文件作为最终的目标文件。
- 如果test文件不存在,或是hello所依赖的后面的test.c文件的文件修改时间要比test这个文件新(可 以用 touch 测试),那么,他就会执行后面所定义的命令来生成test这个文件。
- 如果test所依赖的test.c文件不存在,那么make会在当前文件中找目标为test.c文件的依赖性,如果 找到则再根据那一个规则生成test.c文件。(这有点像一个堆栈的过程)
- 当然,你的C文件和H文件是存在的啦,然后再用test.c 文件声明 make的终极任务,也就是执行文件hello了。
- 这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出第一个目标文 件。
- 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退出,并报错, 而对于所定义的命令的错误,或是编译不成功,make根本不理。
- make只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起, 我就不工作啦。