Makefile GNU制造。为什么使用这种复杂的语法来生成依赖项?

Makefile GNU制造。为什么使用这种复杂的语法来生成依赖项?,makefile,gnu-make,Makefile,Gnu Make,我正在阅读使用GNU Make管理项目,并在第2.7章-自动依赖项生成中找到了这个示例。作者在GNU手册中提到了他们的观点: %.d: %c $(CC) -M $(CPPFLAGS $< > $@.$$$$; \ sed s',\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \ rm -f $@.$$$$ 所有这些行都是生成依赖项,然后添加*.d名称。他们不

我正在阅读使用GNU Make管理项目,并在第2.7章-自动依赖项生成中找到了这个示例。作者在GNU手册中提到了他们的观点:

%.d: %c
        $(CC) -M $(CPPFLAGS $< > $@.$$$$; \
              sed s',\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
              rm -f $@.$$$$
所有这些行都是生成依赖项,然后添加
*.d
名称。他们不得不将第一行更改为:

  foo.o: bar.h foo.h fubar.h
到 foo.o foo.d:bar.h foo.h fubar.h

我的命令更简单,而且似乎工作得很好,但我认为GNU人员使用
sed
命令是有原因的。此外:

  • 为什么要将文件重定向到
    sed
    ?为什么不干脆把它作为一个公共行参数呢
  • 为什么不完全跳过中间文件

我知道GNU的人也会想到这些,但出于某种原因,他们采用了更复杂的设置。我只想理解他们的推理,所以我可以在运行中执行这些操作。

一个更简单的解决方案是完全取消sed调用,因为gcc可以直接完成您需要的所有操作:

%.d: %.c
        $(CC) -M $(CPPFLAGS) -MF $@ $< -MT "$*.o $@"
%.d:%.c
$(CC)-M$(CPPFLAGS)-MF$@$<-MT“$*.o$@”

实际上,甚至规则本身都不是必需的。在Paul D.Smith撰写的文章中,对生成Make样式依赖项的不同方法有一个很好的概述

毕竟,以下规则应该足够了(在使用GCC的情况下):

%.o:%.c
$(CC)$(CPPFLAGS)$(CFLAGS)-MMD-MP-o$@-c$<
-包括$(来源:.c=.d)
UPD。
我刚才也有一个类似的问题。它包含对
-MMD-MP
选项的解释(引用GCC手册)。

解决了以下问题:
为什么要将文件重定向到sed?
如果:

@$(CC) -M $(CPPFLAGS) $<  | sed 's|:| $*.d : |'  > $@;
@$(CC)-M$(CPPFLAGS)$<|sed的|:|$*.d:|'>$;

如果编译失败(出错且不生成输出),您将创建一个空的目标文件。当再次运行
make
时,它将看到新创建的空文件,而不会重新生成它,从而导致生成错误。使用中间文件是一种常见的防御策略,以避免意外创建空目标。

嘿,这对我很有用!我从来没有深入研究过
gcc
的奥秘,它有大量的命令行选项。但是,这非常有效。我喜欢你的
include
指令,比书中的指令要好得多。它更简单,更容易理解。不幸的是,由于某种原因,
%.o%.c
规则未能为其中一个文件构建依赖关系。我将不得不深入研究
gcc
命令参数的多样性。@David Hmm。。。那看起来很奇怪
-MMD-MP
选项对我来说总是很神奇。@DavidW.,你能给我们一个导致规则失败的最小示例吗?@Beta Nothing“fails”,它只是不创建任何文件的依赖关系。这是奥利GNU的书。我想是第2.7章。Makefile在中。这可能与我定义链接依赖项的方式有关。我没有
count\u words
依赖
count\u words.o
,因为这是默认设置。我没有试图追查这个问题。
-MP
是可选的,但非常有用。如果没有它,如果头文件已被删除或重命名,生成的依赖项将导致其目标失败。这就是我要寻找的解释。我的将创建空文件,即使编译失败。GNU的版本不会。
%.o: %.c
    $(CC) $(CPPFLAGS) $(CFLAGS) -MMD -MP -o $@ -c $<

-include $(SOURCES:.c=.d)
@$(CC) -M $(CPPFLAGS) $<  | sed 's|:| $*.d : |'  > $@;