Linux工程管理文件Makefile变量类型详解-进阶篇

1.立即变量和延迟变量

在Makefile中最容易让人引困惑的是立即变量和延迟变量。

立即变量和延迟变量是按展开时间来划分的。

立即变量使用 := 操作符进行赋值,在解析阶段就直接展开了,顾名思义,立即展开变量。

延迟变量则是使用 = 操作符进行赋值,在make解析Makefile阶段不会立即展开,而是等到实际使用这个变量时才展开,获得其真正的值。

a = 1
b = 2
val_a := $(a)
val_b  = $(b)
a = 10
b = 20
test:    
	echo $(val_a)    
	echo $(val_b)

在上面的例子中,val_a是立即变量,当make解析到:=赋值符号时,会把(a)变量的值立即赋值给val_a,虽然后面a的值发生了变化,但val_a因为已经展开,所以值就不再发生变化。而val_b则不同,因为是延迟展开变量,所以,当make解析到 = 符号时,并没有立即把(b)的值赋值给val_b,而是在运行echo命令时才对其展开,因为此时b的值已经是20,所以$(val_b)的值也是20

wit@pc:/home/makefile/# makeecho 11echo 2020

立即展开变量一般用在规则中的目标、目标依赖中。make在解析Makefile阶段,需要这些变量有确切的值来构建依赖关系树。

一个项目中的文件依赖关系在程序编译期间是固定不变的,因此需要立即变量在解析阶段就要有明确的值,立即展开。

延迟展开变量一般用在规则的命令行中,这些变量在make编译过程中被引用到才会展开,获得其实际的值。

2.自动变量

在makefile中,大家经常会见到类似@、^、$<这种类型的变量。这种变量一般称为自动变量,自动变量是局部变量,作用域范围在当前的规则内,它们分别代表不同的含义:

  • $@:目标
  • $^:所有目标依赖
  • $<:目标依赖列表中的第一个依赖
  • $?:所有目标依赖中被修改过的文件

有了这些自动变量,我们就可以改进下面的Makefile:

.PHONY: clean
CC  = gcc
BIN = a.out
OBJS = hello.o
OBJS += module.o
$(BIN): $(OBJS)    

@echo "start compiling..."    
@echo $(OBJS)    
	$(CC) -o $(BIN) $(OBJS)    
@echo "compile done"hello.o: hello.c    
	$(CC) -c -o hello.o hello.c
module.o: module.c    
	$(CC) -c -o module.o module.c
clean:    
rm -f $(BIN) $(OBJS)

将这个Makefile中命令行中的目标和目标依赖分别使用@和^代替,Makefile就变成了下面的样子:

.PHONY: clean
CC  = gcc
BIN = a.out
OBJS = hello.o module.o

$(BIN): $(OBJS)    
	@echo "start compiling..."    
	@echo $(OBJS)    
	$(CC) -o $@ $^    
	@echo "compile done"hello.o: hello.c    
	$(CC) -c -o $@ 
	$^module.o: module.c    
	$(CC) -c -o 
	$@ $^
clean:    
	rm -f $(BIN) $(OBJS)

除了上面几个常用的自动变量外,还有一些自动变量不太常用,但是大家在以后阅读Makefile时可能会遇到,比如:

  • %:当规则的目标是一个静态库文件时,%代表静态库的一个成员名
  • +:类似^,但是保留了依赖文件中重复出现的文件
  • \*:在模式匹配和静态模式规则中,代表目标模式中%的部分。比如hello.c,当匹配模式为%.c时,*表示hello
  • $(@D):表示目标文件的目录部分
  • $(@F):表示目标文件的文件名部分
  • $(*D):在模式匹配中,表示目标模式中%的目录部分
  • $(*F):在模式匹配中,表示目标模式中%的文件名部分
  • : :告诉make在编译时忽略所有的错误
  • @: :告诉make在执行命令前不要显示命令

3.环境变量

除了用户自定义的一些变量,make在解析Makefile中还会引入一些系统环境变量,如编译参数CFLAGS、SHELL、MAKE等。这些变量在make开始运行时被载入到Makefile文件中,因为是全局性的系统环境变量,所以这些变量对所有的Makefile都有效。若Makefile中有用户自定义的同名变量,系统环境变量将会被用户自定义的变量覆盖。若用户在命令行中传递跟系统环境变量同名的变量,系统环境变量也会被传递的同名变量覆盖。

.PHONY:all
CFLAGS = -gall:    
@echo "CFLAGS = $(CFLAGS)"    
@echo "SHELL = $(SHELL)"   
@echo "MAKE = $(MAKE)"    
@echo "HOSTNAME = $(HOSTNAME)"

在上面的Makefile中,默认情况下,echo会打印各个系统变量的值:

wit@pc:/home/makefile/demo
# makeCFLAGS = -g
SHELL = /bin/sh
MAKE = make
HOSTNAME =

如果我们在执行make命令时,给Makefile传递一个同名的变量HOSTNAME=zixue.com,系统环境变量就会被这个同名变量覆盖,Makefile实际打印的值就变成了传递的同名变量的值:

wit@pc:/home/makefile/demo# make HOSTNAME=zixue.comCFLAGS = -gSHELL = /bin/shMAKE = makeHOSTNAME = zixue.com

4.变量替换

4.1字符串替换

.PHONY: all
SRC := main.c sub.c
OBJ := $(SRC:.c=.o)all:    
@echo "SRC = $(SRC)"    
@echo "OBJ = $(OBJ)"

执行make命令,运行结果为:

# makeSRC = main.c sub.cOBJ = main.o sub.o

4.2模式匹配替换

使用匹配符%匹配变量,使用 % 保留变量值中的指定字符串,然后其他部分使用指定字符串代替。

.PHONY: all
SRC := main.c sub.c
OBJ := $(SRC:%.c=%.o)all:    
@echo "SRC = $(SRC)"    
@echo "OBJ = $(OBJ)"

执行make命令,运行结果为:

# makeSRC = main.c sub.cOBJ = main.o sub.o
相关推荐
中云DDoS CC防护蔡蔡11 分钟前
微信小程序被攻击怎么选择高防产品
服务器·网络安全·微信小程序·小程序·ddos
HPC_fac130520678161 小时前
以科学计算为切入点:剖析英伟达服务器过热难题
服务器·人工智能·深度学习·机器学习·计算机视觉·数据挖掘·gpu算力
yaoxin5211232 小时前
第二十七章 TCP 客户端 服务器通信 - 连接管理
服务器·网络·tcp/ip
内核程序员kevin2 小时前
TCP Listen 队列详解与优化指南
linux·网络·tcp/ip
sinat_384241096 小时前
使用 npm 安装 Electron 作为开发依赖
服务器
朝九晚五ฺ7 小时前
【Linux探索学习】第十四弹——进程优先级:深入理解操作系统中的进程优先级
linux·运维·学习
自由的dream7 小时前
Linux的桌面
linux
xiaozhiwise7 小时前
Makefile 之 自动化变量
linux
Kkooe8 小时前
GitLab|数据迁移
运维·服务器·git