Makefile切换目录后md5sum无法找到文件问题及优化需求
解决Makefile生成带MD5SUM的软件包时的命令执行问题
嘿,我之前也踩过这个Makefile的坑!先把你的可复现代码补全一下(方便大家理解问题):
VERSION:=1 DIR:=tmp file: # 使用当前版本标签构建文件的规则 touch $(DIR)/file-$(VERSION) # 失败的file1规则 $(DIR)/file1.tar: file cd $(DIR) md5sum -b \ file-$(VERSION) \ >> md5sum.txt tar -cf file1.tar file-$(VERSION) md5sum.txt # 临时可行的file2规则 $(DIR)/file2.tar: file cd $(DIR) && md5sum -b file-$(VERSION) >> md5sum.txt && tar -cf file2.tar file-$(VERSION) md5sum.txt
为啥file1的规则会失败?
核心原因是Makefile里的每一行命令都是在独立的Shell进程中跑的!你写的cd $(DIR)执行完,这个Shell进程就直接退出了,回到了Makefile所在的原目录。下一行的md5sum命令根本不在tmp目录里执行,自然找不到file-$(VERSION),肯定失败。
比临时方案更优雅的解决办法
你的file2用&&把命令串起来是可行的,但还有几种更易读、更易维护的方式:
1. 用反斜杠把命令合并到同一个Shell进程
把所有需要在tmp目录执行的命令用反斜杠连接,让它们在同一个Shell里运行,同时用&&保证前一步成功才走下一步:
$(DIR)/file1.tar: file cd $(DIR) && \ md5sum -b file-$(VERSION) >> md5sum.txt && \ tar -cf file1.tar file-$(VERSION) md5sum.txt
这样既保持了代码的换行可读性,又解决了目录切换的问题。
2. 用.ONESHELL伪目标(GNU Make专属)
如果你用的是GNU Make 3.82及以上版本,可以直接加.ONESHELL,让整个规则的所有命令都在同一个Shell进程里执行:
.ONESHELL: $(DIR)/file1.tar: file cd $(DIR) md5sum -b file-$(VERSION) >> md5sum.txt tar -cf file1.tar file-$(VERSION) md5sum.txt
这种方式完全不用改命令结构,写起来和普通Shell脚本一样清爽。
3. 用Shell命令块包裹
也可以直接用bash -c把所有命令打包成一个块,强制在同一个Shell里执行:
$(DIR)/file1.tar: file bash -c "cd $(DIR); md5sum -b file-$(VERSION) >> md5sum.txt; tar -cf file1.tar file-$(VERSION) md5sum.txt"
不过这种方式要注意命令里的特殊字符转义,比如如果文件名有空格,就得加引号,不如前两种方便。
小提示
- 可以在生成MD5文件后加个检查,比如
test -f $(DIR)/md5sum.txt,避免后续打包出错; - 打包完成后如果不需要MD5文件,可以用
$(RM) $(DIR)/md5sum.txt清理掉,让目录更干净。
内容的提问来源于stack exchange,提问作者Jonatan Goebel
相关产品推荐
相关产品推荐

