避免使用 makefile 进行不必要的重新编译

Posted

技术标签:

【中文标题】避免使用 makefile 进行不必要的重新编译【英文标题】:Avoiding unecessary recompilation with makefile 【发布时间】:2015-02-27 19:28:51 【问题描述】:

我正在使用带有 gcc 的 makefile。每个 c 文件都有一个随附的标题:

main.c main.h test.c test.h

main.c 包括 main.h 和 test.h

test.c 包含 test.h

我想避免重新编译每个 c 文件。 Makefile 在没有 -B 参数的情况下运行。

我可以手动编写整个 makefile 并指定每个依赖项。编辑头文件时,仅重新编译必要的 c 文件。 test.h 中的编辑将重新编译这两个 c 文件,而 main.h 中的更改只会重新编译 main.c。应该的。

当我切换到更自动化的方法时,这不起作用:

OBJ = main.o test.o

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

main: $(OBJ)
    $(CC) -o main $(OBJ) 

test.h 中的更改只会重新编译 test.c。使用旧版本的 test.h 标头将 main.c 留在旧版本中。如果我想使用这种方法,我不得不使用 -B 运行 makefile。

我可以手动指定标题:

DEPS = main.h sort.h

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

然后在 main.h 中的更改重新编译 main.c 和 test.c,后者是不必要的。

如果我有很多文件,更新 makefile 中的每一个更改是很麻烦的,并且使用自动化方法会增加编译时间。

是否有更好的解决方案,仅重新编译所需文件,或者手动指定所有内容的唯一方法?

【问题讨论】:

查找 gcc 选项以根据包含文件输出 Makefile 依赖项。 make.mad-scientist.net/papers/… @chqrlie 抱歉,这对我来说是个死胡同,我是 make&gcc 的新手,因此在这里寻求建设性的答案。 如果您无法按照示例进行自动依赖跟踪,那么最后一段中您的问题的答案是“没有更好的解决方案(您能够实现),所以手动指定是唯一的方法”。 @MadScientist 不,我无法跟踪很长的外部链接,因为我不知道自动依赖跟踪具体是什么。这就是我在这里问的原因。我虽然这是一个问答网站。 【参考方案1】:

您可以使用另一行指定main.o 的其他依赖项:

OBJ = main.o test.o

main.o: test.h

【讨论】:

我得到一个错误:没有规则来制作目标'test.h','main.o'需要。停止 我从您的帖子中了解到,您有文件 main.hmain.ctest.htest.c。这不是真的吗? 没关系我有错字:-(。谢谢你这解决了我的问题。 请注意,如果您创建的 .c 文件没有使用相同前缀的关联头文件(例如,foo.c 但没有 foo.h),则此 makefile 将失败。 【参考方案2】:

但是,如果您决定手动指定,那么您做错了;您不想将依赖项添加到对 every 对象文件生效的模式中。您为每个目标文件单独定义它,因此只有在正确的文件发生更改时才会重新构建它们:

OBJ = main.o test.o

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

main: $(OBJ)
        $(CC) -o main $(OBJ)

main.o: main.h test.h
test.o: test.h

维护最后几行是自动生成依赖项所做的工作,如果您决定尝试使用它。

【讨论】:

这有点冗长,但更容易手动维护。这就是大多数人所做的,对于大多数项目来说已经足够了。一旦你掌握了 make 和 C 编译器,你就可以达到 Jedi 级别,可以自动计算行数。我花了 10 多年的时间才最终决定值得付出努力实现自动化。 另一个经常被忽视的依赖是%.o: %.c Makefile等。每当你改变Makefile时,重新编译所有东西是明智的,以防某些编译选项或命令行定义发生了变化。

以上是关于避免使用 makefile 进行不必要的重新编译的主要内容,如果未能解决你的问题,请参考以下文章

如何避免存储过程中不必要的重新编译?

make与makefile

如何避免使用自动工具重新编译不同路径中的不同目标?

如何使用带有 gprof 的 makefile 重新编译依赖项?

如何避免在反应功能组件中对“静态组件”进行不必要的重新渲染?

简介make命令和makefile文件