cc -MM 解决:如果makefile和源码不在同一个目录下,更新头文件却不能重建目标的问题

时间:2021-12-07 12:48:56
背景:
当前目录下有include ,src两个目录,include放头文件,src有四个源文件。写了如下makefile文件。可以生成目标。hello
问题:当我更新了头文件之后,重新make竟然提示我当前hello已经是最新的了。28行以后的东西难道没有起作用?28行-32行好多教程里面都是这么写的呀。包括gnu make中文手册,跟我写makefile.

09 OBJ_DIR=./src
 10 VPATH=src:include
 11 #vpath %.h include
 12 sources=$(wildcard $(OBJ_DIR)/*.c)
 13 objects=$(patsubst %.c,%.o,$(sources))
 14 #echo $(sources)
 15 hello : $(objects)
 16         @echo "$$ ^ >" $^
 17         @echo "$$ @ >" $@
 18         cc  $^ -o $@
 19 clean:
 20         -rm hello $(OBJ_DIR)/*.o
 21         -rm $(OBJ_DIR)/*.d*
 22 display:
 23         @echo "VPATH>>" $(VPATH)
 24         @echo "sources>>"$(sources)
 25         @echo "objects>>"$(objects)
 26 #sources=main.c print_hello.c
 27 include $(sources:.c=.d)
 28 %.d: %.c
 29         set -e; rm -f $@; \
 30 $(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \
 31 sed 's,\( $*\)\.o[:]*,\1.o $@:,g' < $@.$$$$ > $@; \
 32 #rm -f $@.$$$$

真是奇怪了。真是百思不得其解。
我在终端上运行 cc -MM src/main.c 输出
main.o: src/main.c src/../include/print_usr.h
查看main.d里面的依赖关系也是下面这样:
main.o: src/main.c src/../include/print_usr.h,中间少了*.d的文件,也就是说,31行没有替换成功。
再次运行make
查看输出信息

sed's,\(src/main\)\.o[:]*,\1.o src/main.d:,g' < src/main.d.$$ > src/main.d;
我草,怪不得,cc -MM里只输出了
main.o: src/main.c src/../include/print_usr.h,
31行却要找到src/main.o去替换,替换不成功的啊。这不是坑爹吗?原因找到了,但为什么cc -MM src/main.c的前面没有路径呢?真不知道那。为了替换成功,修改查找条件,用notdir 取出文件名,作为查找条件,重新生成.d.但是,结果呢,更新.h文件,还是不能重新生成hello.纳尼?看我最后绝招,在main.o前面加上路径吧,31行修改成sed 's,\($(notdir $*)\)\.o[:]*,$(dir $*)\1.o $@:,g' < $@.$$$$ > $@; \
​还真可以了。
​gnu make 中文手册,跟我写makefile,用到的例子源文件和makefile在同一个目录下,所以用起来没有问题。而事实是我们经常将源文件分散到不同的路径下,问题就来了。作为一个经常上网百度解决的问题的人,也要贡献出自己的力量,为苦恼,抓头皮的码农们送出一缕阳光。