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
相关推荐
WTT00119 分钟前
2024楚慧杯WP
大数据·运维·网络·安全·web安全·ctf
苹果醋317 分钟前
React源码02 - 基础知识 React API 一览
java·运维·spring boot·mysql·nginx
了一li40 分钟前
Qt中的QProcess与Boost.Interprocess:实现多进程编程
服务器·数据库·qt
日记跟新中1 小时前
Ubuntu20.04 修改root密码
linux·运维·服务器
唐小旭1 小时前
服务器建立-错误:pyenv环境建立后python版本不对
运维·服务器·python
码农君莫笑1 小时前
信管通低代码信息管理系统应用平台
linux·数据库·windows·低代码·c#·.net·visual studio
明 庭1 小时前
Ubuntu下通过Docker部署NGINX服务器
服务器·ubuntu·docker
BUG 4041 小时前
Linux——Shell
linux·运维·服务器
007php0071 小时前
Go语言zero项目部署后启动失败问题分析与解决
java·服务器·网络·python·golang·php·ai编程