【问题标题】:How do I make Makefile to recompile only changed files?如何使 Makefile 仅重新编译已更改的文件?
【发布时间】:2011-12-10 13:15:48
【问题描述】:

我一直在努力让 make 只编译已编辑的文件。但是我没有取得太大的成功,所有文件都被重新编译。谁能解释一下为什么?

我的文件是:

main.c
a_functions.c

其中 ma​​in.c 包括 main.h a_functions.c 包括 a.h

这是我的生成文件:

CC=gcc
CFLAGS=-Wall -I. -c
EXEC_FILE=program1


all: program

a_functions.o: a_functions.c
a_functions.c: a.h
main.o: main.c
main.c: main.h

objects: a_functions.c main.c
    $(CC) a_functions.c main.c $(CFLAGS)

program: a_functions.o main.o
    $(CC) a_functions.o main.o -o $(EXEC_FILE)

根据建议更改makefile似乎有同样的问题::

all: program

a_functions.o: a_functions.c a.h
    gcc a_functions.c -c

main.o: main.c main.h
    gcc main.c -c

program: a_functions.o main.o
    gcc a_functions.o main.o -o program1

【问题讨论】:

  • -I. 让我觉得很奇怪。那是怎么回事?
  • @sarnold:仅表示在当前目录中搜索包含文件以及实现定义的文件。是否需要它是有争议的,但我认为它不会造成任何伤害。
  • @paxdiablo,也许,但我猜这是另一个问题的症状。如果他的平台没有为某些东西提供系统范围的标头,而他必须提供自己的版本,那是一回事,但我猜这是一个错误......
  • @sarnold:这怎么可能是个错误?几乎可以肯定,在您想要编译的几乎所有程序中,当前目录中都需要包含头文件。
  • 以使答案无效的方式更改问题不是一个好主意。随意扩充信息(请参阅我的编辑),否则 SO 变得不那么有用,因为答案与问题不匹配。

标签: c makefile recompile


【解决方案1】:

你正在谈论的具体问题——即使没有任何改变,也要重建program1(通过重新链接对象)——在这条规则中:

program: a_functions.o main.o
    gcc a_functions.o main.o -o program1

这条规则的目标是program,Make假定它是一个文件。但是由于没有这个文件,所以每次运行 Make 时,Make 都会认为这个文件需要重建,并执行规则。我建议这样做:

program1: a_functions.o main.o
    gcc a_functions.o main.o -o program1

或者更好,这个:

program1: a_functions.o main.o
    gcc $^ -o $@

或者更好的是:

$(EXEC_FILE): a_functions.o main.o
    $(CC) $^ -o $@

(并且不要忘记更改 all 规则以匹配。)

其他几点:

  1. 正如@paxdiablo 指出的那样,

    a_functions.o: a_functions.c a.h
    main.o: main.c main.h
    
  2. 除非一个对象(可能是main.o)调用另一个对象(可能是a_functions.o),否则将这些对象链接在一起是没有意义的,所以我希望看到这样的依赖关系:

    main.o: a.h
    

    所以我怀疑你有一些错误的声明。

  3. 您声明了objects 规则,但从不引用它。所以你从来没有真正使用过它; Make 使用%.o: %.c 的默认规则。我建议这样做:

    OBJECTS = a_functions.o main.o
    $(OBJECTS): %.o: %.c
        $(CC) $< $(CFLAGS) -o $@
    

    (在这种情况下,您可以将$(EXEC_FILE): a_functions.o main.o 更改为$(EXEC_FILE): $(OBJECTS)。)或者只是这样:

    %.o: %.c
        $(CC) $< $(CFLAGS) -o $@
    

