Makefile 中:= ?= += =的区别

本文通过一个简单的实验,详细解释了Makefile中'='、':='、'?='和'+='这四个赋值运算符的区别。包括它们如何在Makefile中操作变量,以及在不同情况下如何改变变量的值。

转自:http://www.cnblogs.com/wanqieddy/archive/2011/09/21/2184257.html

 

在Makefile中我们经常看到 = := ?= +=这几个赋值运算符,那么他们有什么区别呢?我们来做个简单的实验

新建一个Makefile,内容为:
ifdef DEFINE_VRE
    VRE = “Hello World!”
else
endif

ifeq ($(OPT),define)
    VRE ?= “Hello World! First!”
endif

ifeq ($(OPT),add)
    VRE += “Kelly!”
endif

ifeq ($(OPT),recover)
    VRE := “Hello World! Again!”
endif

all:
    @echo $(VRE)

敲入以下make命令:
make DEFINE_VRE=true OPT=define 输出:Hello World!
make DEFINE_VRE=true OPT=add 输出:Hello World! Kelly!
make DEFINE_VRE=true OPT=recover  输出:Hello World! Again!
make DEFINE_VRE= OPT=define 输出:Hello World! First!
make DEFINE_VRE= OPT=add 输出:Kelly!
make DEFINE_VRE= OPT=recover 输出:Hello World! Again!

从上面的结果中我们可以清楚的看到他们的区别了
= 是最基本的赋值
:= 是覆盖之前的值
?= 是如果没有被赋值过就赋予等号后面的值
+= 是添加等号后面的值

 

之前一直纠结makefile中“=”和“:=”的区别到底有什么区别,因为给变量赋值时,两个符号都在使用。网上搜了一下,有人给出了解答,但是本人愚钝,看不懂什么意思。几寻无果之下,也就放下了。今天看一篇博客,无意中发现作者对于这个问题做了很好的解答。解决问题之余不免感叹,有时候给个例子不就清楚了吗?为什么非要说得那么学术呢。^_^

      1、“=”

      make会将整个makefile展开后,再决定变量的值。也就是说,变量的值将会是整个makefile中最后被指定的值。看例子:

            x = foo
            y = $(x) bar
            x = xyz

      在上例中,y的值将会是 xyz bar ,而不是 foo bar 。

      2、“:=”

      “:=”表示变量的值决定于它在makefile中的位置,而不是整个makefile展开后的最终值。

            x := foo
            y := $(x) bar
            x := xyz

      在上例中,y的值将会是 foo bar ,而不是 xyz bar 了。

转载于:https://www.cnblogs.com/x_wukong/p/4716862.html

