Makefile的三要素:
目标:依赖
命令
例如,
hello:main.o hello.o
gcc main.o hello.o -o hello
main.o:main.c
gcc -c main.c -o main.o
hello.o:hello.c
gcc -c hello.c -o hello.o
.PHONY:clean
clean:
rm hello
利用Makefile可以高效地管理项目。我们可以用变量优化一下这个Makefile文件。
关于Makefile一些常见的变量:系统变量、自定义变量、自动化变量。
自动化变量:$<指第一个依赖文件
$^指全部的依赖文件
$@指目标
系统变量:如CC、AS、MAKE等,值为cc、as、make。
自定义变量:自己定义的变量,如A、B等。
A=123
B=$(A)
A=456
.PHONY:all
all:
echo"$(B)"
此Makefile文件执行make命令以后结果为456。因为此处的A=123是延迟赋值,只有当变量调用时等号才会将值赋给自定义变量B。:=是立即赋值。?=是空赋值,当变量值为空时赋值才有效。+=是追加赋值,在已经定义的值后面追加,例如:
A=123
A+=456
.PHONY:all
all:
echo"$(A)"
执行make命令结果为123 456.
下面演示用变量优化文章开头的Makefile文件:
CC=gcc
target=hello
obj=main.o hello.o
$(target):$(obj)
$(CC) $^ -o $@
main.o:main.c
$(CC) -c main.c -o main.o
hello.o:hello.c
$(CC) -c hello.c -o hello.o
.PHONY:clean
clean:
rm hello
这样写就变得优雅(看不懂)了起来!
在Makefile中%的作用是匹配任意多个非空字符,类似于shell中的*(通配符)。
继续优化Makefile:
CC=gcc
target=hello
obj=main.o hello.o
$(target):$(obj)
$(CC) $^ -o $@
%.o:%.c
$(CC) -c $< -o $@
.PHONY:clean
clean:
rm hello
条件分支:
ARCH ?=x86
ifeq($(ARCH),x86)
CC=gcc
else
CC=arm-linux-gnueabihf-gcc
endif
target=hello
obj=main.o hello.o
$(target):$(obj)
$(CC) $^ -o $@
%.o:%.c
$(CC) -c $< -o $@
.PHONY:clean
clean:
rm hello *.o
执行make ARCH=arm后,hello应用程序就是由arm-linux-gnueabihf-gcc编译的了。
常见函数:
patsubst、notdir、wildcard、foreach
patsubst示例:
#Makefile_1
.PHONY:all
all:
echo "$(patsubst %.c, %.o ,x.c.c bar.c)"
执行make -f Makefile_1命令后,结果为x.c.o bar.o。patsubst函数的功能就是指定模式替换。(这里需要注意的是,patsubst函数完成的是模式字符串替换,获取到的和输出的都是字符串,执行完函数以后并不会改变原来文件的后缀!)
notdir示例:
#Makefile_2
.PHONY:all
all:
echo "$(notdir src/fo.c bar.c)"
执行make -f Makefile_2命令后,结果为fo.c bar.c。patsubst函数的功能就是删除文件的路径,只保留文件名,没有路径则不做改变。
wildcard示例:
#Makefile_3
.PHONY:all
all:
echo "$(wildcard *.c)"
执行make -f Makefile_2命令后,结果为x.c xxx.c。wildcard函数的功能就是获取当前目录下匹配模式的文件名。
foreach示例:
#Makefile_4
dirs:=a b c d
files:=$(foreach dir,$(dirs),$(wildcard $(dir)/*))
.PHONY:all
all:
echo "$(files)"
上述语句实现的功能等价于files:=$(wildcard a/* b/* c/* d/*)。foreach函数会遍历dirs中的所有内容并赋值给dir,dir参与wildcard $(dir)/*的运算。