为什么“ make”中的增量构建不使用哈希算法?


10

我是的初学者,make我想知道何时使用make clean

一位同事告诉我,增量构建make基于文件时间戳。因此,如果您在VCS中签出文件的旧版本,则它将具有“旧”时间戳,并将其标记为“无需重新编译此文件”。然后,该文件将不会包含在下一个版本中。
根据同一位同事的说法,这是使用的理由make clean

无论如何,我make clean从其他StackExchange问​​题中大致得到了“何时使用” 问题的答案,但是我的另一个问题是:

为什么使用make依赖文件时间戳而不是例如SHA-1进行增量构建?例如,Git显示我们可以成功确定是否使用SHA-1修改了文件。
是为了速度问题吗?


5
make创建于70年代。SHA-1创建于90年代。Git创建于00年代。您想要做的最后一件事是,由于某人晦涩的构建工作了30年而突然失效,因为有人决定使用经过实践检验的系统将其全部现代化。
Ordous

1
一直在散列文件很慢。我认为git还使用文件系统元数据来优化其对已更改文件的检查。
CodesInChaos

4
原始的基于文件日期的解决方案非常简单,不需要任何其他文件来存储哈希码,并且在几十年中表现出色。为什么有人应该用更复杂的解决方案代替运作良好的解决方案?此外,AFAIK大多数VCS系统将签出的文件分配为“签出日期”,因此更改的文件将正确地导致重新编译而无需“清理”。
布朗

@Ordous:有趣,但是这里有用吗?软件不会生锈;它散发出来是因为有人改变了周围的环境。除非他们没有这样做,否则它仍然应该起作用。
罗伯特·哈维

1
@RobertHarvey当然是!当然,如果不更新您make的软件,则软件不会损坏,但是make会努力在新版本中向后兼容。无缘无故地改变核心行为与之相反。日期显示了为什么最初不使用SHA-1,或者为什么不容易对其进行改造(make当时已有数十年历史)。
Ordous

Answers:


7

一个明显的(可能是肤浅的)问题是,构建系统必须保留上一次构建所使用文件的哈希记录。尽管可以肯定地解决了这个问题,但是当文件系统中已经存在时间戳信息时,它将需要进行边存储。

不过,更严重的是,散列不会传达相同的语义。如果您知道文件T是由具有哈希H 1的依赖项D构建的,然后发现D现在哈希为H 2,是否应该重新构建T?可能是,但也可能是H 2实际上是指文件的较旧版本。时间戳定义顺序,而哈希仅在相等时可比较。

时间戳支持的功能是,您可以简单地更新时间戳(例如,使用POSIX命令行实用程序touch),以欺骗您make以为依赖关系已更改,或者-更有趣的是-目标是最新的比实际的要多。尽管玩这个游戏是一个绝佳的机会,可将自己打入脚下,但它有时会很有用。在基于哈希的系统中,您需要构建系统本身的支持来更新其用于上一构建的哈希的内部数据库,而无需实际构建任何内容。

尽管可以肯定地提出在时间戳上使用哈希的观点,但我的观点是,它们并不是实现相同目标的更好解决方案,而是实现不同目标的不同解决方案。这些目标中哪一个更可取可能尚有争议。


1
尽管哈希和时间戳之间的语义有所不同,但在这种情况下通常是无关紧要的,因为您很可能希望基于当前文件进行构建,而不论其年龄如何。
axl

您所说的大部分内容都是正确的。但是,使用Google blaze / bazel之类的哈希(内部版本的blaze,开源是bazel)的,实现良好的构建系统可以击败诸如Make之类的带有时间戳的系统。就是说,您确实必须在可重复的构建中付出很多努力,以便使用旧的构建工件而不是重新构建始终是安全的。
btilly '16

这里的映射不是多对一的,而是一对一的。如果D现在哈希到H2,并且您没有T2D@H2生成的输出,则需要生产和存储它。之后,无论DH1H2状态之间切换的顺序如何,您都可以使用缓存的输出。
Asad Saeeduddin

1

散列整个项目非常缓慢。您必须读取每个文件的每个字节。Git不会在每次运行一个文件时都对每个文件进行哈希处理git status。VCS检出通常也不会将文件的修改时间设置为原始创作时间。如果您愿意的话,可以进行备份还原。文件系统具有时间戳记的全部原因是针对此类用例。

make clean当Makefile未直接跟踪的依赖项发生更改时,开发人员通常会运行。具有讽刺意味的是,这通常包括Makefile本身。它通常还包括编译器版本。根据Makefile的编写方式,它可能包含外部库版本。

这些是在进行版本控制更新时往往会更新的事情,因此大多数开发人员只是养成同时运行A的习惯make clean,因此您知道自己是从全新的开始。您可以在很多时间不做的情况下逃脱,但是很难预测您无法做到的时间。


您可以使用ZFS这样的文件系统,在其中修改文件时会摊销哈希的费用,而不是在构建时一次付清所有费用。
Asad Saeeduddin

1

关于构建系统中哈希与时间戳的几点说明:

  1. 签出文件时,时间戳记应更新为当前时间,这会触发重建。您的同事所描述的通常不是时间戳系统的故障模式。
  2. 时间戳比哈希略快。时间戳系统仅需检查时间戳,而哈希系统必须先检查时间戳,然后再检查哈希。
  3. Make被设计为轻巧且独立的。为了克服(2),基于哈希的系统通常会运行后台进程以检查哈希(例如Facebook的Watchman)。这与Make的设计目标(和历史记录)相反。
  4. 当时间戳更改但内容没有更改时,哈希可防止不必要的重建。通常,这抵消了计算哈希的成本。
  5. 哈希使伪像缓存可以在项目之间和通过网络共享。同样,这不仅仅抵消了计算哈希的成本。
  6. 现代的基于哈希的构建系统包括Bazel(Google)和Buck(Facebook)。
  7. 大多数开发人员应考虑使用基于哈希的系统,因为它们与Make的设计要求不同。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.