使用makefile注释引发的血案
被一个奇怪的报错困扰了一个晚上,结果是一个注释空格引发的,遂写一文总结一番

🔴 问题一:变量赋值中的尾随空格(本次遇到的问题)

问题描述

OBJ_DIR = Obj  # 文件输出目录</em>

表面上看OBJ_DIR 的值是 Obj

实际上OBJ_DIR 的值是 Obj (包含一个尾随空格!)

为什么会这样?

在 Makefile 中,变量赋值会保留 # 注释符之前的所有字符,包括空格。Make 不会自动 trim 变量值。

导致的错误

Makefile:17: *** mixed implicit and normal rules: deprecated syntax
Makefile:21: warning: overriding recipe for target 'Obj'
Makefile:18: warning: ignoring old recipe for target 'Obj'

当模式规则 $(OBJ_DIR)/%.o 展开为 Obj /%.o 时,空格破坏了模式规则语法,Make 无法正确解析。

✅ 正确写法

<em># 方法1:注释放在单独一行
<em># 文件输出目录
OBJ_DIR = Obj

<em># 方法2:不要在 # 前留空格(不推荐,可读性差)
OBJ_DIR = Obj<em>#文件输出目录

<em># 方法3:使用 := 并用 strip 函数
OBJ_DIR := $(strip Obj )

🟠 问题二:Tab vs 空格

问题描述

target:
    echo "This won't work"  # 使用了空格缩进

错误信息

Makefile:2: *** missing separator.  Stop.

原因

Makefile 的命令行必须以 Tab 字符开头,不能用空格。这是 Make 的历史遗留设计。

✅ 正确写法

target:
	echo "This works"  # 使用 Tab 缩进

💡 提示:在编辑器中开启「显示空白字符」功能可以区分 Tab 和空格。


🟡 问题三:路径大小写敏感问题

问题描述

SRCS = $(wildcard src/*.c)      # 小写 src
OBJS = $(SRCS:Src/%.c=Obj/%.o)  # 大写 Src

错误信息

make: *** No rule to make target 'xxx', needed by 'yyy'.  Stop.

原因

  • 在 Linux/WSL 中,文件系统是大小写敏感
  • src 和 Src 被视为不同的目录
  • 模式替换 $(SRCS:Src/%.c=...) 无法匹配 src/main.c

✅ 正确写法

# 统一使用一致的大小写
SRCS = $(wildcard Src/*.c)
OBJS = $(SRCS:Src/%.c=Obj/%.o)

🟢 问题四:变量展开时机 (= vs :=)

问题描述

A = $(B)
B = hello

# 使用 = (递归展开):A 的值是 "hello"

C := $(D)
D := world

# 使用 := (立即展开):C 的值是 "" (空),因为 D 还未定义

使用建议

赋值符行为适用场景
=延迟展开,使用时才求值需要引用后面定义的变量
:=立即展开,定义时求值变量值固定,提高性能
?=仅在变量未定义时赋值提供默认值
+=追加值累加内容

🔵 问题五:Shell 命令中的变量引用

问题描述

target:
	echo $HOME         # 错误!Make 认为这是 $H 后跟 OME
	echo $$HOME        # 正确:$$ 转义为单个 $,传递给 shell
	echo $(HOME)       # 这是 Make 变量,不是环境变量

✅ 正确写法

target:
	echo $$HOME                    # 访问 shell 环境变量
	echo $(MAKE_VAR)               # 访问 Make 变量
	echo "$${USER:-default}"       # shell 变量替换语法

🟣 问题六:多行命令的执行

问题描述

target:
	cd subdir
	make          # 这行在原目录执行,不是 subdir!

原因

Makefile 中每行命令都在独立的 shell 进程中执行。第一行的 cd 效果不会延续到第二行。

✅ 正确写法

# 方法1:使用分号连接
target:
	cd subdir; make

# 方法2:使用反斜杠续行
target:
	cd subdir && \
	make

# 方法3:使用 .ONESHELL(GNU Make 3.82+)
.ONESHELL:
target:
	cd subdir
	make

⚫ 问题七:通配符在变量中不展开

问题描述

SOURCES = *.c        # 不会展开!SOURCES 的值就是 "*.c" 字符串
FILES := $(wildcard *.c)  # 正确:使用 wildcard 函数

原因

Makefile 中的通配符(*?[...])只在以下位置自动展开:

  1. 规则的目标(target)
  2. 规则的依赖(prerequisites)
  3. 命令行中(由 shell 展开)

在变量赋值中不会自动展开。

✅ 正确写法

SOURCES := $(wildcard Src/*.c)
HEADERS := $(wildcard Inc/*.h)

📋 快速检查清单

在调试 Makefile 问题时,检查以下几点:

  • [ ] 变量赋值行末是否有意外的空格?
  • [ ] 命令行是否使用 Tab 缩进?
  • [ ] 路径大小写是否一致?
  • [ ] = 和 := 的使用是否正确?
  • [ ] Shell 变量是否使用了 $$ 转义?
  • [ ] 多行命令是否需要用 && 或 ; 连接?
  • [ ] 通配符是否使用了 $(wildcard ...) 函数?

🔧 调试技巧

# 打印变量值(注意用引号包裹以显示空格)
debug:
	@echo "OBJ_DIR = '$(OBJ_DIR)'"
	@echo "SRCS = '$(SRCS)'"
	@echo "OBJS = '$(OBJS)'"

# 或使用 make 的 -p 选项打印所有变量和规则
# make -p | grep OBJ_DIR

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