OOP-THU icon indicating copy to clipboard operation
OOP-THU copied to clipboard

Makefile的通配符与变量的使用

Open ZhangZhiyuan-2021 opened this issue 2 years ago • 1 comments

Makefile通配符与变量的使用

Makefile在我们上课时详细介绍,他为我们提供了“自动编译”的功能,只需要简短的命令,就能将整个工程文件重新编译,极大的降低了工程修改的成本,并提高了软件开发的效率。这里我们介绍一些Makefile的较高级用法。


Makefile的通配符

Makefile支持使用shell命令,因此在Makefile中可以直接使用shell所支持的一些通配符,如*%?[……]等。

与正则表达式极其类似,其中,*%表达匹配任意个字符,?表示匹配任意一个字符,[……]表示将指定需要匹配的内容放入[]中。

例如:

test:*.cpp
	g++ -o $@ $^
clean:
	rm -rf *.o test

在以上代码中,我们看到,*既可以用在规则中,也可以用在规则的命令中,此处即表示任意的以.cpp或.o结尾的文件。


需要特别指出的是,%*作用极其类似,但%将我们需要的所有文件组合成为一个列表,从列表中依次取出的每一个文件,%即为取出文件的文件名。

例如:

test:*.o
	g++ -o $@ $^
%.o:%.cpp
	g++ -c $< -o $@

这段代码即表示依次取出%.cpp文件。执行命令直至列表中文件为空。

这就是Makefile中的静态模规则:规则存在多个目标,并且不同的目标可以根据目标文件的名字来自动构造出依赖文件。


Makefile的变量

Makefile中定义变量的语法为:变量名称=值列表,等号左右对于空白符无要求,值列表可以是任意项,并且不需要使用数据类型。

在调用变量的时候可以使用$(VALUE_LIST){VALUE_LIST}

而使用变量的优点在于,当我们需要添加或者是删除某个依赖文件的时候,我们只需要改变变量的值即可。

例如:

TEST = main.o test1.o test2.o test3.o
test:$(TEST)
	g++ -o test $(TEST)

而变量赋值的基本方法有四种,分别是:

  • 简单赋值 ( := ) :类比为c++中的普通赋值,只改变该变量。
  • 递归赋值 ( = ) :类比为c++中的引用,赋值语句可能改变多个变量。
  • 条件赋值 ( ?= ) 如果变量未定义,则使用符号中的值定义变量。如果该变量已经赋值,则该赋值语句无效。
  • 追加赋值 ( += ) 将原变量用空格隔开的方式追加一个新值。

例如:

#简单赋值
a:=friend
b:=$(b)s
a:=guy
#递归赋值
c=friend
d=$(d)s
c=guy
#条件赋值
e:=friend
f:=$(e)s
e?=guy
#追加赋值
g:=friend
h:=$(g)s
g+=$(h)
#输出检验结果
test:
      @echo "a=>$(a)"
      @echo "b=>$(b)"
      @echo "c=>$(c)"
      @echo "d=>$(d)"
      @echo "e=>$(e)"
      @echo "f=>$(f)"
      @echo "g=>$(g)"
      @echo "h=>$(h)"

在命令行执行make test,则有:

a=>friend
b=>friends
#在给b赋值的引用了变量a:$(a)
c=>guy
d=>guys
#随着c变化,采取递归赋值的d跟随变化
e=>friend
f=>friends
#e已经有值,因此条件赋值未生效
g=>friend
h=>friend friends
#在h=friend后追加空格以及变量g=friends

自动变量

在我们介绍通配符的时候,使用了符号$@$^等,这些符号即为自动变量,它们具有很好的便捷性,如果能良好的使用,会极大地缩减我们的代码量。其中:

  • $@表示目标文件的名称;
  • $^表示的是所有依赖文件的列表,使用空格进行分隔;
  • $<表示第一个依赖的文件名称;
  • $?表示所有比目标文件更新的依赖文件的列表,使用空格进行分隔;
  • $%表示静态库的一个成员名;
  • $+$^类似,但$^只记录依赖文件第一次引用的情况,会去掉重复的依赖文件,而$+会保留所有依赖文件中重复出现的文件,可以用于库的引用出现交叉时的情况。

让我们回到刚才的例子:

test:*.cpp
	g++ -o $@ $^
clean:
	rm -rf *.o test

其中$@表示目标文件的名称,在此处被用作命名值,而$^表示所有依赖文件,代表将所有文件统一链接。

test:*.o
	g++ -o $@ $^
%.o:%.cpp
	g++ -c $< -o $@

这段代码的test指令与刚才相同,而第二个指令中,$^表示依赖文件中的第一个,$@代表目标文件,这个指令就是将所有的%.cpp文件编译成为%.o文件。

ZhangZhiyuan-2021 avatar Jun 16 '22 08:06 ZhangZhiyuan-2021

OK

Yu-Shi avatar Jul 04 '22 14:07 Yu-Shi