news 2026/9/1 4:54:30

Makefile文件---定义变量和引用变量

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Makefile文件---定义变量和引用变量

0 Preface/Forword

0.1 makefile文件定义变量的方法

在Makefile中,定义变量的方法

  • 直接在makefile文件内部定义
  • 在make命令行中定义

1 变量定义

1.1 make命令中定义

在makefile中,通过命令定行定义或修改变量是一种非常灵活且常用的方式,主要用于动态控制构建行为切换编译模式、指定安装路径等)。

1.1.1 语法规则

基本语法

在执行make命令时,直接在命令后添加var_name=value就可以。如果有多个变量,可以用空格分隔。

1.1.2 实例

源码:

var_print: @echo "compiler: ${CC}" @echo "compiler: $(CC)"

运行结果:

cc和gcc

1.1.3 命令行定义命令常用场景

场景命令示例说明
切换编译器make CC=g++临时更换C/C++编译器
开启调试make CFLAGS="-g -O0"添加调试符号,关闭优化
指定安装路径make PREFIX=/usr/local install自动以软件安装路径
选择构建目标make BUILD_TYPE=release all根据变量条件编译不同代码分支

1.2 ?= 定义变量 (Conditional assignment)

在makefile中,通过?=来定义变量的值。

处理规则:赋值前,判断该变量是否已经存在,如果存在,则不重新赋值;如果不存在,则重新赋值。(用于给变量赋默认值

展开方式:与=赋值方式一样,递归展开

以下三种情况?=不会赋值

  • 命令行定义了变量。
  • makefile中前面已经定义了变量
  • 环境变量中已经定义了该变量:比如CC变量。

1.2.1 Example

CC ?= g++ MODE ?= debug var_print: @echo "compiler: $(CC)" @echo "mode: $(MODE)"

运行结果

1.3 := 定义变量 (Simple Expansion)

通过:=方式定义的变量称为简单展开变量(或者称为立即展开变量)。

相关属性如下

  • 规则
    • 立即求值:Make在读取该行时,会立即计算右边表达式的值,并将结果固定下来。
    • 静态值:一旦赋值完成,变量的值就确定了,后续对右侧依赖变量的修改不会影响改变量。
    • 只能引用已经定义过的变量:右侧只能引用在此之前已经定义过的变量,否则值为空。
  • 优点:效率高(只计算一次),行为可预测,避免循环引用问题。
  • 缺点:不能引用后面定义的变量。

1.4 += 定义变量 (Appended)

+=用于向变量的末尾添加内容,常用于累积源文件列表编译标志

具体属性如下所示:

  • 规则
    • 自动空格:make会在原有值和新增值之间自动添加一个空格
    • 继承类型+=的行为取决于该变量之前是如何定义的。
      • 如果变量之前是用=定义的,+=保持递归展开特性。
      • 如果变量之前是用:=定义的,+=保持简单展开特性。(先展开旧值,再追加新值)
      • 如果变量之前未定义,+=等效于=,将其定义为递归展开变量。
  • 典型场景:模块化构建中,不同模块向同一个变量(如SRCSCFLAGS)添加内容。

1.5 = 定义变量 (Recursive Expansion)

makefile中最基本的赋值方式,定义的变量称之为递归展开变量

相关属性如下

  • 规则
    • 延时求值:make在读取该行时不会立即计算右边的值,而是将右边的文本原样保存
    • 使用时展开:只有当该变量在后续被引用($(VAR))时,make才会去展开其中的内容。
    • 引用最新值:展开时,它会使用变量在makefile中最后一次被赋予的值。意味着可以引用在定义之后才赋值的变量。
  • 优点:灵活,允许变量引用未来定义的变量。
  • 缺点:如果存在循环引用(如A=$(B), B=$(A)),会导致无限递归错误;每次引用都重新计算,性能较低。

1.6 变量传递给子make (sub-make)

在一个makefile中调用另一个make命令嵌套make)时;命令行定义的变量会自动传递给子make进程

define_var.mk源码

CC ?= g++ MODE ?= debug var_print: @echo "compiler: $(CC)" @echo "mode: $(MODE)" make -f sub_test.mk

sub_test.mk源码