【讨论】:

  • 很好,+1,我想我们赢了。
  • .PHONY 有帮助吗? (不过,可能是 GNU make 独有的功能。)
  • @DavidPoole,从概念上讲是的,它会告诉 Make program 不应该是一个文件(即使这样的文件恰好存在也应该执行)。实际上,不,因为 Make 仍然会每次都执行该规则,即使没有任何变化。
  • 谢谢。我现在看到$(OBJECTS): %.c 没有任何意义。所以规则%.o: %.c&lt;newline&gt;&lt;TAB&gt;$(CC) $&lt; $(CFLAGS) -o $@ 的意思是“对于每个.c 文件,编译对应的.o 目标文件”。规则$(OBJECTS): %: %.c&lt;newline&gt;&lt;TAB&gt;$(CC) $&lt; $(CFLAGS) -o $@ 的意思是“对于OBJECTS 中的每个.o 文件,将相应的.c 文件编译为.o 目标文件”。(?) - 我注意到您的$(OBJECTS): %: %.c$(objects): %.o: %.c 之间存在差异the docs - 他们写%.o,而你只写%。文档错字?还是两者都有效?
  • @Henke:很好,这是我的一个错字——九年来没人注意到!我会编辑。
【解决方案2】:

不确定这是否会导致您的具体问题,但有两行:

a_functions.c: a.h
main.c: main.h

肯定是错误的,因为通常没有命令可以根据包含的头文件重新创建 C 文件。

C 文件不依赖于它们的头文件,这些 C 文件创建的 对象 会。

例如,main.c 的:

#include <hdr1.h>
#include <hdr2.h>
int main (void) { return 0; }

将在makefile 中类似于:

main.o: main.c hdr1.h hdr2.h
    gcc -c -o main.o main.c

变化:

a_functions.o: a_functions.c
a_functions.c: a.h
main.o: main.c
main.c: main.h

到:

a_functions.o: a_functions.c a.h
main.o: main.c main.h

(假设a_functions.c 包括a.hmain.c 包括main.h)然后重试。

如果上述假设是错误的,您必须告诉我们哪些 C 文件包含哪些标头,以便我们告诉您正确的规则。


如果您的观点是 makefile 即使在进行了这些更改之后仍在构建所有内容,那么您需要查看两件事。

第一个是ls -l 对所有相关文件的输出,以便您查看它们的日期和时间。

第二个是make 的实际输出。 make -d 的输出将特别有用,因为它显示 make 使用哪些文件和日期来确定要做什么。


在调查方面,make 似乎可以正常工作,如下所示:

=====
pax$ cat qq.h
#define QQ 1
=====
pax$ cat qq.c
#include "qq.h"
int main(void) { return 0; }
=====
pax$ cat qq.mk
qq: qq.o
        gcc -o qq qq.o

qq.o: qq.c qq.h
        gcc -c -o qq.o qq.c
=====
pax$ touch qq.c qq.h
=====
pax$ make -f qq.mk
gcc -c -o qq.o qq.c
gcc -o qq qq.o
=====
pax$ make -f qq.mk
make: `qq' is up to date.

【讨论】:

  • 我按照你说的做了,但它仍然会重新编译所有内容。我什至尝试通过 main.o 复制您的示例: main.c main.h \n $(CC) main.c $(CFLAGS) 但仍然存在同样的问题
  • @Pithikos:向我们展示编译器的输出。为什么说每次都在编译。
  • @Falmarri 我可以看到它会重新编译,因为每次我“制作”时 program1 的日期都会发生变化。
  • 对象不会被重新编译。只有 program1 被重新链接。
【解决方案3】:

事后很晚,实际上它是基于 paxdiablo 的优秀答案,但在试验时我发现你不需要为每个 .o 文件单独的目标,除非你做一些聪明的事情。

所以对于我的makefile:

all: program

program: a_functions.o main.o
    gcc a_functions.o main.o -o program

clean: 
    rm -f *.o
    rm -f program

在 make 4.1 中,它会自动编译 .o 文件,如果 .o 文件与源文件同名,则无需执行任何操作。因此,它会自动搜索 a_functions.c、a_functions.h、main.h 和 main.c。如果您没有预期的源代码名称,则会收到如下错误:

make: *** No rule to make target 'a_functions.o', needed by 'program'.  Stop.

我还为您添加了一个“干净”的目标。如果您需要将软件作为源代码发布,或者您只想删除所有已编译的目标文件和/或二进制文件,“清理”非常有用。

这就是您需要做的所有事情。

将此保存到“Makefile”并运行:

$ make

构建你的二进制文件。还有

$ make clean 

清理代码中的已编译对象和二进制文件。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-02-01
    • 2014-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-15
    • 1970-01-01
    相关资源
    最近更新 更多