跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Shell / Bash

Makefile 核心机制与最佳实践

Makefile 作为构建自动化核心工具,其命名规范、文件包含及重建机制直接影响项目维护效率。深入解析 GNU Make 两阶段执行流程,阐明变量立即展开与延后展开的差异,对比 include 与 -include 的使用场景。通过梳理依赖关系链表构建与终极目标执行逻辑,帮助开发者规避常见陷阱,编写更稳健的构建脚本。

DebugKing发布于 2017/1/2更新于 2026/9/867 浏览
Makefile 核心机制与最佳实践

Makefile 文件命名规范

通常情况下,make 会在工作目录(执行 make 的目录)下按特定顺序查找并读取 Makefile 文件。默认查找顺序为:

  1. GNUmakefile
  2. makefile
  3. Makefile

建议优先使用 Makefile(首字母大写),这样在目录中与 README、ChangeLog 等重要文件并列时更显眼,便于发现。不推荐使用 GNUmakefile,因为它仅被 GNU make 识别,其他版本的 make 程序可能无法自动加载。

如果文件名不符合上述标准,可通过 -f 或 --file 选项显式指定。例如:

-f NAME

也可以多次使用该选项指定多个 Makefile 文件,它们将按顺序链接并被解析。一旦通过选项指定了文件,make 将不再自动搜索默认的三个标准文件名。

包含其他 Makefile 文件

若需在 Makefile 中引入外部文件,可使用 include 指示符,用法类似 C 语言的头文件包含。

include FILENAMES...

该指示符会让 make 暂停当前文件的读取,转而去加载指定的文件,完成后继续后续内容。例如存在 a.mk、b.mk、c.mk 三个文件,且变量 $(bar) 展开为 bish bash:

include foo *.mk $(bar)

等价于:

include foo a.mk b.mk c.mk bish bash

include 通常用于以下场景:

  • 通用规则复用:多个程序由不同目录下的独立 Makefile 描述,但共享一组变量定义或模式规则。将这些公共部分提取到单独文件中,主 Makefile 通过 include 引入即可。
  • 依赖关系管理:源文件自动生成的依赖关系可保存至独立文件,主 Makefile 直接包含。相比在主文件中追加依赖,这种方式更清晰且符合现代 make 的处理习惯。

若 include 指定的文件不是绝对路径且当前目录不存在,make 会依次在 -I 选项指定的目录及 /usr/gnu/include、/usr/local/include、/usr/include 中查找。若仍未找到,make 会发出警告但不会立即退出,而是尝试根据规则创建该文件;若无法创建则报错退出。

为避免因文件缺失导致的构建中断,建议使用 -include 替代 include。前缀 - 告诉 make 忽略错误并继续执行:

-include FILENAMES...

Makefile 的重建机制

Makefile 本身也可由其他文件生成(如 RCS 或 SCCS 文件)。当 make 开始解析时,如果发现 Makefile 需要更新,它会先重新读取更新后的版本。