MODE ?= debug all: @echo "mode: $(MODE)"

运行结果

1.7 override的作用

override标记的变量,不会被命令行中的定义所覆盖。

CC ?= g++ override MODE = debug var_print: @echo "compiler: $(CC)" @echo "mode: $(MODE)" make -f sub_test.mk

1.8 变量定义对比总结

总结表如下所示:

操作符名称求值时机能否引用后定义变量是否覆盖已有值典型用途
=递归赋值使用时(延时✅️能✅️是通用变量定义,灵活性强。
:=简单赋值定义时(立即❌️不能✅️是性能敏感场景,避免副作用(循环引用)。
?=条件赋值使用时(延时✅️能❌️否(若已有值)设置默认值,允许命令行覆盖。
+=追加赋值取决于前文取决于前文❌️追加积累列表(如源文件、标志)

1.9 变量定义最佳实践

定义变量相关建议

  1. 优先使用 :=:除非需要引用后面定义的变量,否则强烈推荐使用 := ,因为它效率更高且行为直观。
  2. 使用 ?= 设置默认值:对于编译器路径、优化级别等配置项,使用 ?= 可以让用户更容易通过命令行自定义。
  3. 使用 += 管理列表:在大型项目中,使用 += 逐步构建源文件列表或编译参数,可以提供makefile的可维护性。
  4. 避免循环引用:使用 = 时要小心不要形成 A=$(B) 和 B=$(A)这样的循环。

2 变量引用

引用变量的两种方法

  • $(VAR)
  • ${VAR}
var_print: @echo "compiler: ${CC}" @echo "compiler: $(CC)"

3 变量优先级

3.1 变量的来源

Make变量的来源只要有四个渠道,优先级从高到底依次为:

  1. 命令行参数(最高优先级):通过命令行make VAR=value传递。
  2. makefile中override定义:使用override VAR=value定义变量。
  3. makefile中普通定义:使用=、:=、?=、+=定义变量。
  4. 环境变量(最低优先级):系统环境中已经存在的变量(除非使用-e选项)
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/1 4:53:34

Excel FILTER函数:动态数组下的数据筛选与查找新范式

这次我们来看一个 Excel 函数领域的“新晋高手”——FILTER 函数。它并非最新发布,但在动态数组功能普及后,其能力被彻底释放,尤其在数据查找与引用方面,展现出了比传统 VLOOKUP 更灵活、更强大的特性。如果你经常被 VLOOKUP 的诸…

作者头像 李华
网站建设 2026/9/1 4:50:46

华为AI岗面试全流程复盘:OD机试、大模型技术面与避坑指南

4月23日上午十点,我坐在酒店书桌前完成了华为AI岗的最后一轮技术面。结束通话那一刻,我第一反应不是放松,而是把刚才面试官追问的几个问题赶紧记到备忘录里——每次面试完趁热复盘,比刷十道题都管用。这一路从投简历、机试到三轮面…

作者头像 李华
网站建设 2026/9/1 4:50:43

基于STC15F104W的学习型433MHz无线遥控解码方案

简介:这套基于STC15F104W单片机的学习型433MHz无线遥控解码方案,面向硬件开发者和电子爱好者,解决多遥控器免配对共用同一接收模块的痛点。方案支持315/433MHz频段,兼容PT2262、EV1527等常见编码芯片,上电自动学习振荡…

作者头像 李华
网站建设 2026/9/1 4:47:40

基于DeepSeek Harness构建LLM Wiki:知识图谱与可溯源问答全解析

前两周一个朋友跟我抱怨:他们团队花了三周做了一个知识库问答系统,对话效果看起来还行,但真放到生产环境就露馅了——文档更新之后,系统还在用旧答案回答;问一个跨文档的问题,回答里只给出一个相似段落&…

作者头像 李华
网站建设 2026/9/1 4:47:28

德国绿牌暖通制造商哪家好

在探讨“德国绿牌暖通制造商哪家好”这个问题时,我们需要明确一个核心事实:德国绿牌(HS Grn) 本身是德国知名的管道品牌,而国内用户熟知的“德国绿牌”产品,是由北京绿牌暖通技术有限公司作为中国区总代理引…

作者头像 李华