Makefile中执行Bash代码收集CPP文件时变量不更新怎么办?
Makefile收集src目录CPP文件的常见踩坑与正确写法
原代码运行异常的核心原因
你最初编写的Makefile运行后出现g++ -c -g ""的空参数报错,核心是混淆了Make变量与Shell变量的作用域边界,同时存在多处语法不匹配的问题:
- Makefile的变量赋值、替换动作都在解析阶段一次性完成,每个构建规则下的命令是由独立的Shell进程逐行执行的。在Shell命令块里试图修改变量、拼接文件路径的操作,根本不会回传给Make层,更不会影响后续规则里引用的$(SRC_FILES)。你在gather-files规则里写的循环,哪怕Shell层面拼出了正确的文件路径,Make在执行game规则时拿到的还是最开始定义的空SRC_FILES值。
- 循环里写的
$(var)是Make的替换语法,在解析阶段就会被直接替换成空(因为Make上下文里根本没有定义var变量),根本不会等待Shell循环取到实际的文件名单值再做替换,自然变量值无法正常传递。 - 哪怕不考虑作用域隔离的问题,循环里写的
SRC_FILES+="./src/"+"$(var) "本身也不符合Bash语法规则:Bash没有用+做字符串拼接的语法,直接写相邻字符串即可,写+的话会被当成普通字符拼入最终路径,生成的文件路径本身就是无效的。 - 嵌套
ls -all + awk遍历文件名的写法本身兼容性差,遇到带空格的文件名就会解析错误,流程冗余。
符合Make设计逻辑的实现方式
完全不需要额外写独立的gather-files规则,也不需要嵌套Shell循环拼接路径,直接使用Make内置的wildcard函数在解析阶段自动匹配目标目录下的CPP文件即可,也就是你最终参考得到的写法:
# 解析阶段自动匹配src目录下所有cpp文件,直接赋值给SRC_FILES变量 SRC_FILES := $(wildcard src/*.cpp) CC = g++ CFLAGS = -g # 把匹配到的所有cpp文件作为game目标的依赖,Make会自动追踪文件改动 game: $(SRC_FILES) $(CC) -c $(CFLAGS) $(SRC_FILES)
这种写法的优势:
- 全程不需要依赖Shell层做字符串拼接,变量值在Make解析阶段就确定,跨规则引用不会丢值
- 相比手写Shell遍历,对带空格、特殊字符的文件名兼容性更好
- 可以直接利用Make的依赖追踪能力,源文件改动时自动触发重新编译,不需要手动维护文件列表
采用这种写法后,运行
make game就不会再出现空输入文件的报错,Make会把src下所有识别到的cpp文件路径完整传递给g++。
内容的提问来源于stack exchange,提问作者jbolt
相关产品推荐
相关产品推荐

