【Linux】6:自动化构建工具-make/Makefile

📅 2026/7/5 13:30:17
【Linux】6:自动化构建工具-make/Makefile
目录一、背景二、基本使用2.1 make/makefile是什么2.2 makefile的基本概念和使用2.3 项目清理2.4 理解总是被执行2.5 推导过程三、扩展3.1 makefile文件中变量的使用3.2 扩展一3.3 扩展二3.4 扩展三3.5 扩展四3.6 扩展五四、总结一、背景会不会写makefile从一个侧面说明了一个人是否具备完成大型工程的能力一个工程中的源文件不计数其按类型、功能、模块分别放在若干个目录中makefile定义了一系列的规则来指定哪些文件需要先编译哪些文件需要后编译哪些文件需要重新编译甚至于进行更复杂的功能操作makefile带来的好处就是——“自动化编译”一旦写好只需要一个make命令整个工程完全自动编译极大的提高了软件开发的效率。make是一个命令工具是一个解释makefile中指令的命令工具一般来说大多数的IDE都有这个命令比如Delphi的makeVisual C的nmakeLinux下GNU的make。可见makefile都成为了一种在工程方面的编译方法。make是一条命令makefile是一个文件两个搭配使用完成项目自动化构建。二、基本使用2.1 make/makefile是什么make是一个命令makefile是一个文件。2.2 makefile的基本概念和使用首先我们创建一个code.c的源文件如下所示如果我们需要编辑的话就需要使用gcc或者ggcc需要我们自己来敲如果当前工作目录下的源文件非常多的话一个一个敲太浪费时间了效率太低了。那么当源文件非常多的时候我们如何编译呢我们可以使用自动化构建工具-make来创造一个makefileMakefile文件如下所示我们执行make命令之后就会在当前工作目录下查找一个makefile的文件然后根据makefile文件里面的内容生成code来运行。在我们编写的makefile文件中第一行code:code.c表示依赖关系我们要产生code文件需要依赖code.c文件第二行gcc code.c -o code表示依赖方法从code.c到code需要用到的方法必须以tab键开头在makefile文件中必须要有依赖方法和依赖关系。2.3 项目清理我们不仅想让代码进行编译我们还想让代码进行清理清理如下所示在我们执行make clean之前我们当前目录下是由code文件的当我们执行make clean之后就会执行rm -f code这一条命令来清理code文件。此时我们就可以将一个源文件使用make和make clean的命令组合就可以自动化的进行代码的编译和清理了如下所示:第一行.PHONY:clean表示使用.PHONY来修饰clean叫做伪目标。第二行clean:表示依赖关系冒号后面为空表示clean不需要依赖任何文件第三行rm -f code表示依赖方法问题一为什么我们想要产生code文件只需要make呢而clean需要执行make clean呢我们将makefile文件中的代码顺序换一下如下所示然后再次执行make命令就会执行rm -f code这条指令了如下所示然后make code就是执行gcc code.c -o code这条命令了如下所示make命令在扫描makefile文件的时候是从上往下扫描默认形成第一个目标文件也就是使用第一个目标文件的依赖关系形成第一个目标文件。一旦把第一个执行了后面的依赖关系生成的依赖文件就不执行了除非你给make传入一个目标文件你要形成谁例如make code。所以我们默认情况下写makefile文件时喜欢把我们形成的可执行程序放在最前面。如下所示问题二.PHONY:clean是什么意思我们在makefile文件中将这个去掉如下所示然后使用make和make clean来编译执行和清理文件如下所示发现并不影响我们make的具体操作为什么makefile文件里面需要加上.PHONY:clean来声明clean是伪目标呢首先.PHONY类似一种建议的关键字来建议这个clean总是被执行表示对应的依赖关系和依赖方法总是被执行。当我们执行make clean的时候表示这组依赖关系rm -f code总是会被执行。2.4 理解总是被执行在理解总是被执行之前我们先理解一下总是不被执行如下所示在我们的makefile文件里面有两个目标文件一个是code一个是clean其中code是没有被.PYHOY修饰的。我们在第一次执行make来执行编译命令之后后面的三次使用make来执行编译命令就不让我来执行了。我们可以在使用.PYHOY来修饰code目标文件然后再次执行多次make命令如下所示我们发现我们使用.PYHOY来修饰code目标文件之后每次make都会执行对应的依赖方法。问题一为什么我们在第一次执行make来执行编译命令之后后面的三次使用make来执行编译命令就不让我来执行了呢因为我的源代码没有被更新过没有更新过的话就没有必要重新编译形成目标文件。也就是说我的源代码没有被更新过目标文件也就不需要重新编译形成。因为我的文件没有改过为什么要重新再次编译呢只有在改了源文件之后才需要重新编译。当我们有100个源文件我们只修改了10个再次使用make命令来编辑就只会重新编译那10个修改过的文件来提高编译效率。所以我们在形成可执行程序的时候默认不使用.PYHOY来修饰来避免总是被执行降低效率。问题二make怎么知道目标文件code和源文件code.c谁新谁旧呢在linux系统中一切皆文件而其中每一个文件都有相关联的三个时间。我们可以使用stat命令来查看如下所示三个时间分别是Access,Modify,Change。我们知道文件内容属性如果只修改文件的内容Modify时间就会被更新。如果只修改文件的属性Change时间就会被更新。如果不对文件属性和内容做修改只查看文件内容Access时间就会被更新不会每一次查看就会更新一般是查找多次才会被更新。一般我们修改文件的内容会更新Modify时间和Change时间因为修改内容之后文件大小会发生变化Modify时间也会发生变化文件大小是文件的属性Modify时间也是文件的属性。我们回到问题make怎么知道目标文件code和源文件code.c谁新谁旧呢因为每一个文件都用三个时间来表示文件在哪一个时间被修改了make命令在执行依赖方法会查看Modify时间如果code的Modify时间在code.c的Modify时间之前就会执行依赖方法如果code的Modify时间在code.c的Modify时间之后就会不会执行依赖方法总结能不能编译主要就是看目标文件和源文件的Modify时间我们可以使用touch来修改文件的时间如下所示我们在使用.PYHOY来修饰目标文件之后就会让make命令不关注Modify时间可以总是被执行。.PHONY:让make忽略源文件和可执行目标文件的M时间对比2.5 推导过程实际上我们的code目标文件不是依赖code.c文件形成的而是依赖code,o文件形成的而code.o是依赖code.s文件形成的,code.s是依赖code.i文件形成的code.i文件是依赖code.c文件形成的。这就形式了一套依赖链。makefile文件如下所示make是如何工作的在默认的方式下也就是我们只输入make命令。那么make会在当前目录下找名字叫“Makefile”或“makefile”的文件。如果找到它会找文件中的第一个目标文件target在上面的例子中,他会找到code这个文件并把这个文件作为最终的目标文件。如果code文件不存在或是code所依赖的后面的code.o文件的文件修改时间要比code这个文件新可以用touch测试那么他就会执行后面所定义的命令来生成code这个文件。如果code所依赖的code.o文件不存在那么make会在当前文件中找目标为code.o文件的依赖性如果找到则再根据那一个规则生成code.o文件。这有点像一个堆栈的过程当然你的C文件和H文件是存在的啦于是make会生成code.o文件然后再用code.o文件声明make的终极任务也就是执行文件hello了。这就是整个make的依赖性make会一层又一层地去找文件的依赖关系直到最终编译出第一个目标文件。在找寻的过程中如果出现错误比如最后被依赖的文件找不到那么make就会直接退出并报错而对于所定义的命令的错误或是编译不成功make根本不理。make只管文件的依赖性即如果在我找了依赖关系之后冒号后面的文件还是不在那么对不起我就不工作啦。这样写makefile文件我们只是介绍一下依赖链和递归过程一般我们是不会这样写的。三、扩展3.1 makefile文件中变量的使用makefile允许我们去定义变量如下所示我们定义了一个变量BIN,如果需要使用这个变量需要使用${BIN},我们执行make命令之后会显示echo code并且执行这条命令如下所示如果我们不想让echo code这条命令显示可以在makefile文件里面的echo ${BIN}前加一个符号如下所示3.2 扩展一运行如下所示3.3 扩展二其中在依赖关系中:1$表示目标文件名字也就是依赖关系里面的${BIN}也是code2$^表示源文件名字也就是依赖关系里面的${SRC},也是code.c3如果源文件有很多个$^统一代表这些源文件。运行如下所示3.4 扩展三我们不想看到依赖关系我们可以在依赖关系前面加上但是我们又需要看到过程如下所示3.5 扩展四我们在实际项目中不用源文件直接生成可执行程序而是先生成目标文件OBJ,在链接形成可执行程序如下所示3.6 扩展五如果我们有100个源程序呢我们需要在变量定义的时候SRC写100个吗如下所示首先使用命令创建100个源文件count1; while [ $count -le 100 ]; do touch code${count}.c; let count; done四、总结makefile文件的最终格式如下1 BINproc.exe2 CCgcc3 #SRC$(shell ls *.c)4 SRC$(wildcard *.c)5 OBJ$(SRC:.c.o)6 LFLAGS-o7 FLAGS-c8 RMrm -f910 ${BIN}:${OBJ}11 ${CC} ${LFLAGS} $ $^12 echo linking ... $^ to $1314 %.o:%.c15 ${CC} ${FLAGS} $16 echo compling ... $ to $1718 .PHONY:clean19 clean:20 ${RM} ${BIN} ${OBJ}1SRC表示的是当前目录下的全部.c文件2OBJ表示的是所有.c文件的同名.o文件3符号指的是形成目标程序不显示依赖关系4$表示的是该依赖关系的目标文件5$^表示的是该依赖关系的源文件6%.o表示的是当前目录下的所有.o文件7%.c表示的是当前目录下的所有.c文件8%表示的是将所有的源文件生成对应的.o文件。