对于程序开发,我们经常要用make命令来编译链接生成可执行文件,如果“make”、"make all"、“make uboot”、"make uImage"等命令,也会经常使用“make clean”、“make distclean”来清除编译生成的文件。而这些命令的实现涉及到make程序和Makefile文件这些知识,在了解make程序与Makefile文件前,我们带着几个疑问去了解这些知识,
疑问:
1、Makfile文件是什么,有什么作用?
2、make程序与Makefile文件的关系?
3、平时使用“make”、“make clean”等命令,make命令是如何执行Makefile中对应的命令?
4、一旦修改了代码,make命令就会重新编译目标,那么make命令如何判断目标是否需要更新?
一、简介
1、make程序
make程序是一个程序,有不同的版本,比如GNU make、Microsoft nmake等版本,Linux用的是GNU make。make程序的执行需要Makefile文件,只有找到对应的Makefile文件才能执行对应的make命令。
2、Makefile文件的核心规则
目标(target)…: 依赖(prerequiries)…
<tab>命令(command)
规则:一般是用于解释怎么样创建目标和什么时候重建目标。
目标(target)
1)可以是要产生的文件的名称,比如可执行文件或OBJ文件。
2)也可以是一个执行的动作名称,比如,clean
依赖:用来输入从而产生目标的文件,一个目标经常有多个依赖。
命令:是Make执行的动作,一个规则可以含有多个命令,每个命令占一行。每个命令行前面必须是一个Tab字符,即命令行第一个字符时Tab。
二、疑问分析
通过解答文章开头的几个疑问,我们可以对Makefile文件的相关功能有个初步认识。
1、Makfile文件是什么,有什么作用?
答:Makefile文件描述了程序中各个文件之间的相互关系,并提供了每一个目标的更新命令。
简单地讲,Makefile文件定义一些规则,执行这些规则可以实现一些功能,比如将源码文件编译链接为可执行程序,也可以实现删除编译生成的文件等。
2、make程序与Makefile文件的关系?
答:1)要使用make程序,必须有一个名为Makefile的文件。
2)Make程序需要Makefile文件来告诉它能干嘛。比如,Makefile文件告诉Make程序要怎么编译和链接源文件成一个程序。
3)Makefile文件定义规则,make程序触发规则。Make程序只是提供了一个触发条件,触发Makefile文件中的命令执行,至于命令执行什么动作,是Makefile文件定义的。
3、平时使用“make”、“make clean”等命令,make命令是如何执行Makefile中对应的命令?
答:执行“Make 目标”命令后,会触发在Makefile找到对应的目标,根据规则判断是否创建或更新目标,
1)目标有依赖的规则情况:如果目标不存在,则直接执行规则的命令来创建目标,如果目标存在,但是依赖有更新,也要执行命令来更新目标。
单纯执行一个“make”命令,目标是缺省的,在这种缺省情况下,make开始于第一个目标,这个目标一般称为缺省最终目标,一般把编译可执行程序定义为缺省最终目标。
2)目标没有依赖的规则情况:直接调用命令,比如目标是"clean"("clean"是一个动作,又称为假想目标:指不需要依赖仅仅表达动作的目标。假想目标存在的目的仅仅是执行一些特殊的命令)。
4、一旦修改了代码,make命令就会重新编译目标,make命令如何判断目标是否需要更新?
答:只要依赖有更新,则对应的目标需要更新。Make程序根据Makefile文件中每个依赖文件更改的时间戳决定哪些目标需要更新。如果依赖文件的更改时间比目标新,则需要重新执行命令来更新目标。
三、示例分析
创建一些源文件和头文件,有如下的文件组成:
1、Makefile 内容分析
Makefile文件有以下内容:
分别标记为5条规则:
规则1中,目标是mfprj ,依赖文件是 main.o unit.o module.o,命令是gcc -o mfprj main.o unit.o module.o,命令前是一个Tab字符
规则2中,目标是main.o ,依赖文件是 main.c unit.h module.h,命令是gcc -c -o main.o main.c,命令前是一个Tab字符
规则3和规则4与规则2类似
规则5中,clean是一个假想目标,不需要依赖仅仅表达动作的目标。只是为了执行删除文件的命令rm *.o mfprj,命令前是一个Tab字符
2、Makefile功能分析
由该Makefile的内容可知,该Makefile有2个功能,一个是编译链接生成可执行程序mfprj,另一功能是删除所有的.o文件和mfprj文件。
1)单纯执行一个"make"命令,目标是缺省的,在这种缺省情况下,make开始于第一个目标(缺省最终目标),该示例的缺省最终目标是“mfprj”,第1次编译时,由于“mfprj”目标不存在,使用要执行命令“gcc -o mfprj main.o unit.o module.o”来创建“mfprj”目标,但由于第1次编译时,依赖文件“main.o unit.o module.o”也不存在,所以要先生成依赖文件,依赖文件在规则2、3、4中是作为目标,要执行对应的规则来创建目标“main.o unit.o module.o”,依赖文件创建后,再回到规则1中,执行命令创建“mfprj”目标
在Ubuntu中编译示例代码,可以看到如我们分析,先生成依赖文件,最后通过依赖文件创建目标“mfprj”,如下图:
修改文件"module.c",然后重新编译,在检查目标“mfprj”是否需要更新,会根据依赖文件是否有更新来判断,各个依赖文件又会递归下去,作为目标去分析它的依赖是否比较“新”(检查文件的时间戳可知),依赖文件”main.o unit.o“没有更新,而"module.o"的依赖文件"module.c"有更新,所以要使用其命令来更新”module.o",一旦“module.o"更新了,那么其作为目标“mfprj”的依赖,也导致目标“mfprj”需要更新。编译如下图:
修改文件"unit.h",然后重新编译,在检查目标“mfprj”是否需要更新,会根据依赖文件是否有更新来判断,各个依赖文件又会递归下去,作为目标去分析它的依赖是否比较“新”(检查文件的时间戳可知),”main.o unit.o“依赖文件"unit.h"有更新,所以要使用其命令来更新”main.o"和"unit.o“,一旦”main.o"和"unit.o“,更新了,那么其作为目标“mfprj”的依赖,也导致目标“mfprj”需要更新。编译如下图:
2)执行"make clean"命令,“clean”是一个假想目标,不需要依赖,只是为了执行删除文件的命令rm *.o mfprj
本文涉及的示例代码下载链接:https://download.csdn.net/download/bulebin/11347945