如何处理包含带有C中makefile的标题的标题?

如何处理包含带有C中makefile的标题的标题?,c,makefile,C,Makefile,假设您有一个名为file.c的文件 file.c包括header1.h header1.h包括header2.h 以下是生成文件的内容: file.x: file.o -gcc file.o -o file.x file.o: file.c header1.h header2.h -gcc file.c header1.h header2.h 当header2.h包含header1.h时,我不知道如何处理 这条线是多余的吗?还是显示依赖关系的好风格 fil

假设您有一个名为file.c的文件

  • file.c
    包括
    header1.h
  • header1.h
    包括
    header2.h
以下是生成文件的内容:

file.x: file.o
        -gcc file.o -o file.x

file.o: file.c header1.h header2.h
        -gcc file.c header1.h header2.h
当header2.h包含header1.h时,我不知道如何处理

这条线是多余的吗?还是显示依赖关系的好风格

file.c header1.h header2.h

更新:我为造成的混乱道歉。我已恢复了对该问题所做的编辑。当前的makefile是我在Jonathan的答案所指的原始问题中发布的文件。

该问题的原始版本在
makefile
中包含以下行:

file.o: file.c header1.h header2.h
        -gcc file.c header1.h header2.h
我的回答针对问题的原始版本,在它被修正之前

请注意,除非编译器反对编译头文件,否则编译行将生成可执行文件
a.out
。命令行中应该有
-c


有几个问题:

  • makefile
    中,何时需要重建对象文件

    答:当源文件或其中一个标题包含更改时

    子公司Q:这条依赖关系线是什么意思:

    file.o: file.c header1.h header2.h
    
    如果源文件或其中一个头文件发生更改,则需要重新生成子文件A:
    file.o

  • 如果您规定:
    header1.h
    取决于
    header2.h
    ,当您更改
    header2.h
    时,
    header1.h
    会发生什么

    答:没有。您本身并不编译
    header1.h
    。更改的是对象文件

  • 如果您规定
    file.c
    依赖于
    header1.h
    header2.h
    或两者,那么当您更改其中一个标题时,
    file.c
    会发生什么情况

    回答:又没有了。您不需要更改
    file.c
    ;重新编译对象文件

  • 因此,对象文件规则的依赖项部分很好(在与自动依赖项生成相关的限制范围内)。说源文件依赖于头文件的规则没有意义;事实上,源文件并不直接依赖于头文件。(这间接地取决于它们,因为如果标题内容发生变化,使原来有效的代码不再是有效的代码,那么在修复源代码之前,将不会编译任何代码。但这有点离题。)

    硬编码依赖关系是有问题的;他们变了。另一方面,自动生成依赖关系非常复杂。有一些GCC选项(如
    -M
    -MM
    -MF
    -MG
    -MP
    -MQ
    -MD
    -MT
    -H
    -如此丰富的选项告诉您这里有问题!)来帮助,GNU
    make
    具有“条件包含”,如果依赖项文件存在,则包含它们,如果不存在,则不包含witter。这些可能会有所帮助。查找
    makedependent
    mkdep
    和相关命令,了解其他自动化方法


    忽略自动依赖项生成,您的生成文件可能会读取:

    FILES.o = file.o
    
    file.x: ${FILES.o}
            ${CC} -o $@ ${CFLAGS} ${FILES.o} 
    
    file.o: file.c header1.h header2.h
    
    make
    将提供一个命令,将
    file.c
    编译成
    file.o

    当您的程序也开始使用
    other.o
    时,只需将
    other.o
    添加到宏
    FILES.o
    (这就是为什么它是一个复数名称)。您也可以添加依赖项信息。如果您也需要库,则可以向链接行添加选项:

    LDFLAGS = -L/usr/local/lib
    LDLIBS  = -llocal
    
    FILES.o = file.o other1.o other2.o
    
    file.x: ${FILES.o}
            ${CC} -o $@ ${CFLAGS} ${FILES.o} ${LDFLAGS} ${LDLIBS}
    
    file.o: file.c header1.h header2.h
    

    请注意,库应该在对象文件之后。在对象文件之前列出库很容易导致其他平台上的链接时间失败,从而激怒那些试图构建您的软件的人。

    您不需要将头文件提供给编译器。无论如何它都会找到它们的。
    -gcc
    ,真的吗?如果编译失败,你不想让
    make
    失败吗?我是C。。。您认为哪种方法更好?从
    -gcc
    中删除
    -
    。如果希望
    make
    尽可能多地构建,请使用
    make-k
    ;它会在出错后继续运行,直到无法生成任何其他内容为止。不要使用
    make-i
    。通常忽略
    ;这会带来麻烦。而且即使构建失败,
    -gcc
    也会使整个
    make
    成功,这通常是个坏消息。几乎所有代码都有问题,但问题的答案是需要执行依赖性分析。GCC可以为您做到这一点(我相信使用了
    -M
    选项的一些变体),但这有点不简单,您基本上需要在文件上运行两个过程。哦,好吧,这意味着只需编写“file.o:file.c”就足够了?因为头文件已经包含在文件中了?对于下一行:“gcc file.c”?“所以,您的对象文件规则很好”--依赖关系很好(尽管它们应该是自动生成的),但是编译命令是非常错误的。您需要
    file.o:file.c header1.h header2.h
    某个地方告诉
    make
    ,如果三个文件中的任何一个发生更改,它需要重建
    file.o
    。仅将
    file.c
    列为依赖项意味着
    header1.h
    可以更改,但对象文件不会重建。@CowZow“因此,这意味着只需编写“file.o:file.c”就足够了,因为头已经包含在文件中?”--不,这不好,他根本没有这么说。