为什么每次构建同一个 JAR 文件时都有不同的哈希值?
我一直在考虑检查jar文件的哈希值以确定它是否已更改,但事实证明,每次构建它时,相同的jar文件具有不同的哈希值(从eclipse导出为jar文件,或使用maven构建它)。我已经删除了清单文件的日期值和东西,但它仍然不同。字节码生成中是否有包含时间戳或其他内容的内容?
我一直在考虑检查jar文件的哈希值以确定它是否已更改,但事实证明,每次构建它时,相同的jar文件具有不同的哈希值(从eclipse导出为jar文件,或使用maven构建它)。我已经删除了清单文件的日期值和东西,但它仍然不同。字节码生成中是否有包含时间戳或其他内容的内容?
JAR 文件是一个 ZIP 文件,它在其本地文件头和中央目录文件头中包含上次修改日期。这将导致构建的不同哈希值。
如果对完全相同的文件集(具有相同的文件日期)运行 JAR 命令并跳过清单文件的创建,则它应该会为您提供完全相同的 JAR 文件(如果 ZIP 内文件的顺序没有变化)。
我在Gradle构建中遇到了同样的问题。在我的情况下,我的.war文件包含许多构建.jar文件。
在Gradle中,Jar和War任务本质上都是Zip任务的变体,Zip任务有一个名为“preserveFileTimestamps”(https://docs.gradle.org/current/dsl/org.gradle.api.tasks.bundling.Zip.html#org.gradle.api.tasks.bundling.Zip:preserveFileTimestamps)的属性要使SHA相同,请将此属性用于jar和war任务,例如,在build.gradle中的某个地方:
plugins.withType(WarPlugin).whenPluginAdded {
war {
preserveFileTimestamps = false
}
}
jar {
preserveFileTimestamps = false
}
另外有趣的是,如果您在MacOS上构建,请确保.DS_Store文件不会进入构建的存档,因为它也会导致不同的SHA。
要在 MacOS 上禁用,请在终端中运行以下命令:
defaults write com.apple.desktopservices DSDontWriteNetworkStores true
然后重新启动它。您仍然需要删除现有的.DS_Store文件,因此从项目文件夹中,运行:
find . -name '.DS_Store' -exec rm {} \;
如果你想使SHA即使在不同的操作系统上构建后也相同,那么对于war和jar任务,将属性设置为true,并确保在你构建的两个系统上都是相同的(显然,gradle包括war/jar文件中的文件属性,当这些属性不同时,我有不同的SHA)。reproducibleFileOrder
umask
最后,无论我在哪里构建,我都能够获得相同的SHA的工件。
干杯