为何Make将前缀文件夹插入词干中间而非开头?依赖路径疑问
问题描述
文件系统结构如下:
$ tree . ├── deps ├── file2.c ├── Makefile └── subfolder └── file1.c 3 directories, 3 files
为生成依赖文件并保留目录结构编译目标文件,编写了简化版Makefile:
OBJECTS := subfolder/file1.o file2.o all: $(OBJECTS) %.o: %.c deps/%.d @echo '%.o: %.c deps/%.d' @echo '$@: $^ ($*)' @echo %.d: ; .SUFFIXES:
运行make后得到不符合预期的结果:
$ make %.o: %.c deps/%.d subfolder/file1.o: subfolder/file1.c subfolder/deps/file1.d (subfolder/file1) %.o: %.c deps/%.d file2.o: file2.c deps/file2.d (file2)
疑问:当词干为subfolder/file1时,为何deps/%.d匹配为subfolder/deps/file1.d,而非预期的deps/subfolder/file1.d?
原因分析与解决方法
原因
这种情况通常是因为你使用的Make实现(如部分非GNU版本的Make)对模式匹配的%处理逻辑不同:
- GNU Make中,
%会匹配包含路径分隔符的完整词干,因此对于目标subfolder/file1.o,%对应的词干是subfolder/file1,deps/%.d会被解析为deps/subfolder/file1.d,这是符合预期的结果。 - 若你使用的Make版本仅让
%匹配文件名部分(不包含路径前缀),那么subfolder/file1.o的词干是file1,Make会自动将目标的路径前缀subfolder/附加到依赖路径前,导致deps/%.d被解析为subfolder/deps/file1.d。
解决方法
如果你需要兼容不同Make版本,或确保依赖路径严格符合deps/subfolder/file1.d的结构,可以用以下方式修改Makefile:
方法1:明确构造依赖路径(GNU Make兼容)
OBJECTS := subfolder/file1.o file2.o all: $(OBJECTS) # 确保依赖文件路径为deps/xxx.d,自动创建子目录 %.o: %.c deps/%.d @echo '$@: $^ ($*)' # 替换为实际编译命令,例如:gcc -c $< -o $@ # 生成依赖文件时自动创建deps下的子目录 deps/%.d: @mkdir -p $(dir $@) @touch $@ .SUFFIXES:
方法2:遍历目标生成规则(兼容更多Make版本)
OBJECTS := subfolder/file1.o file2.o all: $(OBJECTS) # 为每个目标单独生成规则,精准控制依赖路径 define compile_rule $(1): $(1:.o=.c) deps/$(1:.o=.d) @echo '$@: $$^ ($$(basename $$@))' endef $(foreach obj,$(OBJECTS),$(eval $(call compile_rule,$(obj)))) # 生成依赖文件时自动创建目录 deps/%.d: @mkdir -p $(dir $@) @touch $@ .SUFFIXES:
这样修改后,无论使用哪种Make实现,都能生成deps/subfolder/file1.d格式的依赖文件,符合你的预期。
内容的提问来源于stack exchange,提问作者salieff
相关产品推荐
相关产品推荐