具体流程如下:

  1. make 读入所有 Makefile 文件后,将其视为目标寻找更新规则。
  • 若存在明确或隐含规则可更新某个 Makefile,则执行更新。
  • 若任何已读取的 Makefile 被更新,make 会清除状态重新读取一遍所有文件。
  • 再次读取后,由于时间戳已是最新,通常不会再触发重建,随后开始解析和执行动作。
  • 实际开发中我们通常手动维护 Makefile,无需自动重建。但 make 每次执行仍会尝试查找重建规则。出于效率考虑,可显式定义一个以 Makefile 为目标且命令为空的规则,从而避免不必要的检查。

    Make 解析流程详解

    GNU make 的执行分为两个阶段,理解这一点对掌握变量和函数展开至关重要。

    第一阶段:读取与构建

    读取所有 Makefile 文件(包括 MAKEFILES 变量、include 指示符及 -f 选项指定的文件),内建变量、明确规则和隐含规则,建立目标与依赖之间的链表结构。

    第二阶段:决策与执行

    根据第一阶段建立的依赖链表,决定哪些目标需要更新,并使用对应规则进行重建。

    在此过程中,变量和函数的展开时机分为'立即'和'延后'两种:

    • 立即展开:在第一阶段发生。例如简单变量赋值 = 在某些情况下,或条件语句分支的判定。
    • 延后展开:直到规则使用时或第二阶段才展开。例如规则命令行中的变量引用。
    变量取值规则
    定义方式展开时机
    IMMEDIATE = DEFERRED立即
    IMMEDIATE ?= DEFERRED立即
    IMMEDIATE := IMMEDIATE立即
    define IMMEDIATE ... endef立即
    += (追加)视原变量类型而定

    若此前变量是简单变量(使用 := 定义),追加 += 时视为立即展开;否则通常为延后展开。

    条件语句

    所有条件分支(ifdef、ifeq、ifndef、ifneq)的展开均为'立即'的,make 会根据预设条件选择正确的分支。

    规则定义

    规则展开遵循以下模式:

    IMMEDIATE : IMMEDIATE ; DEFERRED
    DEFERRED
    

    目标和依赖中的变量引用会被立即展开,而规则命令行中的变量引用会被延后展开。此模式适用于明确规则、模式规则、后缀规则及静态模式规则。

    执行流程总结

    综合来看,make 的执行逻辑可概括为以下步骤:

    1. 依次读取 MAKEFILES 变量定义的 Makefile 列表。
    2. 读取工作目录下符合命名顺序的文件(GNUmakefile > makefile > Makefile)。
    3. 依次读取 Makefile 中 include 包含的文件。
    4. 查找重建所有已读取 Makefile 的规则,若存在则重建并从第一步重新开始。
    5. 初始化变量值,展开需立即展开的变量和函数,确定条件分支。
    6. 根据终极目标及其他目标的依赖关系建立依赖链表。
    7. 执行除终极目标外的所有目标规则(若依赖文件时间戳较新则重建)。
    8. 执行终极目标所在的规则。

    目录

    1. Makefile 文件命名规范
    2. 包含其他 Makefile 文件
    3. Makefile 的重建机制
    4. Make 解析流程详解
    5. 第一阶段:读取与构建
    6. 第二阶段:决策与执行
    7. 变量取值规则
    8. 条件语句
    9. 规则定义
    10. 执行流程总结

    更多推荐文章

    查看全部
    • 卷积神经网络 CNN 经典架构解析与 PyTorch 实战
    • LFM2-1.2B:面向边缘设备的混合模型整理
    • GitHub Copilot 免费版与专业版功能对比及使用指南
    • 数据结构:图的定义、存储与遍历应用
    • 清华团队发布 OpenClaw 研究报告:AI 智能体生态闭环解析
    • AI 工具前端提示词实战:从设计原则到工程化落地
    • 算法实战:Z 字形变换与外观数列模拟解法
    • 主流前端技术栈、框架与组件库生态选型指南
    • C++26 std::future 原生支持超时机制,优化异步任务管理
    • 鸿蒙 Share Kit 目标应用开发指南:UIAbility 与扩展能力接入实战
    • 基于机器学习的 Web 入侵检测系统设计与实现
    • 电商系统商品管理模块设计与实现
    • OpenClaw 集成飞书机器人部署指南
    • Web 自动化测试入门:从概念到百度搜索实战
    • 单卡 RTX 3090 实现 LLaMA-3 8B 低比特量化全参微调
    • ESP32 语音对话机器人:Coze 大模型与百度千帆集成实战
    • OpenClaw 在 Linux 环境下的安装、初始化与 Web UI 配置
    • 资深安全工程师推荐的9本黑客技术经典书籍
    • HDFS 编程实践:Shell 命令、Web 界面与 Java API 详解
    • RabbitMQ 入门:架构解析、环境搭建与 Java 实战

    相关免费在线工具

    • Base64 字符串编码/解码

      将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

    • Base64 文件转换器

      将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

    • Markdown转HTML

      将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

    • HTML转Markdown

      将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

    • JSON 压缩

      通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

    • JSON美化和格式化

      将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online