Makefile中dirname处理多文件路径返回空值的问题咨询
问题原因与解决方案
这个问题的根源在于不同Make实现对dirname函数的参数处理逻辑差异,尤其是BSD Make(比如macOS默认的make)和GNU Make的区别:
为什么多文件时B为空?
- 当
A只有单个文件时,$(dirname $(A))是给dirname传递了单个参数,不管是哪种Make版本,都能正确提取该文件的目录路径,所以逻辑正常。 - 当
A包含多个文件时,$(A)会展开成多个空格分隔的路径:- 如果你用的是GNU Make,
dirname函数支持多参数,会对每个路径单独处理,返回所有文件的目录部分(你的例子里会得到./dir1 ./dir1 ./dir1 ./dir1)。 - 但如果你用的是BSD Make,它的
dirname函数仅支持单个参数——当传入多个参数时,函数会直接返回空值,这就是你看到B =的原因。
- 如果你用的是GNU Make,
针对你的需求(获取子目录路径)的最优解法
你想要获取./dir1/和./dir2/的路径,但当前通过文件路径推导的方式不仅会产生重复值(因为A里的文件被重复添加了),还无法覆盖dir2(因为A里没有dir2的文件)。更直接的方式是直接匹配子目录:
方法1:直接匹配子目录(推荐)
用wildcard直接匹配目录,而不是文件:
# 获取所有以dir开头的子目录(带末尾斜杠) DIRS = $(wildcard ./dir*/) # 如果不需要末尾的斜杠,可以用patsubst去掉: # DIRS = $(patsubst %/,%,$(wildcard ./dir*/)) print-DIRS : ; @echo $* = $($*)
执行后会得到:
$ make print-DIRS DIRS = ./dir1/ ./dir2/
方法2:从文件路径提取唯一目录(兼容多Make版本)
如果你的场景确实需要从文件列表中提取不重复的目录,可以用foreach遍历每个文件,逐个调用dirname(避免多参数问题),再用sort去重:
# 同时包含dir1和dir2的文件 A = $(wildcard ./dir1/* ./dir2/*) # 遍历每个文件取目录,再去重 B = $(sort $(foreach file,$(A),$(dirname $(file)))) print-B : ; @echo $* = $($*)
执行后会得到:
$ make print-B B = ./dir1 ./dir2
内容的提问来源于stack exchange,提问作者Welgriv
相关产品推荐
相关产品推荐

