C语言 如何使 Makefile 仅重新编译已更改的文件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7815400/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 09:55:50  来源:igfitidea点击:

How do I make Makefile to recompile only changed files?

cmakefilerecompile

提问by Pithikos

I have been struggling a bit to get make to compile only the files that have been edited. However I didn't have much success and all the files get recompiled. Can someone explain me why?

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

My files are:

我的文件是:

main.c
a_functions.c

where main.cincludes main.hand a_functions.cincludes a.h

其中main.c包括main.ha_functions.c包括ah

Here is my makefile:

这是我的生成文件:

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)

Changing the makefile as per suggestions seems to have the same problem::

根据建议更改 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

回答by Beta

The specific problem you're talking about -- Make rebuilds program1(by relinking the objects) even when nothing has changed -- is in this rule:

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

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

The target of this rule is program, and Make assumes that it is a file. But since there is no such file, every time you run Make, Make thinks that this file needs to be rebuilt, and executes the rule. I suggest this:

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

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

Or better, this:

或者更好的是,这个:

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

Or better still this:

或者更好的是:

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

(And don't forget to change the allrule to match.)

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

A few other points:

其他几点:

  1. As @paxdiablo pointed out,

    a_functions.o: a_functions.c a.h
    main.o: main.c main.h
    
  2. It doesn't make sense to link these objects together unless something in one (probably main.o) calls something in the other (probably a_functions.o), so I would expect to see a dependency like this:

    main.o: a.h
    

    So I suspect that you have some misplaced declarations.

  3. You declare an objectsrule, but never refer to it. So you never actually use it; Make uses the default rule for %.o: %.c. I suggest this:

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

    (In which case you can change $(EXEC_FILE): a_functions.o main.oto $(EXEC_FILE): $(OBJECTS).) Or just this:

    %.o: %.c
        $(CC) $< $(CFLAGS) -o $@
    
  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): %: %.c
        $(CC) $< $(CFLAGS) -o $@
    

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

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

回答by paxdiablo

Not sure if this is causing your specific problem but the two lines:

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

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

are definitely wrong, because there's generally no command to re-create a C file based on a header it includes.

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

C files don't depend on their header files, the objectscreated by those C files do.

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

For example, a main.cof:

例如,一个main.c

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

would be in the makefileas something like:

makefile像这样:

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

Change:

改变:

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

to:

到:

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

(assuming that a_functions.cincludes a.hand main.cincludes main.h) and try again.

(假设a_functions.c包含a.hmain.c包含main.h)并重试。

If that assumption above is wrong, you'll have to tell us what C files include what headers so we can tell you the correct rules.

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



If your contention is that the makefileis still building everything even after those changes, you need look at two things.

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

The first is the output from ls -lon all relevant files so that you can see what dates and times they have.

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

The second is the actual output from make. The output of make -dwill be especially helpful since it showswhat files and dates makeis using to figure out what to do.

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



In terms of investigation, makeseems to work fine as per the following transcript:

在调查方面,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.

回答by Owl

This very late after the fact, and actually it's based on paxdiablo's excellent answer, but while experimenting i found that you don't need separate targets for each .o file unless you're doing something clever.

事后很晚,实际上它基于paxdiablo的出色答案,但是在进行实验时,我发现除非您做一些聪明的事情,否则您不需要为每个 .o 文件设置单独的目标。

So for my makefile:

所以对于我的 makefile:

all: program

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

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

In make 4.1 it compiles the .o files automatically, you don't have to do anything if your .o files have the same names as your source files. So, it will go and hunt for a_functions.c, a_functions.h, main.h and main.c automagically. If you don't have the expected source code names, then you'll get an error like:

在 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.

I have also added a "clean" target for you. "Clean" is useful if you need to release your software as source code, or you just want to remove all the compiled object files and / or binaries.

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

And this is all you need to do.

这就是您需要做的全部。

Save this to "Makefile" and run:

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

$ make

to build your binary. And

构建你的二进制文件。和

$ make clean 

to clean up the compiled objects and binaries in your code.

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