7

我的雇主有业务需要使 Java 构建逐字节可重复。我知道使 JAR 文件可重现的困难(由于归档顺序和时间戳),但此时我正在谈论类文件。

我在 Mac 和 Linux 上都使用 Java 8u65 构建了相同的代码。类文件是二进制不同的。两个类都反编译回相同的源;要查看差异需要 javap 反汇编程序。

源代码似乎是:

final TrustStrategy acceptingTrustStrategy =
              (X509Certificate[] chain, String authType) -> true;

在一个构建中,结果是:

private static boolean lambda$restTemplate$38(java.security.cert.X509Certificate[], java.lang.String) throws java.security.cert.CertificateException;
        Code:
           0: iconst_1
           1: ireturn
     

另一方面,它是:

private static boolean lambda$restTemplate$15(java.security.cert.X509Certificate[], java.lang.String) throws java.security.cert.CertificateException;
        Code:
           0: iconst_1
           1: ireturn

匿名 lambda 的名称中包含不同的数字(lambda$restTemplate$15lambda$restTemplate$38)。

看来,当我在同一台主机上重建时,我得到了相同的字节。当主机不同时,数字会改变;两个 Linux 主机产生不同的字节。

是什么决定了这些数字?有没有办法强制每个编译在这个地方使用相同的数字,从而产生相同的类文件?还是 Java 8 类文件编译不确定?

4

3 回答 3

3

lambda 表达式的计数由编译器完成,并在遇到其他 lambda 表达式时增加。

如果编译器以相同的顺序读取文件,它应该给出相同的编译类。

无论如何,由于您自己构建代码,您可以简单地将 lambda 表达式更改为匿名类声明。

编辑:我刚刚注意到你指出这些类是建立在两个不同的操作系统上的。这可能会在代码的编译阶段引入差异。为了获得可重现的构建,它必须在相同的架构上执行。您是否有理由无法将工件部署为构建在一个架构(MacOSLinux)上?

于 2019-03-15T02:45:20.873 回答
3

我没有过多地研究它,但是这篇文章讨论了 Java 中的可重现构建,并且reproducible-builds有一些工具可以尝试帮助使构建(和类)可重现。

您可能正在寻找的链接是Reproducible Build Maven Plugin,专为 Java 制作,以尝试“从生成的工件中剥离不可重现的数据”。

于 2019-03-15T02:27:23.967 回答
2

正如 DZone 文章中提到的,在 Major 的回答中链接,对于 gradle 这就是你所需要的:

tasks.withType(AbstractArchiveTask) {
    preserveFileTimestamps = false
    reproducibleFileOrder = true
}

将此添加到 后build.gradle,文件的 md5sum.jar在同一系统上的构建之间是稳定的。我无法使用其他系统进行测试,因为我询问的每个人都有不同的编译器版本,这使得构建不同。

于 2019-03-21T10:20:06.530 回答