从头开始写项目Makefile(三):变量的使用

【版权声明:转载请保留出处:blog.csdn.net/gentleliu。Mail:shallnew at 163 dot com】

仔细研究我们的之前Makefile发现,我们还有改进的地方,就是此处:

target_bin : main.o debug.o ipc.o timer.o tools.o
>---gcc -o target_bin main.o debug.o ipc.o timer.o tools.o

如果增加一个源文件xx.c的话,需要在两处或多处增加xx.o文件。我们可以使用变量来解决这个问题。之前说过,Makefile的变量就像C语言的宏一样,使用时在其位置上直接展开。变量在声明时赋予初值,在引用变量时需要给在变量名前加上“$”符号,但最好用小括号“()”或是大括号“{}”把变量给包括起来。

默认目标target_bin也在多处出现了,该文件也可以使用变量代替。

修改我们的Makefile如下:

SRC_OBJ = main.o debug.o ipc.o timer.o tools.o
SRC_BIN = target_bin
$(SRC_BIN) : $(SRC_OBJ)
>---gcc -o $(SRC_BIN) $(SRC_OBJ)

clean:
>---rm $(SRC_OBJ) $(SRC_BIN)

这样每次有新增的文件是只需要在SRC_OBJ变量里面增加一个文件即可。要修改最终目标的名字是可以只修改变量SRC_BIN。

其实在之前还说过特殊变量:

$@,表示规则中的目标。

$<,表示规则中的第一个依赖文件。

$?,表示规则中所有比目标新的条件,组成一个列表,以空格分隔。

$^,表示规则中的所有条件,组成一个列表,以空格分隔。

上一节我们看到make -p有很多自定义的变量,比如CC。其中很多变量我们可以直接使用或修改其变量值或增加值。我们的Makefile中可以使用CC(默认值为cc)、RM(默认值为rm -f)。

 

由此可见我们的Makefile还可以进一步修改:

 

SRC_OBJ = main.o debug.o ipc.o timer.o tools.o
SRC_BIN = target_bin
$(SRC_BIN) : $(SRC_OBJ)
>---$(CC) -o $@ $^                                                                                                                                                                         
 
clean:
>---$(RM) $(SRC_OBJ) $(SRC_BIN)
这样的Makefile编译也是可用的。

但是这样的Makefile还是需要我们手动添加文件,还是不够自动化,最好增删文件都要修改Makefile。伟大的人类真是太懒了!!于是乎,他们发明了一个函数wilcard(函数后面会讲到),它可以用来获取指定目录下的所有的.c文件列表。这样的话我们可以自动获取当前目录下所有.c源文件,然后通过其他方法再得到.o文件列表,这样的话就不需要在每次增删文件时去修改Makefile了。所谓其他方法这里给出两种:

1.     使用patsubst函数。在$(patsubst %.c,%.o,$(dir) )中,patsubst把$(dir)中的变量符合后缀是.c的全部替换成.o。

2.     变量值的替换。 我们可以替换变量中的共有的部分,其格式是“$(var:a=b)”或“${var:a=b}”,其意思是,把变量“var”中所有以“a”字串“结尾”的“a”替换成“b”字串。

 

修改后的Makefile如下:

 
# SRC_OBJ = $(patsubst %.c, %.o, $(wildcard *.c))                                                                                                                                        

SRC = $(wildcard *.c)
SRC_OBJ = $(SRC:.c=.o)
SRC_BIN = target_bin
 
$(SRC_BIN) : $(SRC_OBJ)
>---$(CC) -o $@ $^
 
clean:
>---$(RM) $(SRC_OBJ) $(SRC_BIN)
其中# 后面的内容为注释。

这样终于满足了那些懒人的想法了。可见在使用变量时,的确可以是编译变得更自动化。

 

其实变量的定义有三种运算符=、:=、?=、+=。

1.     =运算符可以读取到后面定义的变量。比如:

VAR = $(VAR2)
VAR2 = hello_make
 
all:
>---@echo =====$(VAR)=====

运行结果为:

#
=====hello_make=====
#

