解析Makefile中sed调用的作用及等效实现方式
Makefile中sed命令行的解析与等效改写
首先给出你提供的Makefile代码:
CFLAGS = -O6 -g -Wall CC = gcc VPATH = ./code LIB_MOD = common arith inout log valid_MOD = valid $(LIB_MOD) xporta_MOD = porta four_mot portsort largecalc mp $(LIB_MOD) ALL_MOD = $(valid_MOD) $(xporta_MOD) all: xporta valid valid: $(valid_MOD:%=%.d) $(valid_MOD:%=%.o) $(CC) -o bin/$@ $(valid_MOD:%=%.o) xporta: $(xporta_MOD:%=%.d) $(xporta_MOD:%=%.o) $(CC) -o bin/$@ $(xporta_MOD:%=%.o) clean: rm -f *.o bin/xporta bin/valid %.d: %.c $(SHELL) -ec 'gcc -MM $(CPPFLAGS) $< \ | sed '\''s/\($*\)\.o[ :]*/\1.o $@ : /g'\'' > $@; \ [ -s $@ ] || rm -f $@' include $(ALL_MOD:%=%.d)
问题聚焦
你无法理解以下代码段的作用、展开结果及等效写法:
| sed '\''s/\($*\)\.o[ :]*/\1.o $@ : /g'\'' > $@; \ [ -s $@ ] || rm -f $@'
一、命令行的展开结果
先明确Makefile自动变量的含义:
$*:匹配%.d模式中的%部分,比如处理foo.d时,$*就是foo$@:当前目标文件名,比如处理foo.d时,$@就是foo.d$<:当前依赖文件,即对应的foo.c
当处理foo.c生成foo.d时,这段命令展开后为:
gcc -MM $(CPPFLAGS) foo.c | sed 's/\(foo\)\.o[ :]*/foo.o foo.d : /g' > foo.d; [ -s foo.d ] || rm -f foo.d
具体作用拆解
gcc -MM foo.c:生成foo.o的头文件依赖,输出格式类似foo.o: foo.h bar.h utils.hsed 's/\(foo\)\.o[ :]*/foo.o foo.d : /g':把输出中的foo.o:替换成foo.o foo.d :,最终输出变为foo.o foo.d : foo.h bar.h utils.h——这样当头文件更新时,不仅会重新编译foo.o,还会重新生成foo.d文件> foo.d:将处理后的内容写入foo.d文件[ -s foo.d ] || rm -f foo.d:检查foo.d是否为非空文件,若为空(比如编译出错时)则删除它,避免后续include空文件导致Make报错
二、不使用sed的等效写法
方式1:用awk替代sed(兼容旧环境)
awk可实现相同的文本替换逻辑,写法更直观:
%.d: %.c $(SHELL) -ec 'gcc -MM $(CPPFLAGS) $< \ | awk -v target="$@" "{sub(/^[^:]+:/, \"& \"target\" \"); print}" > $@; \ [ -s $@ ] || rm -f $@'
这段awk命令会把每行开头的xxx.o:替换成xxx.o xxx.d :,和原sed效果完全一致。
方式2:使用gcc内置参数简化(现代易读写法)
如果你的环境支持较新版本的gcc(兼容-MMD和-MP参数),可以完全抛弃手动生成.d文件的复杂逻辑,改用更简洁的写法:
CFLAGS = -O6 -g -Wall CC = gcc VPATH = ./code LIB_MOD = common arith inout log valid_MOD = valid $(LIB_MOD) xporta_MOD = porta four_mot portsort largecalc mp $(LIB_MOD) ALL_MOD = $(valid_MOD) $(xporta_MOD) all: xporta valid # 用-MMD自动生成.d文件,-MP避免头文件删除时报错 %.o: %.c $(CC) -c $(CFLAGS) $(CPPFLAGS) -MMD -MP $< -o $@ valid: $(valid_MOD:%=%.o) $(CC) -o bin/$@ $(valid_MOD:%=%.o) xporta: $(xporta_MOD:%=%.o) $(CC) -o bin/$@ $(xporta_MOD:%=%.o) clean: rm -f *.o *.d bin/xporta bin/valid include $(ALL_MOD:%=%.d)
-MMD:自动生成.d文件,包含*.o的头文件依赖-MP:自动为每个头文件生成空的phony目标(比如foo.h:),避免头文件被删除时Make报错- 这种写法去掉了所有sed/awk调用,还简化了目标依赖(无需显式依赖
.d文件),可读性大幅提升
内容的提问来源于stack exchange,提问作者One_Cable5781
相关产品推荐
相关产品推荐

