如何在GNU Make 3.81的Makefile中切换至相对父目录?
解决GNU Make中cd到父目录不生效的问题
嘿,这个坑我踩过!在GNU Make里直接写cd '..'没效果,核心原因是Make的每条命令都是在独立的Shell进程中执行的——你cd到父目录的那个进程跑完就终止了,下一条命令又回到了Make初始的工作目录,相当于白cd了😅。
要解决这个问题,关键是要基于当前Makefile文件的实际路径来切换目录(而不是依赖执行make命令时的工作目录),同时让cd和后续命令在同一个Shell进程里生效。下面给你两种实用的解决方法:
方法1:获取Makefile的绝对路径,统一在父目录执行命令
首先,先定义一个变量来获取当前Makefile所在的绝对目录(不管你在哪个目录执行make,这个路径都是准确的):
# 获取当前Makefile的绝对目录 MAKEFILE_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) # 基于上面的路径,得到父目录的绝对路径 PARENT_DIR := $(abspath $(MAKEFILE_DIR)/..)
然后,你可以用两种方式在父目录执行命令:
方式A:把cd和命令放在同一行(同Shell进程)
把cd和要执行的命令用&&连接,这样它们会在同一个Shell进程里运行,cd的效果会保留:
# 示例:在父目录打印当前路径 print-parent-dir: cd $(PARENT_DIR) && echo "当前工作目录:$$PWD"
如果要执行多条命令,可以用Shell的大括号把命令包起来,注意每行末尾加反斜杠\(表示命令未结束):
# 示例:在父目录执行多个操作 parent-operations: cd $(PARENT_DIR) && { \ echo "列出父目录内容:"; \ ls -l; \ echo "创建临时文件:"; \ touch temp_demo.txt; \ }
方式B:用make -C直接切换目录执行目标
如果父目录也有Makefile,你可以直接用make的-C选项(切换到指定目录后再执行目标),这是更简洁的写法:
# 示例:调用父目录Makefile的build目标 build-parent-project: $(MAKE) -C $(PARENT_DIR) build
方法2:全局切换Make的工作目录(适合整个Makefile都在父目录工作)
如果你的整个Makefile逻辑都需要在父目录运行,可以在Makefile开头就切换工作目录,比如:
MAKEFILE_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) # 切换到父目录,后续所有命令都在该目录执行 $(shell cd $(MAKEFILE_DIR)/..) # 或者更稳妥的,重新设置CURDIR变量 CURDIR := $(abspath $(MAKEFILE_DIR)/..)
不过这种方式要注意,后续所有依赖路径都要基于父目录来写,避免混淆。
为什么直接cd '..'不行?
举个反例,你写这样的代码:
bad-example: cd '..' pwd
这两条命令是在两个完全独立的Shell进程里执行的:第一条进程cd到父目录后就退出了,第二条进程还是在你执行make时的原始目录,所以pwd输出的还是原来的路径,看起来cd没生效。
内容的提问来源于stack exchange,提问作者kenorb




