学习目标:
学习Makefile一下关键字:
addprefix :加前缀
patsubst:更改后缀
参考: Makefile 简介 - Makefile基本概念介绍 - Makefile 简明教程 | 宅学部落
1- 分支
语法:
ifeq (arg1, xxx)
do somethings
else ifeq (arg1, yyy)
do somethings
else
do somethings
endif
语法和C语言基本一致
注意:
a- ifeq和后面的条件判断“(xxx)”之间必须有空格
b- 条件判断(arg1, xxx)的arg1和xxx之间可以有空格,也可以不加空格
c- do something可以缩进,也可以不缩进。
d- 如果do something为赋值语句CC = gcc。赋值语句等号前后可以有空格,也可以不加空格
示例:
ifeq ($(ARCH), x86)
CC = gcc
$(info "[info]: gcc")
else ifeq ($(ARCH), arm)
CC = arm-linux-gcc
$(info "[info]: arm-linux-gcc")
else
CC = arm-linux-gnueabihf-gcc
$(info "[info]: arm-linux-gnueabihf-gcc")
endif
all:
@echo ""
结果:
[root@localhost makefile]# make
"[info]: arm-linux-gnueabihf-gcc"
[root@localhost makefile]# make ARCH=x86
"[info]: gcc"
其他:
对于内核编译模块我们也会使用分支,比如《linux设备驱动程序》就有介绍:
ifneq ($(KERNELRELEASE),)
obj-m := hello.o
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
2- 字符处理
2.1- patsubst 正则替换
格式:$(patsubst <pattern>,<replacement>,<text> )
功能:查找<text>中的单词(单词以“空格”、“Tab”或“回车”“换行”分隔)是否符合模式<pattern>,如果匹配的话,则以<replacement>替换。这里,<pattern>可以包括通配符“%”,表示任意长度的字串。如果<replacement>中也包含“%”,那么,<replacement>中的这个“%”将是<pattern>中的那个“%”所代表的字串。可以用“\”来转义,以“\%”来表示真实含义的“%”字符
返回:函数返回被替换过后的字符串。如果没有匹配上的原样输出。
场景:替换文件后缀
示例:
ret = $(patsubst %.c,%.o, a.c b.c c.bat)
all:
@echo "ret: $(ret)"
结果:
ret: a.o b.o c.bat
2.2- subst 普通替换
格式:$(subst <from>,<to>,<text> )
功能:查找<text>中的单词,将from字符替换为to字符
场景:替换字符
示例:
ret = $(subst world, makefile, "hello world")
all:
@echo "ret: $(ret)"
结果:
ret: hello makefile
2.3- $(VAR:A=B)--变量替换
格式:$(VAR:A=B)
功能:将变量VAR中匹配A的字符替换成B
返回:返回替换结果。
场景:替换文件后缀
示例:
foo := a.c b.c c.bat
ret := $(foo:.c=.o)
all:
@echo "ret: $(ret)"
结果:
ret: a.o b.o c.bat
这里发现$(VAR:A=B)和patsubst功能基本相似。
2.4- filter 过滤
格式:$(filter PATTERN…,TEXT)
功能:过滤掉TEXT中不符合PATTERN的字符
返回:返回匹配结果
示例:
foo = a.c b.c c.s d.h
ret = $(filter %c %s, $(foo))
all:
@echo "ret: $(ret)"
结果:
ret: a.c b.c c.s
2.5- filter-out 反过滤
格式:$(filter-out PATTERN…,TEXT)
功能:过滤掉TEXT中符合PATTERN的字符
返回:返回匹配结果
示例:
foo = a.c b.c c.s d.h
ret = $(filter-out %c %s, $(foo))
all:
@echo "ret: $(ret)"
结果:
ret: d.h
2.6- findstring --字符查找
格式:$(findstring FIND, IN)
功能:在IN中查找FIND字符
返回:返回查找结果。没找到返回空
示例:
ret1 = $(findstring world, "hello world")
ret2 = $(findstring makefile, "hello world")
all:
@echo "ret1: $(ret1)"
@echo "ret2: $(ret2)"
结果:
ret1: world
ret2:
2.7- strip--去除空格
格式:$(strip TEXT)
功能:去除TEXT前后空格字符,对于中间多个空格合并为1个空格
返回:返回去除后字符
示例:
str1 := abc
str2 := abc
str3 := a b c
all:
@echo ---$(strip $(str1))---
@echo ---$(strip $(str2))---
@echo ---$(strip $(str3))---
结果:
---abc---
---abc---
---a b c---
2.7- 其他
sort : 排序
world : 取单词
wordlist函数:取字串
words函数:统计单词数目
firstword函数:取首个单词
详情参考:Makefile 文本处理函数(下) : sort、word、wordlist、words、firstword函数详解 - Makefile 简明教程 | 宅学部落
3- foreach 遍历操作
格式:$(foreach VAR,LIST,TEXT)
功能:遍历LIST中每个变量,每次遍历的中间值保存在VAR,TEXT对VAR处理
返回:返回处理结果。
场景:遍历处理文件后缀;遍历获取所有.c文件等。参考:Makefile foreach函数 - Makefile 简明教程 | 宅学部落
示例:
foo := a b c
ret := $(foreach var,$(foo),$(var).o)
all:
@echo "ret: $(ret)"
结果:
ret: a.o b.o c.o
4- 目录处理
4.1- wildcard --获取目录下文件
格式:$(wildcard pattern)
功能:获取匹配pattern规则的信息
返回:返回匹配pattern规则的信息
场景:获取路径下所有.c文件。
示例:
#获取当前路径下的.c文件
ret := $(wildcard *.c)
all:
@echo "ret: $(ret)"
结果:
ret: a.c b.c
4.2- notdir dir --去除/获取路径
格式:$(notdir 文件列表)
功能:去除文件路径
返回:返回去除文件路径后结果
格式:$(dir 文件列表)
功能:获取文件路径
返回:返回文件路径
示例:
ret_dir := $(dir /home/lhk/a.c)
all:
@echo "ret_notdir: $(ret_notdir)"
@echo "ret_dir: $(ret_dir)"
结果:
ret_notdir: a.c
ret_dir: /home/lhk/
4.3- suffix basename --获取文件名后缀/前缀
格式:$(suffix
文件列表)
功能:获取后缀
格式:$(basename 文件列表)
功能:获取前缀
示例:
ret_suffix := $(suffix /home/lhk/a.c)
ret_basename := $(basename /home/lhk/a.c)
all:
@echo "ret_suffix: $(ret_suffix)"
@echo "ret_basename: $(ret_basename)"
结果:
ret_suffix: .c
ret_basename: /home/lhk/a
4.4- addprefix,addsuffix :加前缀/后缀
格式:$(addprefix PREFIX, NAMES…)
功能:给NAMES…加前缀 PREFIX
格式:$(addsuffix SUFFIX, NAMES…)
功能:给NAMES…加后缀SUFFIX
示例:
first := /home/lhk/
second := lhk_c/main.c
ret_addprefix = $(addprefix $(first), $(second))
foo := a b c
ret_addsuffix = $(addsuffix .c, $(foo))
all:
@echo "ret_addprefix: $(ret_addprefix)"
@echo "ret_addsuffix: $(ret_addsuffix)"
结果:
ret_addprefix: /home/lhk/lhk_c/main.c
ret_addsuffix: a.c b.c c.c
4.5- join 连接
格式:$(join str1..., str2...)
功能:将str1和str2连接起来
示例:
first = a b c
second = .c .h
ret = $(join $(first),$(second))
all:
@echo "ret: $(ret)"
结果:
ret: a.c b.h c
综合示例:
摘录野火makefile : http://doc.embedfire.com/linux/imx6/base/zh/latest/linux_app/makefile.html#id13
#定义变量
#ARCH默认为x86,使用gcc编译器,
#否则使用arm编译器
ARCH ?= x86
TARGET = hello_main
#存放中间文件的路径
BUILD_DIR = build_$(ARCH)
#存放源文件的文件夹
SRC_DIR = sources
#存放头文件的文件夹
INC_DIR = includes .
#源文件
SRCS = $(wildcard $(SRC_DIR)/*.c)
#目标文件(*.o)
OBJS = $(patsubst %.c, $(BUILD_DIR)/%.o, $(notdir $(SRCS)))
#头文件
DEPS = $(wildcard $(INC_DIR)/*.h)
#指定头文件的路径
CFLAGS = $(patsubst %, -I%, $(INC_DIR))
#根据输入的ARCH变量来选择编译器
#ARCH=x86,使用gcc
#ARCH=arm,使用arm-gcc
ifeq ($(ARCH),x86)
CC = gcc
else
CC = arm-linux-gnueabihf-gcc
endif
#目标文件
$(BUILD_DIR)/$(TARGET): $(OBJS)
$(CC) -o $@ $^ $(CFLAGS)
#*.o文件的生成规则
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c $(DEPS)
#创建一个编译目录,用于存放过程文件
#命令前带“@”,表示不在终端上输出
@mkdir -p $(BUILD_DIR)
$(CC) -c -o $@ $< $(CFLAGS)
#伪目标
.PHONY: clean cleanall
#按架构删除
clean:
rm -rf $(BUILD_DIR)
#全部删除
cleanall:
rm -rf build_x86 build_arm
5- origin--变量来源
格式:$(origin 变量)
功能:获取变量来源。来源:命令行,文件定义,环境变量,未定义,自动变量,重定义等
返回:返回变量来源
详细参考:makefile之origin函数 - suonikeyinsu - 博客园
示例:
all:
@echo $(origin vv)
结果:
[root@localhost makefile]# make vv="hello"
command line
[root@localhost makefile]# make
undefined
6- call --函数调用
格式:$(call VARIABLE,PARAM1,PARAM2,..)
功能:类似函数调用。VARIABLE可以为变量也可以为函数,PARAM为入参值
返回:返回执行结果
示例:
reverse = $(2) $(1)
define func_rev
$(2) $(1)
endef
ret_var = $(call reverse,a,b)
ret_func = $(call func_rev,a,b)
all:
@echo "ret_var=$(ret_var)"
@echo "ret_func=$(ret_func)"
结果:
ret_var=b a
ret_func=b a
注意:如果使用变量方式,需要注意变量为reverse = $(2) $(1) 和 reverse := $(2) $(1) 间差别;
传入参数间的空格也会照样认为是入参。