一、make和makefile
1、make是一个应用程序,解析源程序之间的依赖关系,根据依赖关系自动维护编译工作。
2、makefile是一个描述文件,定义了一系列规则来指定各源文件编译的先后顺序。
3、makefile中的描述用于指导make程序如何完成工作,make根据makefile中的规则完成编译输出。
4、最简单的makefile示例:
hello:
@echo "hello makefile"
5、make程序使用示例:
make -f mf.txt hello
make以hello作为目标查找rm.txt文件,并执行hello目标的的命令。
6、简化make,直接输入make hello,以hello为目标查找makefile或者Makefile文件,并执行hello处的命令。
或者直接输入make,那么程序直接查找makefile或者Makefile文件中的最顶层目标,并执行。
7、示例:
hello :
echo "hello makefile"
test :
echo "test"
pwd
ls
二、makefile的结构
1、makefile用于定义源文件之间的依赖关系
依赖定义:
target : prerequistes ; command1
'\t' command2(命令年需要使用tab健缩进4个字节)
2、target:通常为需要生成的目标文件名,make所需执行的命令名称。target可包含多个目标,使用空格对目标名进行分隔
prerequistes:当前目标所依赖的其他目标或文件。prerequistes可包含多个依赖,使用空格对依赖进行分隔。
command:完成目标所需要执行的命令。 每个命令行必须以一个tab字符开始。
续行符\:可以将内容分开写到下一行。
依赖规则:
当目标对应的文件不存在,执行对应命令。
当依赖在时间上早于目标,执行对应命令。
当依赖关系连续发生时,对比依赖链上的每一个目标。
小技巧:在命令前加上@,则不回回显命令
示例1:
all : test
@echo "make all"
test :
@echo "make test"
示例2:包含func.c和main.c两个源文件
hello.out all : func.o main.o
gcc -o hello.out func.o main.o
func.o : func.c
gcc -o func.o -c func.c
main.o : main.c
gcc -o main.o -c main.c
三、伪目标
1、默认情况下,make认为目标对应着一个文件,make比较目标文件和依赖文件的新旧,决定执不执行。make以文件处理作为第一优先级。
2、通过.PHONY声明伪目标,伪目标不对应任何实际的文件,不管伪目标的依赖是否更新,命令都会被执行
示例:
.PHONY : rebuild clean all
rebuild : clean all
all : hello.out
clean :
rm -f *.o hello.out
四、变量和赋值
1、makefile中的变量只代表文本数据,即字符串,并且大小写敏感。
2、变量定义和使用
定义、CC := gcc
使用、$(CC)
3、赋值:
简单赋值(:=): 只针对当前赋值语句有效。
递归赋值(=) : 赋值操作可能影响多个地方,所有与目标有关的其他变量全部都会改变
条件赋值(?=) 如果变量已定义,则不改变变量值,如果未定义,则使用当前值
追加赋值(+=) : 原变量之后追加赋值,原值与新值用空格隔开
五、预定义变量
1、自动变量
$@:当前规则中触发命令被执行的目标
$^:当前规则中的所有依赖
$<:当前规则中的第一个依赖
2、特殊变量
$(MAKE) : 当前 make解释器的文件名(make)
$(MAKECMDGOALS): 命令行中指定的目标名(make命令行参数,即输入的make之后的命令)
$(MAKEFILE_LIST) : make所需要处理的makefile文件列表
$(MAKE_VERSION) : 当前make解释器的版本
$(CURDIR) : 当前解释器的工作目录
$(.VARIABLES) : 所有已定义的预定义变量和自定义变量
六、变量高级主题1:
1、 变量值替换:使用指定字符串替换变量值中的后缀字符串
语法格式: $(var:a=b),替换表达式中不能有任何空格
示例:
src := a.cc b.cc c.cc
obj := $(src:cc=o)
2、 变量模式替换:使用%保留变量值中的指定字符,替换其他字符
语法格式:$(var:a%b=x%y)
示例:
src := a1b.c a2b.c a3b.c
obj := $(src:a%b=x%y)
3、规则中的模式替换:
语法:
targets : target-pattern : perreq-pattern
command1
command2
.....
意义:通过target-pattern 从targets中匹配子目标,再通过perreq-pattern从子目标生成依赖,进而构成完整的规则。
示例:
OBJS := func.o mmain.o
$(OBJS) : %.o : %.c
gcc -o $@ -c $^
等价于:
func.o : func.c
gcc -o $@ -c $^
main.o: main.c
gcc -o $@ -c $^
4、命令行变量:运行make时,在命令行定义变量,命令行变量默认覆盖makefile中定义的变量值。
5、override关键字:用于指示makefile中定义的变量不能被命令行变量覆盖。
6、define关键字:用于在makefile中定义多行变量。多行变量的定义从变量名开始到endef结束,可用override修饰。
示例:
define foo
I'M fool
endef
override define cmd
@echo "run cmd"
@ls
endef
七、变量高级主题2
1、环境变量(全局变量)
makefile中能够直接使用环境变量的值;如果定义了同名变量,环境变量值将被覆盖;运行make时,加上-e,则优先使用环境变量;环境变量可在任何makefile文件中使用。
2、不同makefile中的值传递
直接在外部定义环境变量进行传递;使用export定义变量进行传递(定义临时环境变量);定义make命令行变量进行传递(推荐使用)
3、目标变量(局部变量):只能在指定目标及其连带规则中使用。
4、模式变量:模式变量是目标变量的扩展,作用域只在符合模式的目标及其连带规则中。
八、条件判断语句
条件判断语句只能用于控制make实际执行的语句,不能控制规则中命令的执行过程。类似与C语言的宏2定义,只在预处理阶段有效,执行阶段无效。
格式:
ifeq(arg1,arg2) : 判断参数是否相等
ifneq(arg1,arg2) :判断参数是否不想等
ifdef arg1 :判断变量是否有值
ifndef arg1:判断变量是否无值
九、函数定义及调用
1、自定义函数:通过define实现自定义函数,自定义函数是一个多行变量,无法直接调用;自定义函数是一种调用过程,没有任何返回值。
自定义函数语法:
define func
@echo “my name is $(0)” #$(0)表示函数名 $(1)表示函数第一个参数,$(2)表示函数第二个参数。
endef
函数调用:
test :
$(call func) #输出为my name is func
2、预定义函数:预定义函数提供了处理文件名、变量和命令的函数。函数在调用的地方被替换为处理结果。
语法:
var := $(func_name arg1,arg2.....)
示例:
var := $(abspath ./) (获取当前文件你的绝对路径,并保存到var中)
test:
@echo "var==》$(var)"
十、综合应用
1、$(wildcard _pattern)
获取当前工作目录中满足_pattern的文件或目录列表。
2、$(addprefix _pattern,_names)
给名字列表_names中的每个名字增加一个前缀_pattern 。
3、自动获取当前目录下的源文件列表(函数调用)
SRCS := $(wildcard *c)
4、根据源文件列表生成目标文件列表(变量的值替换)
OBJS := $(SRCS:.c=.o)
5、对每一个目标文件加上路径前缀(函数调用)
OBJS := $(addprefix path/,$(OBJS))
6、规则中的模式替换(目录结构)
工作目录中存在func.c main.c 源文件
模式替换:
%o : %c
gcc -o $@ -c $^
等价于:
func.o: func.c
gcc -o $@ -c $^
main.o: main.c
gcc -o $@ -c $^
示例:
CC := gcc
MKDIR := mkdir
RM := rm -fr
DIR_OBJS := objs
DIR_TARGET := target
DIRS := $(DIR_OBJS) $(DIR_TARGET)
TARGET := $(DIR_TARGET)/hello-makefile.out
SRCS := $(wildcard *.c)
OBJS := $(SRCS:.c=.o)
OBJS :=$(addprefix $(DIR_OBJS)/,$(OBJS))
.PHONY: rebuild clean all
$(TARGET) : $(DIRS) $(OBJS)
$(CC) -o $@ $(OBJS)
@echo "Target File ==>$@"
$(DIRS) :
$(MKDIR) $@
$(DIR_OBJS)/%.o : %.c
$(CC) -o $@ -c $^
rebuild: clean all
all : $(TARGET)
clean:
$(RM) $(DIRS)