文章目录
- 0.概述
- 1.函数调用语法
- 2.字符串处理函数
- 2.1 subst(字符串替换函数)
- 2.2 patsubst(模式字符串替换函数)
- 2.3 strip(去空格函数)
- 2.4 findstring(查找字符串函数)
- 2.5 filter(过滤函数)
- 2.6 filter-out(反过滤函数)
- 2.7 sort(排序函数)
- 2.8 word(取单词函数)
- 2.9 wordlist(取单词串函数)
- 2.10 words(单词个数统计函数)
- 2.11 firstword(首单词函数——firstword)
- 3.文件名操作函数
- 3.1 dir(取目录函数)
- 3.2 notdir(取文件函数)
- 3.3 suffix(取後缀函数)
- 3.4 basename(取前缀函数)
- 3.5 addsuffix(加后缀函数)
- 3.6 addprefix(加前缀函数)
- 3.7 join(连接函数)
- 4. 其他函数
- 4. 1 foreach 函数(几乎是仿照for语句)
- 4. 2 if 函数(类似make所支持的条件语句——ifeq)
- 4. 3 call 函数(创建新的参数化的函数)
- 4. 4 origin函数(变量是哪里来的)
- 4. 5 shell函数(Shell的命令)
- 4. 6 控制make的函数
- 5. 补充
- 5.1 wildcard
- 6. 实用模板
- 6.1 实例1
- 6.2 实例2(生成多目标)
0.概述
在Makefile中可以使用函数来处理变量,从而让我们的命令或是规则更为的灵活和具有智能。
makefile详细消息见makefile经验总结。部分函数是工作中遇到的补充。
1.函数调用语法
函数调用,很像变量的使用,也是以 $ 来标识的,其语法如下:
$(<function> <arguments>)
或是:
${<function> <arguments>}
function 就是函数名,make支持的函数不多。 arguments 为函数的参数,参数间以逗号 , 分隔,而函数名和参数之间以“空格”分隔。函数调用以 $ 开头,以圆括号或花括号把函数名和参数括起。感觉很像一个变量,是不是?函数中的参数可以使用变量,为了风格的统一,函数和变量的括号最好一样。
示例:
comma:= ,
empty:=
space:= $(empty) $(empty)
foo:= a b c
bar:= $(subst $(space),$(comma),$(foo))
在这个示例中, $(comma) 的值是一个逗号。 $(space) 使用了 $(empty) 定义了一个空格, $(foo) 的值是 a b c , $(bar) 的定义用,调用了函数 subst ,这是一个替换函数,这个函数有三个参数,第一个参数是被替换字串,第二个参数是替换字串,第三个参数是替换操作作用的字串。这个函数也就是把 $(foo) 中的空格替换成逗号,所以 $(bar) 的值是 a,b,c 。
2.字符串处理函数
2.1 subst(字符串替换函数)
2.2 patsubst(模式字符串替换函数)
2.3 strip(去空格函数)
2.4 findstring(查找字符串函数)
2.5 filter(过滤函数)
2.6 filter-out(反过滤函数)
2.7 sort(排序函数)
2.8 word(取单词函数)
2.9 wordlist(取单词串函数)
2.10 words(单词个数统计函数)
2.11 firstword(首单词函数——firstword)
以上,是所有的字符串操作函数,如果搭配混合使用,可以完成比较复杂的功能。这里,举一个现实中应用的例子。我们知道,make使用 VPATH 变量来指定“依赖文件”的搜索路径。于是,我们可以利用这个搜索路径来指定编译器对头文件的搜索路径参数 CFLAGS ,如:
override CFLAGS += $(patsubst %,-I%,$(subst :, ,$(VPATH)))
如果我们的 $(VPATH) 值是 src:…/headers ,那么 ( p a t s u b s t (patsubst %,-I%, (patsubst(subst :, ,$(VPATH))) 将返回 -Isrc -I…/headers ,这正是cc或gcc搜索头文件路径的参数。
3.文件名操作函数
下面我们要介绍的函数主要是处理文件名的。每个函数的参数字符串都会被当做一个或是一系列的文件名来对待。
3.1 dir(取目录函数)
3.2 notdir(取文件函数)
3.3 suffix(取後缀函数)
3.4 basename(取前缀函数)
3.5 addsuffix(加后缀函数)
3.6 addprefix(加前缀函数)
3.7 join(连接函数)
4. 其他函数
4. 1 foreach 函数(几乎是仿照for语句)
4. 2 if 函数(类似make所支持的条件语句——ifeq)
4. 3 call 函数(创建新的参数化的函数)
4. 4 origin函数(变量是哪里来的)
4. 5 shell函数(Shell的命令)
4. 6 控制make的函数
5. 补充
5.1 wildcard
$(wildcard <PATTERN...>)
用于获取匹配该模式下的所有文件列表,<PATTERN…>参数若有多个则用空格分隔。若没有找到指定的匹配模式则返回为空。
6. 实用模板
基于工作经验编写的makefile 模板,基本满足日常需求。
6.1 实例1
#目标文件
TARGET = targe_bin
#目标路径
CUR_PATH = .
#获取所有c cpp文件
DIRS = $(shell find $(CUR_PATH) -maxdepth 10 -type d)
SRC = $(foreach dir, $(DIRS), $(wildcard $(dir)/*.cpp))
CSRC = $(foreach dir, $(DIRS), $(wildcard $(dir)/*.c))
CCSRC = $(foreach dir, $(DIRS), $(wildcard $(dir)/*.cc))
# 将所有.c,.cpp文件改为对应的.o文件
OBJS = $(patsubst %.cpp,${DIR_OBJ}/%.o,$(notdir ${SRC}))
COBJS = $(patsubst %.c,${DIR_OBJ}/%.o,$(notdir ${CSRC}))
CCOBJS = $(patsubst %.cc,${DIR_OBJ}/%.o,$(notdir ${CCSRC}))
#确认.c文件路径
VPATH = $(DIR_SRC):$(XXX)
- 使用shell函数find 列出搜索路径下所有的文件列表
- 通过foreach函数轮询find函数搜索结果,通过wildcard函数展开.cpp .c .cc文件,注意结果中包含路径。
- 通过notdir函数去除第二步中的路径,再调用patsubst函数将.cc .c .cpp 文件转换为.o文件。
编译选项配置环节合库的链接。
#c语言编译选项
CFLAGS += -W -fPIC -DNONUTF8CONV -DELPP_NO_DEFAULT_LOG_FILE '-Wno-implicit-fallthrough' -Wfatal-errors
#cc cpp规则
CPPFLAGS += $(CFLAGS) -std=c++14 -fpermissive -no-pie
LIBS += -L./lib -Lxxx
LIBS += -lpthread -lxxx
INC += -I./ -I/xxx
目标生成
all: dir_check ${OBJS} ${COBJS} ${CCOBJS}
$(CXX) $(CPPFLAGS) -g ${OBJS} ${COBJS} ${CCOBJS} -o ${BIN_TARGET} $(LIBS)
#$(CXX) $(CPPFLAGS) -g ${OBJS} ${COBJS} ${CCOBJS} -o ${BIN_TARGET} $(LIBS)
#编译所有源文件
${DIR_OBJ}/%.o:%.cpp
$(CXX) $(CPPFLAGS) $(INC) -c $< -o $@ $(LIBS)
${DIR_OBJ}/%.o:%.cc
$(CXX) $(CPPFLAGS) $(INC) -c $< -o $@ $(LIBS)
${DIR_OBJ}/%.o:%.c
$(CC) $(CFLAGS) $(INC) -c $< -o $@ $(LIBS)
dir_check:
-d ./obj || mkdir -p ./obj
.PHONY: clean
clean:
rm -rf ${OBJS} ${COBJS} ${CCOBJS} $(BIN_TARGET)
通过自动化变量$@ $< 生成目标.o,通过目标.o生成bin文件。
6.2 实例2(生成多目标)
利用伪目标生成多目标,make一次生成多个。
# this is the build file for project
# it is autogenerated by the xmake build system.
# do not edit by hand.
MXX=/usr/bin/gcc
AS=/usr/bin/gcc
CXX=/usr/bin/gcc
MM=/usr/bin/gcc
CC=/usr/bin/gcc
AR=/usr/bin/ar
SH=/usr/bin/g++
LD=/usr/bin/g++
example.out_CXXFLAGS=-m64 -g -xxx
example.out_LDFLAGS=-m64 -g -Llib/linux -s -liclient -lcurl -lpthread -ldl
iclient_CXXFLAGS=-m64 -g -xxx
iclient_ARFLAGS=-cr
all: iclient example.out
#.PHONY: all example.out iclient
.PHONY: all example.out iclient
example.out: bin/example.out
bin/example.out: a.o b.o c.o
linking.release example.out
-p bin
@$(LD) -o bin/example.out
a.o: a.cpp
a.cpp
-p build
@$(CXX) -c -g $(example.out_CXXFLAGS) -o a.o example/a.cpp > build/.build.log 2>&1
b.o: b.cpp
b.cpp
-p build
@$(CXX) -c -g $(example.out_CXXFLAGS) -o b.o example/b.cpp > build/.build.log 2>&1
c.o: c.cpp
c.cpp
-p build
@$(CXX) -c -g $(example.out_CXXFLAGS) -o c.o example/c.cpp > build/.build.log 2>&1
iclient: lib/linux/libiclient.a
lib/linux/libiclient.a: A.o B.o C.o
linking.release libiclient.a
-p lib/linux
@$(AR) $(iclient_ARFLAGS) lib/linux/libiclient.a A.o B.o C.o > build/.build.log 2>&1
A.o: src/A.cpp
compiling.release A.cpp
-p build
@$(CXX) -c -g $(iclient_CXXFLAGS) -o A.o A.cpp > build/.build.log 2>&1
B.o: src/B.cpp
compiling.release B.cpp
-p build
@$(CXX) -c -g $(iclient_CXXFLAGS) -o B.o B.cpp > build/.build.log 2>&1
C.o: src/C.cpp
compiling.release C.cpp
-p build
@$(CXX) -c -g $(iclient_CXXFLAGS) -o C.o C.cpp > build/.build.log 2>&1
clean: clean_example.out clean_iclient
clean_example.out: clean_iclient
-rf bin/example.out
-rf bin/example.out.sym
-rf a.o
-rf b.o
-rf c.o
clean_iclient:
-rf lib/linux/libiclient.a
-rf lib/linux/iclient.sym
-rf A.o
-rf B.o
-rf C.o