makefile中函数定义及调用

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/lms1008611/article/details/85200983

    在Makefile中,是支持函数使用的,Makefile中的函数包括make解释器自身预定义的函数,同时也支持我们自己定义函数。

在Makefile中, 通过define关键字来实现函数的自定义,并以endef关键字结束,自定义函数使用预定义函数call调用,后边跟自定义函数名及参数,如下就是一个简单的自定义函数:


 
 
  1. .PHONY : test
  2. define fun1
  3. @ echo "My name is $(0)"
  4. endef
  5. define fun2
  6. @ echo "My name is $(0), param is $(1)"
  7. endef
  8. test:
  9. $(call fun1)
  10. $(call fun2, hello Makefile)

上边我们首先定义了一个伪目标test,接着定义了两个函数,fun1和fun2。fun1中直接通过$(0)输出call 的第一个参数,也就是函数名fun1,fun2中同时输出了第二个参数(这看起来有点 类似C语言里的main函数参数)。 在调用自定义函数fun1和fun2时,格式为$(call 函数名,参数...),call函数的参数需要以逗号","隔开,下边 执行如下:

    除了可以自定义函数外,make解释器还提供了众多预定的函数供我们使用,比方abspath(取文件的绝对路径)


 
 
  1. .PHONY : test2
  2. var := $(abspath ./)
  3. test2 :
  4. @ 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点技巧,我们以一个简单的实例来展示:


 
 
  1. .PHONY : all clean
  2. CC := gcc
  3. SRCS := $(wildcard *.c)
  4. OBJS := $(SRCS:.c=.o)
  5. OBJSPATH := $(addprefix path/, $(OBJS))
  6. all: $(OBJS)
  7. @ echo "SRCS => $(SRCS)"
  8. @ echo "OBJS => $(OBJS)"
  9. @ echo "OBJSPATH => $(OBJSPATH)"
  10. #变量中的规则模式替换
  11. #$(OBJS):%.o:%.c
  12. # @echo $(CC) -o $@ -c $^
  13. #目录结构的规则模式替换
  14. %.o:%.c
  15. @ echo $(CC) -o $@ -c $^
  16. clean:
  17. $(RM) -f *.o

make的结果如下,可以看到,我们使用的这些技巧,能可以方便的帮助我们编写易于维护的Makefile,当项目工程越来越大时,这就显得尤为重要:

有了以上的知识我们开始编写综合实例,当前目录下有如下文件:

Makefile文件如下:


 
 
  1. CC := gcc
  2. MKDIR := mkdir
  3. RM := rm -rf
  4. DIR_OBJS := objs
  5. DIR_TARGET := target
  6. DIRS := $(DIR_OBJS) $(DIR_TARGET)
  7. TARGET := $(DIR_TARGET)/main.out
  8. # main.c fun.c
  9. SRCS := $(wildcard *.c)
  10. # main.o fun.o
  11. OBJS := $(SRCS:.c=.o)
  12. #./objs/main.o ./objs/fun.o
  13. OBJS := $(addprefix $(DIR_OBJS)/, $(OBJS))
  14. .PHONY : rebuild all clean
  15. $(TARGET) : $(DIRS) $(OBJS)
  16. $(CC) -o $@ $(OBJS)
  17. @ echo "target file => $@"
  18. $(DIRS):
  19. $(MKDIR) $@
  20. #debug与release版本编译选择
  21. #目录结构的规则模式替换,因为.o文件在objs目录下,所以要加objs路径
  22. $(DIR_OBJS)/%.o:%.c
  23. ifeq ($(DEBUG), true)
  24. $(CC) -o $@ -g -c $^
  25. else
  26. $(CC) -o $@ -c $^
  27. endif
  28. rebuild : clean all
  29. all : $(TARGET)
  30. clean:
  31. $(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、付费专栏及课程。

余额充值