<think>我们正在讨论Makefile中的赋值操作符。用户明确询问的是`:=`和`?=`的区别。根据引用内容,我们可以总结如下: 1. **`:=` 操作符(立即赋值)** - 特点:在定义变量时立即展开右侧表达式,并赋值给变量。后续对该变量引用的其他变量的修改不会影响已赋值的变量。 - 示例: ```makefile x := a y := $(x) b # 此时y的值是"a b" x := c # 修改x,但y的值不会改变 ``` 输出:`y`的值仍然是`a b`(引用[2][4])。 2. **`?=` 操作符(条件赋值)** - 特点:只有当变量尚未定义时,才进行赋值。如果变量已定义(即使为空),则忽略此次赋值。 - 示例: ```makefile VAR1 = 1234 VAR1 ?= 5678 # 因为VAR1已定义,所以此赋值无效 ``` 输出:`VAR1`的值保持`1234`(引用[2][5])。 3. **关键区别总结** | 特性 | `:=` | `?=` | |--------------|-------------------------------|-------------------------------| | **赋值时机** | 立即展开并赋值 | 仅当变量未定义时赋值 | | **展开方式** | 定义时立即展开右侧表达式 | 若赋值发生,则展开右侧表达式 | | **变量状态** | 覆盖已定义的变量 | 不覆盖已定义的变量 | | **适用场景** | 需要固定当前值的变量 | 提供默认值但不覆盖已有设置 | 4. **综合示例**(结合引用[5]) ```makefile VAR1 = 1234 VAR2 := $(VAR1) # 立即展开:VAR2=1234 VAR1 ?= 5678 # VAR1已定义,跳过 VAR3 ?= 9999 # VAR3未定义,赋值:VAR3=9999 VAR1 = 5678 # 修改VAR1 test: @echo "VAR1=$(VAR1)" # 输出5678 @echo "VAR2=$(VAR2)" # 输出1234(:=赋值不受后续影响) @echo "VAR3=$(VAR3)" # 输出9999 ``` 运行`make test`输出: ``` VAR1=5678 VAR2=1234 VAR3=9999 ``` 5. **注意事项** - `:=`避免递归展开导致的性能问题(如引用[3]中`B=$(A)`的递归问题)。 - `?=`常用于设置默认值,例如: ```makefile CC ?= gcc # 如果用户未指定CC,则使用gcc ``` 用户可通过命令行覆盖:`make CC=clang`(引用[2])。 通过以上对比,可清晰理解两者差异:`:=`关注赋值时的即时值,而`?=`关注变量是否已存在。 §§相关问题§§ 1. Makefile中`=`和`:=`的主要区别是什么? 2. 如何通过命令行覆盖Makefile中`?=`赋值的变量? 3. Makefile中`+=`操作符的作用是什么?</think>### Makefile 赋值操作符 `:=` 和 `?=` 的区别详解 #### 1. **`:=`(立即赋值/静态展开)** - **核心特点**:在定义时**立即展开右侧表达式**,后续变量的修改不影响已赋值的变量[^2][^4]。 - **行为解析**: ```makefile x := a # 定义 x = "a" y := $(x) b # 立即展开:y = "a b" x := c # 修改 x = "c" ``` - 结果:`y` 的值固定为 `"a b"`,不受 `x` 后续修改影响[^4]。 - **适用场景**:需要固定当前变量值的场景(如依赖路径、工具名)。 #### 2. **`?=`(条件赋值)** - **核心特点**:仅当变量**未定义时**才进行赋值,已定义的变量(包括空值)不会被覆盖[^2][^5]。 - **行为解析**: ```makefile VAR1 = 1234 VAR1 ?= 5678 # 无效(VAR1 已定义) VAR2 ?= 9999 # 生效(VAR2 未定义) ``` - 结果:`VAR1` 保持 `1234`,`VAR2` 被赋值为 `9999`[^5]。 - **适用场景**:提供默认值但不覆盖用户自定义值(如编译器选择)。 #### 3. **关键区别对比** | 特性 | `:=` | `?=` | |--------------|-------------------------------|-------------------------------| | **赋值时机** | 定义时立即展开右侧表达式 | 仅当变量未定义时赋值 | | **值更新** | 后续变量修改不影响已赋值结果 | 不覆盖已定义的变量 | | **空值处理** | 空值也会被赋值 | 空值视为已定义,不赋值 | | **典型用途** | 固定路径、工具名等静态值 | 提供默认配置(可被命令行覆盖)| #### 4. **综合示例演示** ```makefile # 定义变量 TOOL := gcc # 立即固定为 "gcc" OPTIMIZE ?= -O2 # 默认优化等级 # 修改尝试 TOOL := clang # 覆盖 TOOL OPTIMIZE ?= -O0 # 无效(OPTIMIZE 已定义) test: @echo "TOOL: $(TOOL)" # 输出 clang @echo "OPTIMIZE: $(OPTIMIZE)" # 输出 -O2 ``` - 运行 `make test` 输出: ``` TOOL: clang OPTIMIZE: -O2 ``` - **说明**:`?=` 的默认值 `-O2` 被保留,而 `:=` 的 `gcc` 被后续赋值覆盖[^4][^5]。 #### 5. **使用建议** - **优先 `:=`**:当需要固定变量值(如工具链路径)时使用,避免递归展开的性能开销[^3]。 - **优先 `?=`**:为可配置项提供默认值(如 `CC ?= gcc`),允许用户通过命令行覆盖: ```bash make OPTIMIZE=-O0 # 覆盖默认值 -O2 ``` #### 6. **与其他操作符对比** - **与 `=` 的区别**:`=` 是递归展开(使用时才求值),而 `:=` 是立即展开[^1][^3]。 - **与 `+=` 的区别**:`+=` 是追加操作,不影响赋值逻辑[^2]。 > 通过合理选择赋值操作符,可显著提升 Makefile 的可维护性和灵活性。例如:用 `:=` 确保关键路径不变,用 `?=` 支持用户自定义配置[^2][^5]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值