一、makefile编写规则
makefile由一组规则组成 :
目标 : 依赖
( tab )命令
注意:命令前面的是 tab 键!
二、makefile工作原理
工作原理:
若想生成目标 , 检查规则中的所有的依赖文件是否都存在:如果有的依赖文件不存在, 则向下搜索规则 , 看是否有生成该依赖文件的规则,如果有规则用来生成该依赖文件, 则执行规则中的命令生成依赖文件 ;如果没有规则用来生成该依赖文件 , 则报错。
更新:
如果所有依赖都存在,检查规则中的目标是否需要更新,必须先检查它的所有依赖,依赖中有任何一个被更新,则目标必须更新。( 检查的规则是哪个时间大哪个最新)
三、实例
例:目录下有 main.c、task1.c、task2.c ,根据这个基本规则编写一个简单的 makefile 文件 ,生成可执行文件 main.
第一个版本的 makefile:
main:main.c fun1.c fun2.c sum.c
(tab)gcc main.c fun1.c fun2.c sum.c -o main -I./
缺点 :效率低 ,修改一个文件,所有的文件会全部重新编译。
第二个版本的makefile :
main:main.o fun1.o fun2.o sum.o
gcc main.o fun1.o fun2.o sum.o-o main
main.o:main.c
gcc -c main.c -o main.o-I./
fun1.o:fun1.c
gcc -c fun1.c-o fun1.o
fun2.o:fun2.c
gcc -c fun2.c-o fun2.o
sum.o:sum.c
gcc -c sum.c-o sum.o
缺点: 冗余,若 .c文件数量很多,编写起来比较麻烦。
在makefile 中使用变量有点类似于 C 语言中的宏定义,使用该变量相当于内容替换,使用变量可以使makefile 易于维护,修改起来变得简单。
makefile有三种类型的变量:
普通变量
自带变量
自动变量
普通变量
变量定义: 直接用 =
使用变量值: 用 $( 变量名 )
如: 下面是变量的定义和使用
foo = abc // 定义变量并赋值
bar = $(foo) // 使用变量, $(变量名)
自带变量
除了使用用户自定义变量, makefile中也提供了一些变量(变量名大写)供用户直接使用 ,我们可以直接对其进行赋值:
CC = gcc #arm-linux-gcc
CPPFLAGS : C预处理的选项 -I
CFLAGS: C编译器的选项 -Wall -g -c
LDFLAGS : 链接器选项 -L -l
自动变量
$@ 表示规则中的目标
$^ 表示规则中的所有条件, 组成一个列表, 以空格隔开, 如果这个列表中有重复的项消除重复项
$\< 表示规则中的第一个条件
$? 第一变化的依赖
特别注意:自动变量只能在规则的命令中使用.
makefile的第三个版本 :
target=main
object=main.o fun1.o fun2.o sum.o
CC=gcc
CPPFLAGS=-I./
$(target):$(object)
$(CC) $^ -o $@
%.o:%.c
$(CC) -c $\< -o $@ $(CPPFLAGS)
四、 makefile 函数
wildcard
wildcard – 查找指定目录下的指定类型的文件
src=$(wildcard \*.c) //找到当前目录下所有后缀为.c的文件,赋值给src
Patsubst
patsubst – 匹配替换
obj=$(patsubst %.c,%.o, $(src)) //把src变量里所有后缀为.c的文件替换成.o
makefile的第四个版本 :
src=$(wildcard ./\*.c)
object=$(patsubst %.c,%.o,$(src))
target=main
CC=gcc
CPPFLAGS=-I./
$(target):$(object)
$(CC) $^ -o $@
%.o:%.c
$(CC) -c $\< -o $@ $(CPPFLAGS)
缺点: 每次重新编译都需要手工清理中间 .o文件和最终目标文件
makefile的清理操作
伪目标声明:
.PHONY:clean
声明目标为伪目标之后,makefile 将不会检查该目标是否存在或者该目标是否需要更新
clean 命令中的特殊符号:
此条命令出错 ,make也会继续执行后续的命令。如 :-rm main.o
rm -f: 强制执行 , 比如若要删除的文件不存在使用 -f 不会报错
makefile的第5个版本:
src=$(wildcard ./\*.c) #等价于src=main.c fun1.c fun2.c sum.c,其中wildcard - 查找指定目录下的指定类型的文件
object=$(patsubst %.c,%.o,$(src)) #等价于obj=main.o fun1.o fun2.o sum.o,其中,patsubst – 匹配替换
target=main
CC=gcc
CPPFLAGS=-I./
$(target):$(object)
$(CC) -o $@ $^
%.o:%.c
$(CC) -o $@ -c $\< $(CPPFLAGS)
.PHONY:clean
clean:
-rm -f $(target) $(object)