You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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 = 的原因。

针对你的需求(获取子目录路径)的最优解法

你想要获取./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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:13:41