但是这种定义可能会导致并非我们意愿的事发生,并不是很符合C语言的编程习惯。

2.     :=运算符在遇到变量定义时立即展开。

VAR := $(VAR2)                                                                                                                                                                                        
VAR2 = hello_make
 
all:
>---@echo =====$(VAR)=====
运行结果为:
#
==========
#

3.     ?=运算符在复制之前先做判断变量是否已经存在。例如var1 ?= $(var2)的意思是:如果var1没有定义过,那么?=相当于=,如果var1先前已经定义了,则什么也不做,不会给var重新赋值。

4.     +=运算符是给变了追加值。如果变量还没有定义过就直接用+=赋值,那么+=相当于=

 

如何使用这几个运算符要看实际情况,有时一个大的工程可能有许多Makefile组成,变量可能在多个Makefile中都在使用,这时可能使用+=比较好。使用:=有时可能比要好。

有时在编译程序时,我们需要编译器给出警告,或加入调试信息,或告知编译器优化可执行文件。编译时C编译器的选项CFLAGS使用的较多,默认没有提供值,我们可以给该变量赋值。有时我们还需要使用链接器选项LFLAGS告诉链接器链接时需要的库文件。可能我们还需要给出包含头文件的路径,因为头文件很可能和源文件不再同一目录。所以,我们今天的Makefile加上部分注释又更新了:

# A commonMakefile for c programs, version 1.0
# Copyright (C)2014 shallnew \at 163 \dot com
 
CFLAGS += -g -Wall-Werror -O2
CPPFLAGS += -I.-I./inc                                                                                                                                                                  
LDFLAGS +=-lpthread
 
# SRC_OBJ =$(patsubst %.c, %.o, $(wildcard *.c))
SRC_FILES =$(wildcard *.c)
SRC_OBJ =$(SRC_FILES:.c=.o)
SRC_BIN =target_bin
 
$(SRC_BIN) :$(SRC_OBJ)
>---$(CC) -o $@$^ $(LDFLAGS)
 
clean:
>---$(RM)$(SRC_OBJ) $(SRC_BIN)

编译:
# make
cc -g -Wall-Werror -O2 -I. -I./inc  -c -o debug.odebug.c
cc -g -Wall-Werror -O2 -I. -I./inc  -c -o ipc.oipc.c
cc -g -Wall-Werror -O2 -I. -I./inc  -c -o main.omain.c
cc -g -Wall-Werror -O2 -I. -I./inc  -c -o timer.otimer.c
cc -g -Wall-Werror -O2 -I. -I./inc  -c -o tools.otools.c
cc -o target_bindebug.o ipc.o main.o timer.o tools.o -lpthread
#

可见我们的预编译选项,编译选项都用到了,之前我们说过make的使用隐含规则自动推导:

COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) –c

其中变量CFLAGS 和 CPPFLAGS均是我们给出的,变量$(TARGET_ARCH)未给,所以在编译输出可以看到-c前面有2个空,最早未给变量是有四个空。

目前给出的Makefile基本上可以适用于那些源代码全部在同一目录下的简单项目,并且基本上在增删文件时不需要再去手动修改Makefile代码。在新的一个项目只需要把该Makefile拷贝到源代码目录下,再修改一下你需要编译的可执行文件名称以及你需要的编译连接选项即可。

后面章节将会讲到如何写多目录源代码工程下的Makefile。

最后,今天的最终Makefile是这样的:

# A commonMakefile for c programs, version 1.0
# Copyright (C)2014 shallnew \at 163 \dot com
 
CFLAGS += -g -Wall-Werror -O2
CPPFLAGS += -I.-I./inc                                                                                                                                                                  
LDFLAGS +=-lpthread
 
# SRC_OBJ =$(patsubst %.c, %.o, $(wildcard *.c))
SRC_FILES =$(wildcard *.c)
SRC_OBJ =$(SRC_FILES:.c=.o)
SRC_BIN =target_bin
 
$(SRC_BIN) :$(SRC_OBJ)
>---$(CC) -o $@$^ $(LDFLAGS)
 
