makefile 与c语言的学习(三)

(一)使用变量
变量可以使用在“目标”,“依赖目标”,“命令”或者Makefile的其他部分。
变量的名字可以包含字符、数字、下划线,但不能含有“:”、“#”、“=”或是空字符,变量大小写敏感。除了定义的变量还包括自动化变量“$<"、” $@"等
(1)变量在声明时需要给予处置,而在使用时,需要给在变量名前加上“ $";但最好用小括号或者大括号把变量给包括起来。
(2)在makefile中有两种方式在用变量定义变量的值
1、简单的使用“=”,在“=”左侧是变量,右侧是变量的值(右侧变量可以使用后面定义的值)

foo = $(bar)
bar = $(g)
g = hh
echo $(foo)

显示的值是hh
但是这种方式不好的地方在于递归定义,会让make陷入无限的变量展开过程,而且导致两个make的函数“wildcard” 和“shell”发生不可预知错误。

A = $(B)
B = $(A)

2、使用“:="操作符
这种方法前面的变量不能使用后面的变量,只能使用前面已定义好的变量
下面这个例子,包含make的函数、条件表达式和一个系统变量 "MAKELEVEL"的使用

ifeq (0,${MAKELEVEL})
cur-dir := $(shell pwd)
whoami := $(shell whoami)
host-type := $(shell arch)
MAKE :=${MAKE} host-type=${host-type} whoami=${whoami}
endif

对于系统变量”MAKELEVEL",即如果我们的make有一个嵌套执行的动作,那么这个变量会记录当前makefile的调用层数

如果需要定义一个变量,其值是空格

nullstring :=
space := $(nullstring) #end of the line

3、还有一个操作符是“?=“

FOO ?= bar

即如果FOO没有被定义过,那么变量FOO的值就是"bar”,如果FOO先前被定义过,那么这条语句什么也不做。
等价于

ifeq($(origin FOO),undefined)
FOO = bar
endif

(3)变量高级用法
1、变量值的替换,可以替换变量中的共有的部分
“$(var : a=b)"或者用花括号,即将变量“var”中所有以“a”字串结尾的”a“替换成”b”字串;这里的“结尾”->“空格"或者”结束符“

foo : a.o b.o c.o
bar := $(foo:.o=.c)
或者
foo : a.o b.o c.o
bar := $(foo:%.o=%.c)

2、将变量的值再当成变量

x = y
y = z
a := $($(x))

(4)追加变量值
可以使用"+="操作符给变量追加值

objects = main.o foo.o bar.o utils.o
objects += another.o

或者

objects = main.o foo.o bar.o utils.o
objects := $(objects) another.o

(5)override 指示符
如果有变量是通常make的命令行参数设置,那么对这个变量的赋值会被忽略,如果需要在makefile中设置这类参数的值,可以使用override指示符

override <variable> = <value>
override <variable> := <value>

(6)多行命令
可查看(二)中的命令包

(二)使用条件判断
例子:
判断$(CC)变量是否”gcc“,如果是的话,则使用GNU函数编译目标

lib_for_gcc = -lgnu
normal_libs =

foo : $(objects)
ifeq ($(CC),gcc)
	$(CC) -o foo $(objects) $(libs_for_gcc)
else
	$(CC) -o foo $(objects) $(normal_libs)
endif

(三)make的运行
(1)make的退出码
0 - 表示成功执行
1 - 如果make运行时出现任何问题,返回1
2 - 如果使用了make的”-q“选项,并且make 使得一些目标不需要更新,返回2

(2)可以给make命令指定一个特殊名字的makefile
使用make的”-f“或者”–file“参数
例如

make -f hchen.mk

(3)伪目标
1、all
编译所有目标
2、clean
删除所有被make创建的文件
3、install
安装已编译好的程序,就是把目标执行文件拷贝到指定的目标中去
4、print
列出改变过的源文件
5、tar
把源程序打包备份,也就是一个tar文件
6、TAGS
更新所有目标,以备完整地重编译使用
7、check 与 test
这两个伪目标一般用于测试makefile的流程

(四)隐含规则使用的变量
隐含规则中,基本使用了一些预先设置的变量。可以在makefile中改变这些变量的值,或是在make的命令行中传入这些值,或在环境变量中设置这些值。
也可以利用make的“-R"参数来取消你所定义的变量对隐含规则的作用
例如,编译C程序的隐含规则的命令时”$ (CC) -c $(CFLAGS) $(CPPFLAGS)"
make默认编译命令是cc,如果将变量“ $(CC)"重定义成”gcc“,把变量” $(CFLAGS)"重定义成“ -g”,那么,隐含规则中的命令全部会以“gcc -c -g $(CPPFLAGS)"来执行。
(1)关于命令的变量
1、AR
函数库打包程序。默认命令是“ar”。
2、AS
汇编语言编译程序。默认命令是“as”。
3、CC
C 语言编译程序。默认命令是“cc”。
4、CXX
C++语言编译程序。默认命令是“g++”。
5、CO
从 RCS 文件中扩展文件程序。默认命令是“co”。
6、CPP
C 程序的预处理器(输出是标准输出设备)。默认命令是“ $(CC) –E”。
7、RM
删除文件命令。默认命令是“rm –f”。

(2)关于命令参数的变量
如果没有指明其默认值,那么其默认值都是空。
1、ARFLAGS
函数库打包程序 AR 命令的参数。默认值是“rv”。
2、ASFLAGS
汇编语言编译器参数。(当明显地调用“.s”或“.S”文件时)。
3、CFLAGS
C 语言编译器参数。
4、CXXFLAGS
C++语言编译器参数。
5、CPPFLAGS
C 预处理器参数。( C 和 Fortran 编译器也会用到)。
6、LDFLAGS
链接器参数。(如:“ld”)

(五)定义模式规则
(1)模式规则中,至少在规则的目标定义中要包含”%“,”%“表示对文件名的匹配,”%“表示长度任意的非空字符串。例如:”%.c"表示以“.c"结尾的文件名(文件名的长度至少是3),而”s.%.c"则表示以"s.“开头,”.c"结尾的文件名(文件名的长度至少为5)

如果“%”定义在目标中,那么,目标中的“%”的值决定了依赖目标中的“%”的值
例如

%.o : %.c ; <command>

如果要生成的目标是“a.o b.o",那么”%c“就是”a.c b.c"

(2)自动化变量
1、$@
表示规则中的目标文件集。在模式规则中,如果有多个目标,那么," $@“就是匹配于目标中模式定义的集合。
2、 $%
仅当目标是函数库文件中,表示规则中的目标成员名。
3、 $<
依赖目标中的第一个目标名字。如果依赖目标是以模式(即” % “)定义的,那么” $<“将是符合模式的一系列的文件集。注意,其是一个一个取出来的。
4、 $?
所有比目标新的依赖目标的集合。以空格分隔。
5、 $^
所有的依赖目标的集合。以空格分隔。如果在依赖目标中有多个重复的,那个这个变量会去除重复的依赖目标,只保留一份。
6、 $+
这个变量很像” $^",也是所有依赖目标的集合。只是它不去除重复的依赖目标。
7、 $*
这个变量表示目标模式中"%“及其之前的部分。但是,如果目标文件的
后缀是 make 所识别的,那么” $*"就是除了后缀的那一部分。

发布了54 篇原创文章 · 获赞 4 · 访问量 1035

猜你喜欢

转载自blog.csdn.net/buzhiquxiang/article/details/103599165