Makefile 中 : 和 :: 的使用指南
1. 概述
在 Makefile 中,:(单冒号)和 ::(双冒号)都用于定义目标(target),但它们的行为存在关键区别。理解它们的用法可以帮助我们更好地组织 Makefile,提高可维护性和灵活性。
2. :(单冒号)与 ::(双冒号)的区别
| 语法 | 行为 |
|---|---|
:(单冒号) | 定义唯一规则,如果同一目标出现多次,后面的规则会覆盖前面的规则 |
::(双冒号) | 定义多个独立规则,同一目标可以有多个规则,所有规则都会被执行 |
3. :(单冒号)的用法
3.1 基本示例
all: build
@echo "Running build"
all: test
@echo "Running test"
执行 make all 结果:
Running test
解释:
all:目标被定义了两次。- 后面的
all: test覆盖 了前面的all: build,因此只执行test相关的命令。
3.2 依赖的覆盖
all: build
test:
@echo "Testing..."
all: test # 覆盖前面的规则
执行 make all 结果:
Testing...
解释:
all: build先定义了build依赖。all: test覆盖了前面的all: build,最终all只依赖test。
适用场景:
- 适用于单一规则的目标,如
CC = gcc这类变量定义。 - 确保不执行重复规则,仅保留最后一次的定义。
4. ::(双冒号)的用法
4.1 基本示例
all:: build
@echo "Running build"
all:: test
@echo "Running test"
执行 make all 结果:
Running build
Running test
解释:
all::目标被定义了两次,但不会相互覆盖。make all会依次执行所有all::规则。
4.2 组合依赖
test:: unit-test
t@echo "Integration testing..."
test:: integration-test
t@echo "Unit testing..."
执行 make test 结果:
Integration testing...
Unit testing...
解释:
test::目标多次定义,每个规则都会被执行。
适用场景:
- 适用于模块化规则,比如
make test可能需要多个测试步骤。 - 扩展性更强,多个
Makefile片段可以独立定义test::,不会相互覆盖。
5. : vs :: 适用场景总结
| 适用场景 | 使用 :(单冒号) | 使用 ::(双冒号) |
|---|---|---|
| 唯一规则目标 | ✅ | ❌ |
| 可累积执行的目标 | ❌ | ✅ |
变量赋值(如 CC=gcc) | ✅ | ❌ |
| 多 Makefile 规则合并 | ❌ | ✅ |
| 防止规则覆盖 | ❌ | ✅ |
6. 结论
:(单冒号) 适用于唯一规则,如果目标重复定义,后面的规则会覆盖前面的。::(双冒号) 允许多次定义相同目标,并且所有规则都会被执行。- 如果 Makefile 可能被多个文件拆分并包含(
include Makefile.common),推荐使用::以避免目标覆盖。
🚀 掌握 : 和 :: 的区别,有助于编写更灵活和可维护的 Makefile!