第⼋载:makefile中函数定义及调⽤
在Makefile中,是⽀持函数使⽤的,Makefile中的函数包括make解释器⾃⾝预定义的函数,同时也⽀持我们⾃⼰定义函数。
在Makefile中, 通过define关键字来实现函数的⾃定义,并以endef关键字结束,⾃定义函数使⽤预定义函数call调⽤,后边跟⾃定义函数名及参数,如下就是⼀个简单的⾃定义函数:
.PHONY : test
define fun1
@echo "My name is $(0)"
endef
define fun2
@echo "My name is $(0), param is $(1)"
endef
test:
$(call fun1)
$(call fun2, hello Makefile)
上边我们⾸先定义了⼀个伪⽬标test,接着定义了两个函数,fun1和fun2。fun1中直接通过$(0)输出call 的第⼀个参数,也就是函数名fun1,fun2中同时输出了第⼆个参数(这看起来有点 类似C语⾔⾥的main函数参数)。 在调⽤⾃定义函数fun1和fun2时,格式为$(call 函数名,参数...),call函数的参数需要以逗号","隔开,下边 执⾏如下:
除了可以⾃定义函数外,make解释器还提供了众多预定的函数供我们使⽤,⽐⽅abspath(取⽂件的绝对路径)
.PHONY : test2
var := $(abspath ./)
test2 :
@echo $(var)
这⾥需要注意的是, 当我们使⽤make解释器中预定义的 函数时,不需要通过call调⽤,⽽是直接$(函数名 参数1,参数2,...),下边make⼀下:
可见,输出了我当前路径的绝对路径。
上述仅仅是⼀些基础知识,下边就来使⽤make中的变量与函数来实现⼀个⼩综合例⼦(会使⽤到⼀些预定义函数),要求如下:
1、⾃动⽣成target⽂件夹 存放可执⾏⽂件
2、⾃动⽣成objs⽂件夹存放编译⽣成的⽬标⽂件(*.o)
3、 ⽀持调试版本的 编译选项
4、考虑代码的可扩展性
在开始之前,⾸先来了解⼏个关键技巧
1、⾃动获取当前⽬录下的源⽂件列表(预定义函数wildcard)
- SRCS := $(wildcard *.c)
2、由源⽂件列表 ⽣成⽬标⽂件列表(变量的值变换)
-OBJS := $(SRCS : .c=.o)
3、为每个 ⽬标⽂件列表增加路径前缀(预定义函数调⽤addprefix)
- OBJS := $(addprefix path/, $(OBJS))
4、规则的模式替换,这⾥⼀共可以分为两种形式:
- 变量中的规则模式替换,如下
其中$(OBJS):%.o:%.c的意思就是,$(OBJS):%.o在变量OBJS中 逐个匹配后缀为.o的⽂件,将匹配到的变量作为⽬标,然后再将该变量的后缀由.o替换为.c,作为⽬标的依赖。合成的 步骤就是$(OBJS):%.o:%.c -> func.o:%.c -> func.o:func.c,这样变形成了func.o为⽬标,func.c为依赖的⼀条规则,同理main.o与main.c的⽬标依赖关系也是 这么形成的。
- ⽬录中的规则模式替换,⽬录与变量的主要区别就是⼀个是从当前⽬录中去匹配,⼀个是从变量中去匹配。
这⾥我们可以看到⽬录中的规则模式匹配,省去的⽬标 变量$(OBJS),⽽是直接 %.o:%.c 从 当前⽬中
去进⾏.o⽂件的模式匹配。
对于以上5点技巧,我们以⼀个简单的实例来展⽰:
.PHONY : all clean
CC := gcc
SRCS := $(wildcard *.c)
OBJS := $(SRCS:.c=.o)
OBJSPATH := $(addprefix path/, $(OBJS))
all: $(OBJS)
@echo "SRCS => $(SRCS)"
@echo "OBJS => $(OBJS)"
@echo "OBJSPATH => $(OBJSPATH)"
#变量中的规则模式替换
#$(OBJS):%.o:%.c
# @echo $(CC) -o $@ -c $^
#⽬录结构的规则模式替换
%.o:%.c
@echo $(CC) -o $@ -c $^
clean:
$(RM) -f *.o
make的结果如下,可以看到,我们使⽤的这些技巧,能可以⽅便的帮助我们编写易于维护的Makefile,当项⽬⼯程越来越⼤时,这就显得尤为重要:
有了以上的知识我们开始编写综合实例,当前⽬录下有如下⽂件:
Makefile⽂件如下:
CC := gcc
MKDIR := mkdir
makefile phonyRM := rm -rf
DIR_OBJS := objs
DIR_TARGET := target
DIRS := $(DIR_OBJS) $(DIR_TARGET)
TARGET := $(DIR_TARGET)/main.out
# main.c fun.c
SRCS := $(wildcard *.c)
# main.o fun.o
OBJS := $(SRCS:.c=.o)
#./objs/main.o ./objs/fun.o
OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
.PHONY : rebuild all clean
$(TARGET) : $(DIRS) $(OBJS)
$(CC) -o $@ $(OBJS)
@echo "target file => $@"
$(DIRS):
$(MKDIR) $@
#debug与release版本编译选择
#⽬录结构的规则模式替换,因为.o⽂件在objs⽬录下,所以要加objs路径
$(DIR_OBJS)/%.o:%.c
ifeq ($(DEBUG),true)
$(CC) -o $@ -g -c $^
else
$(CC) -o $@ -c $^
endif
rebuild : clean all
all : $(TARGET)
clean:
$(RM) $(DIRS)
下边分别来编译debug版本与release版本,编译debug版本时在命令⾏后加DEBUG := true即可
编译成功后的⽬录结构如下
可以看到,多出了objs与target两个⽂件夹,⾥边的内容分别为.o⽬标⽂件与.out可执⾏⽂件到此,我们的⼀个⼩⼩的可维护的Makefile综合实例已经完成,更多的内容待后续慢慢完善。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论