GNU Make中环境变量与宏的交互规则及优先级问题咨询
GNU Make 变量优先级规则及场景解释
核心优先级规则(默认无特殊参数时,优先级从高到低)
- Makefile 中带
override修饰的赋值:优先级最高,会覆盖所有其他来源的变量值 - 执行 make 时命令行直接传入的变量(格式为
make VAR=value):默认会忽略 Makefile 中对该变量的普通赋值 - Makefile 中的普通赋值(
=/:=/?=无override修饰) - Shell 环境变量:make 启动时会导入所有环境变量作为自身变量,但如果 Makefile 中对同名变量做了普通赋值,会覆盖环境变量的值
- Make 内置的默认变量(比如默认的
CC=cc、CFLAGS=-O2这类)
第一种Makefile的执行差异原因
对应Makefile代码:
# 使用:=避免宏展开出现无限递归 CFLAGS := -g -O2 $(CFLAGS) hello: src/hello.c cc $(CFLAGS) -o $@ $<
执行CFLAGS=-pipe make hello的结果说明
这种写法是将CFLAGS=-pipe设置为Shell环境变量传递给make进程:
- make启动时先导入环境变量,此时变量空间中
CFLAGS=-pipe - 解析到Makefile中
CFLAGS := -g -O2 $(CFLAGS)这行赋值时,:=是立即展开运算符,会先解析右侧的$(CFLAGS)拿到当前已有的值-pipe - 最终赋值后
CFLAGS=-g -O2 -pipe,所以编译命令为cc -g -O2 -pipe -o hello src/hello.c
执行make CFLAGS=-pipe hello的结果说明
这种写法是将CFLAGS=-pipe作为命令行参数传递给make:
- 按照优先级规则,命令行传入的变量优先级高于Makefile普通赋值,所以Makefile中
CFLAGS := ...这行普通赋值会被直接忽略 - 最终
CFLAGS=-pipe,所以编译命令为cc -pipe -o hello src/hello.c
第二种Makefile的结果说明
对应修改后的Makefile代码:
CFLAGS ?= -g -O2 $(CFLAGS) hello: src/hello.c cc $(CFLAGS) -o $@ $<
?=是缺省赋值运算符,逻辑为:仅当变量当前未被定义时,才执行右侧的赋值操作,否则直接跳过。
两种执行场景的逻辑分别为:
- 执行
CFLAGS=-pipe make hello:make启动时已经从环境变量导入了CFLAGS,变量已被定义,?=赋值直接跳过,最终CFLAGS=-pipe - 执行
make CFLAGS=-pipe hello:命令行已经传入了CFLAGS的定义,?=赋值直接跳过,最终CFLAGS=-pipe
所以两种场景下编译命令都为cc -pipe -o hello src/hello.c
内容的提问来源于stack exchange,提问作者shadowtalker
相关产品推荐
相关产品推荐

