第八载: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
RM := 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综合实例已经完成,更多的内容待后续慢慢完善。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值