Makefile快速学习上手
一、Makefile介绍
1、Makefile规则
target ... : prerequisites ...
command
...
(1)command一定要以Tab开头
(2)prerequisites中若有一个文件比target新,或target不存在,command命令就会执行。
2、make是如何工作的
(1)在当前目录下找Makefile或makefile
(2)找第一个target,作为最终的目标文件
(3)若target不存在或依赖的修改时间比它新,就执行后面定义的命令
(4)依次以依赖循环下去,直到生成最终目标
3、变量
定义:OBJ = main.o test.o
使用:$(OBJ)
4、自动推导
make找到*.o那么*.c就是其依赖文件。
二、Makefile总述
1、Makefile组成
(1)显式规则:如何生成目标文件
(2)隐晦规则:自动推导
(3)变量定义:变量一般是字符串
(4)文件指示:①引用另一个Makefile ②指定有效部分
(5)注释:#
(6)命令必须tab开头
2、Makefile文件名
make默认寻找GNUmakefile、makefile、Makefile,也可使用-f或--file指定
3、引用其他Makefile
include ...
(1)前面可以有空格,但不能是tab。
(2)默认在当前目录寻找,然后/usr/local/bin或/usr/include
(3)-I 或 --include-dir指定目录
(4)未找到文件生成警告消息,继续执行,再次寻找时会产生致命信息
(5)-include <filename>加横杆忽略错误
4、工作方式
(1)读Makefile
(2)include
(3)初始化变量
(4)推导隐晦规则
(5)创建依赖关系链
(6)根据依赖关系,决定哪些目标重新生成
(7)执行命令
三、书写规则
1、通配符
*, ?, [...]
2、伪目标
.PHONY : clean
避免和文件重名
3、多目标
$@所有目标集合
4、静态模式
<targets ...>:<target-pattern>:<prereq-patterns ...>
<commands>
...
targets 定义了一系列目标文件
target-parrtern 指明模式
prereq-patterns 目标的依赖模式
objects = foo.o bar.o
all: $(objects)
$(objects): %.o: %.c
$(CC) -c $(CFLAGS) $< -o $@
5、自动生成依赖
-M 自动寻找源文件中包含的头文件,并生成依赖关系
-MM 避免包含标准库头文件
%d: %.c
@set -e; rm -rf $@; \
$(CC) -M $(CPPFLAGS) $< > $@.$$$$; \
sed `s, \($*\)\.o[ :]*,\1.o $@ : ,g` < $@.$$$$ > $@; \
rm -f $@.$$$$
四、书写命令
1、显式命令
① @在命令前,不显示执行的命令
② make -n 或 --just-print只显式不执行
2、命令执行
① 后一条命令依赖前一条命令的结果,需写在一行用";"分开
3、命令出错
① 命令出错终止执行
② 加横杆-,忽略错误
③ make -i 或者 --ignore-errors,忽略所有命令的错误
4、嵌套执行
subsystem:
cd subdir && $(MAKE)
或
subsystem:
$(MAKE) -C subdir
① Makefile变量可以传递到下级,但不会覆盖,除非指定-e参数
② export <variable ...> 传递到下级,后面不跟变量表示传递所有变量
③ unexport <variable ...> 不传递到下级
5、定义命令包
define run-yacc
yacc $(firstwword $^)
mv y.tab.c $@
endef
foo.c: foo.y
$(run-yacc)
五、变量
由字符、数字、下划线组成,大小写敏感
1、声明时赋初值,使用$引用,最好加()或{}
使用$字符,$$
2、使用时赋值
foo = $(bar)
bar = 123
3、立即赋值
x := foo
y := $$(x)
x := later
4、判断赋值,未赋值才赋值
FOO ?= 456
5、追加变量赋值
x = test.c
x += main.c
6、参数变量
make CC=gcc
7、override覆盖参数变量值
override CC = g++
override CC := g++
8、多行变量
define two-lines
echo foo # 可以是函数、命令、文字、其他变量
echo $(bar)
endef
9、环境变量
① Makefile中可使用环境变量,make参数和里面定义的变量会覆盖环境变量
② 若make -e则环境变量覆盖他们
③ 上层Makefile中变量可使用export声明传递到下层
10、目标变量
<target ...>: <variable-assignment>
<target ...>: override <variable-assignment>
11、模式变量
<pattern ...>: <variable-assignment>
<pattern ...>: override <variable-assignment>
%.o: CFLAGS = -O
六、条件判断
条件表达式可以是比较变量的值、变量、常量
1、ifeq ($(CC), gcc)
@echo ""
else
@echo ""
endif
2、语法
①
<conditional-directive>
<text-if-true>
endif
②
<conditional-directive>
<text-if-true>
else
<text-if-true>
endif
③
ifeq (<arg1>, <arg2>)
ifeq '<arg1>' '<arg2>'
ifeq "<arg1>" "<arg2>"
ifeq "<arg1>" '<arg2>'
ifeq '<arg1>' "<arg2>"
ifdef foo #测试变量是否有值
七、函数
1、函数调用
$(<function> <arguments>)
${<function> <arguments>}
bar := $(subst $(sub), $(value), $(main))
2、字符串处理函数
$(subst <from>, <to>, <text>) # 替换子字符串
$(patsubst <pattern>, <replacement>, <text>) # 模式替换字符串
$(strip <string>) # 去除首位的空格
$(findstring <find>, <in>) # 查找字符串是否存在
$(filter <pattern...>, <text>) # 模式过滤字符串
$(filter-out <pattern...>, <text>) # 反过滤字符串
$(sort <list>) # 给字符串中的单词升序排序
$(word <n>, <text>) # 取text中第n个单词
$(wordlist <s>, <e>, <text>) # 取text中第s到e中的单词
$(words <text>) # 统计单词个数
$(firstword <text>) # 取第一个单词
3、文件名操作函数
$(dir <names...>) # 取目录
$(suffix <names...>) # 取后缀
$(basename <names...>) # 取前缀
$(addsuffix <suffix>, <names...>) # 加后缀
$(addprefix <prefix>, <names...>) # 加前缀
$(join <list1>, <list2>) # 单词连接
4、foreach
$(foreach <var>, <list>, <text>) # 逐个参数值处理
names := a b c d
files := $(foreach n,$(names),$(n).o)
5、if函数
$(if <condition>, <then-part>) 或
$(if <condition>, <then-part>, <else-part>)
6、call函数
$(call <expression>, <parm1>, <parm2>, <parm3>...)
reverse = $(1) $(2)
foo = $(call reverse, a, b)
7、shell函数
files := $(shell echo *.c)
生成shell程序来执行命令,注意性能问题
八、make的运行
1、make退出码
0 成功,1 错误,2 make -q,使得一些目标不需要更新
2、指定文件-f或--file
3、指定目标
① make install,make clean
② "="或"-"开头时会被解析成参数或变量
③ MAKECMDGOALS环境变量指定目标
④ 常用功能
all :编译所有目标
clean:删除创建的文件
print:列出改变过的源文件
tar:打包源程序
dist:创建压缩文件
TAGS:更新所有目标,以备完整地重编译使用
check和test:测试Makefile的流程
4、检查规则
参数:-n、--just-print、--dry-run,--recon
5、参数
① -b和-m忽略和其他make版本的兼容性
② -B和--always-make重编译
③ -C和--directory=<dir>指定读取Makefile的目录
④ -e和--environment-overrides指明环境变量的值覆盖makefile中值
⑤ -f、--file、--makefile指定文件
⑥ -h和--help显式帮助信息
⑦ -i和--ignore-errors忽略执行错误
⑧ -I 和--include-dir=指定包含makefile的搜索目标
⑨ -j和--jobs指定同时运行命令个数
11 -q和--question检查目标是否需要更新
12 -r和--nobuiltin-rules禁止make使用任何隐含规则
九、隐含规则
1、make自动推导规则和命令
2、-r和--no-builtin-rules取消隐含规则,有默认后缀列表的还是会生效
3、常用隐含规则
① C语言,<n>.o的目标的依赖会自动推导为<n>.c
② c++,<n>.o的目标的依赖会自动推导为<n>.cc或<n>.C
③ 汇编和汇编预处理,<n>.o的目标的依赖会自动推导为<n>.s
4、隐含规则使用变量
① 命令变量
AR :ar 函数库打包
AS :as 汇编语言编译
CXX :g++
CPP :c程序预处理器
RM :rm -rf
② 命令参数变量
ARFLAGS :rv 函数库打包程序AR的参数
ASFLAGS :汇编语言编译器参数
CFLAGS :c语言编译器参数
CXXFLAGS:c++语言编译器参数
CPPFLAGS:c预处理器参数
LDFLAGS :链接器参数
5、隐含规则链
产生中间文件
6、定义模式规则
1、目标中%表示对文件名的匹配,%.c或s.%.c
2、示例
%.o : %.c
$(CC) -c $(CFLAGS) $(LDFLAGS) $< -o $@
$< 依赖挨个值,$@ 目标挨个值
7、自动变量
把模式中所定义的一系列的文件自动地挨个取出。
$@ 目标文件集,若有多个目标匹配于目标中模式定义的集合
$% 仅当目标是函数库文件中,表示规则中的目标成员名
$< 依赖目标中的第一个目标名字
$? 所有比目标新的依赖目标的集合
$^ 所有依赖目标的集合,去除重复
$+ 与$^相似,但不去重
$* 表示目标模式中%及其之前的部分。如dir/a.foo.b模式a.%.b, $*为dir/a.foo
$(@D) 表示$@的目录部分
$(@F) 表示$@的文件部分
$(*D)、$(*F) 与前两个相似,但不包含后缀
$(<D)、$(<F) 表示第一个依赖的目录和文件部分
$(^D)、$(^F) 表示所有依赖的目录和文件部分,无相同
$(+D)、$(+F) 表示所有依赖的目录和文件部分,可相同
$(?D)、$(?F) 表示被更新的依赖的目录和文件部分
8、模式匹配
① 依赖目标的茎会传给目标
② 有斜杆时会先将目录部分移开,匹配成功后再加回去。
十、更新函数库文件
1、隐含规则
%.o会去找bar.o, 没有的话去找bar.c来生成bar.o
cc -c bar.c -o bar.o
ar r foo.a bar.o
rm -rf bar.o
2、后缀规则
.c.a:
$(CC) $(CFLAGS) $(CPPFLAGS) -c $< -o $*.o
$(AR) r $@ $*.o
$(RM) $*.o
等效:
(%.o) : %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -C $< -o $*.o
$(AR) r $@ $*.o
$(RM) $*.o
并行机制-j可以损坏函数库
十一、实例
#################################################
BIN = main
OBJS = a.o b.o c.o
CFLAGS = -Werror -Iinclude
CC = gcc
DEPENDE_FILES := $(patsubst %, .%.d, $(OBJS))
DEPENDE_FILES := $(wildcard $(DEPENDE_FILES))
$(BIN): $(OBJS)
$(CC) -o $@ $^
ifneq ($(DEPENDE_FILES),)
include $(DEPENDE_FILES)
endif
%.o : %.c
$(CC) $(CFLAGS) -c -o $@ $< -MD -MF .$@.d
clean:
rm *.o $(BIN)
distclean:
rm $(DEPENDE_FILES)
.PHONY: clean
#################################################
参考《一起来写Makefile》
欢迎转载请注明出处:海漩涡
http://blog.csdn.net/tanhuifang520