GNU Make:如何结合子目录使用模式规则?
问题
我原本的Makefile构建规则如下:
SRCS := $(shell find . -name '*.c') HEADERS := $(shell find . -name '*.h') OBJS := $(SRCS:.c=.o) %.o : %.c $(CC) -c $(CFLAGS) $< -o $@ executable : $(OBJS) $(HEADERS) $(CC) $(CFLAGS) $(OBJS) -o executable
我希望将.c和.h文件移至src/目录,同时将.o文件生成在obj/目录中,但遇到了困难:
SRCS := $(shell find src/ -name '*.c') HEADERS := $(shell find src/ -name '*.h') OBJS := $(SRCS:.c=.o) <- 这一行我该替换成什么?? obj/ : mkdir -p obj obj/%.o : src/%.c obj/ $(CC) -c $(CFLAGS) $< -o $@ bin/ : mkdir -p bin bin/executable : $(OBJS) $(HEADERS) bin/ $(CC) $(CFLAGS) $(OBJS) -o bin/executable
有没有简便方法从src/%.c文件路径生成obj/%.o文件路径?我查阅了文档,但不知道该搜索哪些关键词。
解决方案
要实现src/下的.c到obj/下.o的路径转换,用Make的模式替换就能轻松搞定,有两种简洁写法:
写法1:使用patsubst函数
OBJS := $(patsubst src/%.c, obj/%.o, $(SRCS))
这个函数会把$(SRCS)中所有匹配src/%.c的字符串,替换成对应的obj/%.o,完全匹配你的需求。
写法2:简化的原生替换语法
如果偏好更简洁的写法,也可以直接用Make的原生替换规则:
OBJS := $(SRCS:src/%.c=obj/%.o)
效果和patsubst完全一致,是Make中专门针对模式匹配的简化写法。
修正后的完整Makefile
替换OBJS行后,还可以优化目录创建逻辑(不用单独写obj/、bin/规则),最终版本如下:
SRCS := $(shell find src/ -name '*.c') HEADERS := $(shell find src/ -name '*.h') OBJS := $(SRCS:src/%.c=obj/%.o) # 编译.c为.o,自动创建obj目录 obj/%.o : src/%.c @mkdir -p $(dir $@) $(CC) -c $(CFLAGS) $< -o $@ # 链接生成最终可执行文件,自动创建bin目录 bin/executable : $(OBJS) $(HEADERS) @mkdir -p $(dir $@) $(CC) $(CFLAGS) $(OBJS) -o $@ # 可选:清理生成文件的规则 clean: rm -rf obj/ bin/
相关知识点提示
你需要搜索的关键词是 Makefile pattern substitution(模式替换)或者 Makefile path transformation(路径转换),这些关键词能快速定位到官方文档里的对应内容。
另外,$(dir $@)会自动提取目标文件的目录部分(比如obj/test.o对应的目录是obj/),配合mkdir -p可以自动创建所需目录,省去单独维护目录规则的麻烦。
内容的提问来源于stack exchange,提问作者kerkeslager
相关产品推荐
相关产品推荐