clean:
>---$(RM)$(SRC_OBJ) $(SRC_BIN)

  • 7
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
跟我一起 Makefile 作者:陈皓 整理:祝冬华 来源网络,希望能与大家分享这份学习资料,资源分数也设置了最低值,如有侵权,请联系我删除文件。 第一部分、概述 (6) 第二部分、关于程序的编译和链接 (6) 第部分、Makefile 介绍 (7) 一、Makefile的规则 (7) 二、一个示例 (8) 、make是如何工作的 (9) 四、makefile使用变量 (10) 五、让make自动推导 (11) 六、另类风格的makefile (12) 七、清空目标文件的规则 (13) 第四部分、Makefile 总述 (13) 一、Makefile里有什么? (13) 1、显式规则。 (14) 2、隐晦规则。 (14) 3、变量的定义。 (14) 4、文件指示。 (14) 5、注释。 (14) 二、Makefile的文件名 (15) 、引用其它的Makefile (15) 四、环境变量 MAKEFILES (16) 五、make的工作方式 (16) 第五部分、书规则 (17) 一、规则举例 (17) 二、规则的语法 (17) 、在规则中使用通配符 (18) 四、文件搜寻 (19) 五、伪目标 (20) 六、多目标 (22) 七、静态模式 (22) 八、自动生成依赖性 (24) 第六部分书命令 (25) 一、显示命令 (26) 二、命令执行 (26) 、命令出错 (27) 四、嵌套执行make (28) 五、定义命令包 (30) 第七部分使用变量 (30) 一、变量的基础 (31) 二、变量中的变量 (32) 变量高级用法 (34) 四、追加变量值 (37) 五、override 指示符 (37) 六、多行变量 (38) 八、目标变量 (39) 九、模式变量 (40) 第八部分使用条件判断 (40) 一、示例 (40) 二、语法 (42) 第九部分使用函数 (43) 一、函数的调用语法 (44) 二、字符串处理函数 (44) 1、subst (44) 2、patsubst (45) 3、strip (45) 4、findstring (46) 5、filter (46) 6、filter-out (46) 7、sort (47) 8、word (47) 9、wordlist (47) 10、words (47) 11、firstword (48) 12、字符串函数实例 (48) 、文件名操作函数 (48) 1、dir (48) 2、notdir (48) 3、suffix (49) 4、basename (49) 5、addsuffix (49) 6、addprefix (49) 7、join (50) 四、foreach 函数 (50) 五、if 函数 (50) 六、call函数 (51) 七、origin函数 (51) “undefined” (52) “default” (52) “file” (52) “command line” (52) “override” (52) “automatic” (52) 八、shell函数 (53) 九、控制make的函数 (53) 1、error (53) 2、warning (54) 第十部分 make 的运行 (54) 二、指定Makefile (54) 、指定目标 (55) “all” (56) “clean” (56) “install” (56) “print” (56) “tar” (56) “dist” (56) “TAGS” (56) “check”和“test” (56) 四、检查规则 (57) 五、make的参数 (57) 第十一部分隐含规则 (61) 一、使用隐含规则 (61) 二、隐含规则一览 (62) 1、编译C程序的隐含规则 (63) 2、编译C++程序的隐含规则 (63) 3、编译Pascal程序的隐含规则 (63) 4、编译Fortran/Ratfor程序的隐含规则 (63) 5、预处理Fortran/Ratfor程序的隐含规则 (63) 6、编译Modula-2程序的隐含规则 (63) 7、汇编和汇编预处理的隐含规则 (64) 8、链接Object文件的隐含规则 (64) 9、Yacc C程序时的隐含规则 (64) 10、Lex C程序时的隐含规则 (64) 11、Lex Ratfor程序时的隐含规则 (65) 12、从C程序、Yacc文件或Lex文件创建Lint库的隐含规则 (65) 、隐含规则使用变量 (65) 1、关于命令的变量。 (65) 2、关于命令参数的变量 (66) 四、隐含规则链 (67) 五、定义模式规则 (68) 1、模式规则介绍 (68) 2、模式

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值