GNU make 如何管理文件版本控制?

Posted

技术标签:

【中文标题】GNU make 如何管理文件版本控制?【英文标题】:How GNU make manages file version control? 【发布时间】:2018-09-06 02:53:33 【问题描述】:

我正在学习 GNU make 。假设我有一个 hello_world.c 文件和一个 Makefile:hello_world.c:

#include <stdio.h>                        

int main()                               
        printf("Hello World!\n");  
        return 0;                         
 

生成文件:

hello: hello_world.c
        gcc hello_world.c -o hello_world

现在,我认为hello 是我的目标,hello_world.c 是它的依赖项。如果 make 以某种方式检测到 hello_world.c 比它的目标文件更新,它会执行相应的命令。

1-make 如何管理文件版本控制以及它如何检测比其他内容更新并需要更新的内容?2- 如果我使用编辑器更改hello_world.o 并损坏文件,它显然不会执行,但make hello 报告无需执行任何操作! 我的意思是,make 只检查了依赖项是否比目标更旧并且什么都不做就退出了。我认为它应该检测到该目标不是与其最新调用对应的目标。不知何故,它应该比较“依赖和目标的组合”历史,而不是仅仅比较依赖的历史 w.r.t。 target.3- 这是make的限制吗?我该如何规避这个问题?因为可能有一些外部应用程序弄乱了我的 make 操作的目标。

【问题讨论】:

试着让你的 Makefile 变成一行:hello: hello_world.o 【参考方案1】:

1- make 如何管理文件版本控制以及它如何检测比其他内容更新并需要更新的内容?

您已经知道这个问题的答案。您在下一段中说过:“我的意思是,make 只检查了依赖项是否比目标更旧并且什么也不做。”这是正确的。 make 当目标的依赖更新时更新依赖的目标。

2- 如果我使用编辑器更改hello_world.o 并损坏文件,它显然不会执行,但make hello 报告无需执行任何操作!我的意思是,make 只检查了依赖项是否比目标更旧并且什么都不做就退出了。我认为它应该检测到该目标不是与其最新调用对应的目标。不知何故,它应该比较“依赖和目标的组合”历史,而不是仅仅比较依赖的历史 w.r.t。目标。

您要求make 做的比它打算做的要多得多。

3- 这是make的限制吗?我该如何规避这个问题?因为可能有一些外部应用程序弄乱了我的 make 操作的目标。

从您的角度来看,这似乎是make 的限制。但是,我想指出您正在通过手动更新目标来破坏make 的工作。

你怎么能绕过它?

    不要手动修改由make构建的目标。

    手动更新其中一个依赖项的时间戳,然后运行make。为此,您可以使用命令touch

    提供一个名为clean 的虚拟目标,它将删除所有相关目标。然后,运行make clean,然后运行make

    提供一个名为 rebuild 的虚拟目标。强制构建您需要在该目标中构建的任何内容。然后,运行make rebuild

【讨论】:

所以最保守的解决方案是make rebuild,它没有任何依赖关系,无论如何都简单地执行所有其他规则的命令?这和我们在 IDE 中点击重建项目是一样的吗? @Zeta.Investigator。是的。但是,您可以通过在该目标下执行 make cleanmake 作为唯一命令来减少 Makefile 中的代码重复。 @Zeta.Investigator 您的 makefile 不会生成 .o 文件,因此您无法手动编辑该不存在的文件,因为您要求编译器直接创建可执行文件。你描述的问题只是没有发生。如果您通过hello: hello_world.ohello_world.o: hello_world.cpp 更改依赖关系,然后编辑hello_world.o,GNU Make 将执行hello: hello_world.o 的配方(再次进行链接)。【参考方案2】:

make 程序只是比较目标文件 (hello) 和依赖文件 (hello_world.c) 的修改时间戳。

如果依赖文件的时间戳比目标文件新,则执行命令。

【讨论】:

好的,关于 2 和 3 有什么想法吗?【参考方案3】:

make 如何管理文件版本控制以及它如何检测到某些内容比其他内容更新并需要更新?

很简单:make 不关心文件版本。

只需通过比较文件系统中的时间戳来检测某项是否比其他项更新。

如果我使用编辑器更改 hello_world.o 并损坏文件,它显然不会执行,但会发出 hello 报告,无需执行任何操作!我的意思是,make 只检查依赖项是否比目标更旧并且什么也不做。我认为它应该检测到该目标不是与其最新调用对应的目标。不知何故,它应该比较“依赖和目标的组合”历史,而不是仅仅比较依赖的历史 w.r.t。目标。

您没有告诉make 任何有关您的 .o 文件的信息。为什么make 应该检查该文件的时间戳? 检查依赖关系正是make 所期望的。 如果你不告诉它,这个工具怎么可能知道这个过程涉及到一个名为hello_world.o 的文件?没有魔法发生,只是遵循 Makefile 的规则。

这是make的限制吗?我该如何规避这个问题?因为可能有一些外部应用程序弄乱了我的 make 操作的目标。

您可以指定分层依赖关系:

all: hello

hello: hello_world.o
    <gcc linker command...>

hello_world.o: hello_world.c
    gcc hello_world.c -o hello_world

【讨论】:

所以在你提议的 Makefile 中,如果我损坏了 hello_world.o,make 首先查看所有内容,然后查看 hello,然后检查 hello_world.o 是否比 hello 更新?但是 hello 本身并不是一个文件…… 损坏不是源文件的文件是个坏主意。当然,它们不是从源重新创建的,导致链接器错误等。您应该将输出文件定义为目标。否则应该比较哪个文件作为重建的参考? 如果 make 以某种方式保存了文件哈希的副本,或者像 git 那样做了一些 vc,它本可以完成我的请求,对吧? 你在混合工具。 Make 既不是数据库,也不是 VC 系统。它是完全在 Makefile 中指定的依赖项的扫描器。您可以指定正确的依赖关系和规则。 “它本可以满足我的要求,对吧?”是的,完全不同的工具可以处理您的请求。

以上是关于GNU make 如何管理文件版本控制?的主要内容,如果未能解决你的问题,请参考以下文章

版本控制git第一篇

gcc make和gnu make的区别,一般是用哪个?

Git教程首页

Git的使用

Ubuntu下安装make

.o文件或构建版本控制的最佳实践是什么?