多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] # 简介 makefile就像个shell命令一样.也可以执行一些命令 一般来说,大多数的IDE都有这个命令, 比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。 可见,makefile都成为了一种在工程方面的编译方法。 ~~~ sudo apt install make -y ~~~ # 语法规则 **一条规则:** > 目标:依赖文件列表 > > 命令列表 Makefile基本规则三要素: 1)目标: * 通常是要产生的文件名称,目标可以是可执行文件或其它obj文件,也可是一个动作的名称 2)依赖文件: * 用来输入从而产生目标的文件 * 一个目标通常有几个依赖文件(可以没有) 3)命令: * make执行的动作,一个规则可以含几个命令(可以没有) * 有多个命令时,每个命令占一行 ~~~ all:test1 test2 echo "hello all" test1: echo "hello test1" test2: echo "hello test2" ~~~ ~~~ make -f Makefile ~~~ # 命令格式 make是一个命令工具,它解释Makefile 中的指令(应该说是规则)。 make命令格式: make \[ -f file \]\[ options \]\[ targets \] 1.\[ -f file \]: * make默认在工作目录中寻找名为GNUmakefile、makefile、Makefile的文件作为makefile输入文件 * \-f 可以指定以上名字以外的文件作为makefile输入文件 2.\[ options \] * \-v: 显示make工具的版本信息 * \-w: 在处理makefile之前和之后显示工作路径 * \-C dir:读取makefile之前改变工作路径至dir目录 * \-n:只打印要执行的命令但不执行 * \-s:执行但不显示执行的命令 3.\[ targets \]: * 若使用make命令时没有指定目标,则make工具默认会实现makefile文件内的第一个目标,然后退出 * 指定了make工具要实现的目标,目标可以是一个或多个(多个目标间用空格隔开)。 # 工作原理 1. 若想生成目标, 检查规则中的依赖条件是否存在,如不存在,则寻找是否有规则用来 生成该依赖文件 ![](https://img.kancloud.cn/b7/67/b76700899133c2eb3481546c41440cff_588x232.png) 2. 检查规则中的目标是否需要更新,必须先检查它的所有依赖,依赖中有任一个被更新,则目标必须更新 ![](https://img.kancloud.cn/a0/1b/a01b3ed16c141750c1ea6d026d135c1d_541x275.png) **总结:** * 分析各个目标和依赖之间的关系 * 根据依赖关系自底向上执行命令 * 根据修改时间比目标新,确定更新 * 如果目标不依赖任何条件,则执行对应命令,以示更新 # 例子 测试程序: `test.c add.c sub.c mul.c div.c` **最简单的Makefile** ~~~ test:test.c add.c sub.c mul.c div.c gcc test.c add.c sub.c mul.c div.c -o test ~~~ 缺点:效率低,修改一个文件,所有文件会被全部编译 **第二个版本Makefile** ~~~ test:test.o add.o sub.o mul.o div.o gcc test.o add.o sub.o mul.o div.o -o test ​ test.o:test.c gcc -c test.c add.o:add.c gcc -c add.c sub.o:sub.c gcc -c sub.c mul.o:mul.c gcc -c mul.c div.o:div.c gcc -c div.c ~~~ # Makefile中的变量 在Makefile中使用变量有点类似于C语言中的宏定义,使用该变量相当于内容替换,使用变量可以使Makefile易于维护,修改内容变得简单变量定义及使用。 **自定义变量** 1. 定义变量方法: 变量名=变量值 2. 引用变量: ~~~ $(变量名)或${变量名} ~~~ 3. makefile的变量名: * makefile变量名可以以数字开头 * 变量是大小写敏感的 * 变量一般都在makefile的头部定义 * 变量几乎可在makefile的任何地方使用 ~~~ # 变量 OBJS=add.o sub.o mul.o div.o test.o TARGET=test ${TARGET}:${OBJS} gcc test.o add.o sub.o mul.o div.o -o test test.o:test.c gcc -c test.c -o test.o add.o:add.c gcc -c add.c -o add.o sub.o:sub.c gcc -c sub.c -o sub.o mul.o:mul.c gcc -c mul.c -o mul.o div.o:div.c gcc -c div.c -o div.o clean: rm -rf ${OBJS} ${TARGET} ~~~ 除了使用用户自定义变量,makefile中也提供了一些变量(变量名大写)供用户直接使用,我们可以直接对其进行赋值。 > CC = gcc#arm-linux-gcc > > CPPFLAGS :C预处理的选项 如:-I > > CFLAGS: C编译器的选项 -Wall -g -c > > LDFLAGS : 链接器选项 -L -l # 自动变量 * `$@`: 表示规则中的目标 * `$<`: 表示规则中的第一个条件 * `$^`: 表示规则中的所有条件, 组成一个列表, 以空格隔开,如果这个列表中有重复的项则消除重复项。 **注意:自动变量只能在规则的命令中中使用** ~~~ # 变量 OBJS=add.o sub.o mul.o div.o test.o TARGET=test CC=gcc ${TARGET}:${OBJS} gcc test.o add.o sub.o mul.o div.o -o test test.o:test.c ${CC} -c $^ -o $@ add.o:add.c ${CC} -c $^ -o $@ sub.o:sub.c ${CC} -c $^ -o $@ mul.o:mul.c ${CC} -c $^ -o $@ div.o:div.c ${CC} -c $^ -o $@ clean: rm -rf ${OBJS} ${TARGET} ~~~ # 模式规则 把一些相同的变量替换 模式规则示例: > %.o:%.c > > $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@ ~~~ # 变量 OBJS=add.o sub.o mul.o div.o test.o TARGET=test CC=gcc ${TARGET}:${OBJS} gcc test.o add.o sub.o mul.o div.o -o test %.o:%.c ${CC} -c $^ -o $@ clean: rm -rf ${OBJS} ${TARGET} ~~~ # Makefile中的函数 makefile中的函数有很多,在这里给大家介绍两个最常用的。 > 1. wildcard – 查找指定目录下的指定类型的文件 > > src = $(wildcard *.c) //找到当前目录下所有后缀为.c的文件,赋值给src > > 2. patsubst – 匹配替换 > > obj = $(patsubst %.c,%.o, $(src)) //把src变量里所有后缀为.c的文件替换成.o 在makefile中所有的函数都是有返回值的。 ~~~ # 获取当前目录下的所有.c文件 SRC=${wildcard *.c} # 将SRC中所有出现的.c替换成.o OBJS=${patsubst %.c, %.o, ${SRC}} TARGET=test CC=gcc ${TARGET}:${OBJS} gcc ${OBJS} -o ${TARGET} %.o:%.c ${CC} -c $^ -o $@ ~~~ # Makefile中的伪目标 clean用途: 清除编译生成的中间.o文件和最终目标文件 make clean 如果当前目录下有同名clean文件,则不执行clean对应的命令 解决方案: Ø伪目标声明: **.PHONY:clean** 声明目标为伪目标之后,makefile将不会该判断目标是否存在或者该目标是否需要更新 **clean命令中的特殊符号:** * “-”此条命令出错,make也会继续执行后续的命令。如:“-rm main.o” * “@”不显示命令本身,只显示结果。如:“@echo clean done” ~~~ SRC=${wildcard *.c} OBJS=${patsubst %.c, %.o, ${SRC}} TARGET=test CC=gcc ${TARGET}:${OBJS} gcc ${OBJS} -o ${TARGET} %.o:%.c @${CC} -c $^ -o $@ #声明clean为伪目标,伪目标不去判断文件是否存在或者已经更新 #无条件执行命令 .PHONY:clean clean: -rm -rf ${OBJS} ~~~ 执行 ~~~ make -f Makefile clean ~~~