ant 如何编译和 jar 字节相同的 jar 文件,即 MD5 匹配,除非 .java (以及 .class)发生变化?

发布于 2024-12-02 10:26:43 字数 1775 浏览 1 评论 0原文

总结

如何让 ant 从相同的 .class 文件中重复生成字节相同的 jar 文件?

背景

我们的构建过程执行以下操作:

  1. 从另一个应用程序的源存储库获取 Web 服务定义 (wsdl) 文件
  2. 运行 wsdl2java 以生成供 Web 服务客户端(即我们的应用程序)使用的 .java 文件
  3. 编译java 文件
  4. 从编译器输出生成 .jar 文件 将
  5. “artifact”jar 文件检查到源代码控制中

注意:我们执行最后一步,以便开发人员可以访问此 jar 文件,而无需自己构建它。我们使用特殊的“派生”目录来区分源和工件。

问题

我们无法让ant生成字节相同的.jar文件,即使源文件没有改变,即每个构建生成一个略有不同的jar(具有不同的MD5)

我检查了互联网并发现大约5年前的这个问题:

如果我编译一些代码并使用 ANT 创建一个 jar 和相关的 md5 文件 md5 文件中的校验和每次都不同,即使 代码没有改变。任何想法都可以解释为什么会这样 ?我怀疑某个地方有一些时间戳信息。

http://www.velocityreviews.com/forums/t150783- create-new-jar-same-code- different-md5.html

根据响应,我尝试了以下操作:

  1. 将所有时间戳设置为“0” .class 文件,然后在 jarring 之前
  2. 指定清单文件,并将该清单的时间戳设置为 0

[注意:第二步似乎无效。见下文]

每次构建后,.jar 文件仍然具有不同的 MD5 和。

CSI:Jar 文件

我已经解压并检查了这些 jar 的内容和时间戳,这些 jar 的内容和时间戳在“不同”jar 之间都匹配,但有一个例外:META-INF/MANIFEST.MF 的时间戳不同。

代码

   <-- touch classes and manifest to set consistent timestamp across builds -->
   <touch millis="0">
    <fileset dir="${mycompany.ws.classes.dir}"/>
   </touch>
   <touch millis="0" file="mymanifest.mf"/>

   <jar destfile="${derived.lib.dir}/mycompanyws.jar"
        manifest="mymanifest.mf"
        basedir="${mycompany.ws.classes.dir}"
        includes="**/com/mycompany/**,**/org/apache/xml/**" 
    />

其他选项

我们可以使用更高级的 ant 编程来仅检查 .jar 文件(如果 .java 文件已更改)。

Summary

How can you make ant repeatedly generate byte-identical jar files from the same .class files?

Background

Our build process does the following:

  1. gets web-services-definition (wsdl) files from another application's source repository
  2. runs wsdl2java to generate .java file for use by web-service clients (i.e. our app)
  3. compiles the java files
  4. generates a .jar file from the compiler output
  5. checks the 'artifact' jar file into source control

Note: We do this last step so developers have access to this jar file w/o building it themselves. We use a special 'derived' directory to distinguish source from artifacts.

The problem

We cannot get ant to generate byte-identical .jar files, even if the source files have not changed, i.e. each build generates a slightly different jar (with different MD5)

I checked the internet and found this question from some 5 years back:

If I compile some code and create a jar and related md5 file using ANT
the checksum in the md5 file is different everytime even though the
code hasn't changed. Any idea's why this is so how it can circumvented
? I suspect there is some timestamp information coming in somewhere.

http://www.velocityreviews.com/forums/t150783-creating-new-jar-same-code-different-md5.html

Per the responses, I've attempted the following:

  1. setting the timestamp to '0' on all .class files before jarring
  2. specifying a manifest file and also setting the timestamp to 0 for this manifest

[Note: this second step seems ineffective. See below]

After each build, the .jar file still has a different MD5 sum.

CSI: Jar file

I've unjarred and examined and the jars both contents and timestamps match between the "different" jars with one exception: different timestamps for META-INF/MANIFEST.MF.

Code

   <-- touch classes and manifest to set consistent timestamp across builds -->
   <touch millis="0">
    <fileset dir="${mycompany.ws.classes.dir}"/>
   </touch>
   <touch millis="0" file="mymanifest.mf"/>

   <jar destfile="${derived.lib.dir}/mycompanyws.jar"
        manifest="mymanifest.mf"
        basedir="${mycompany.ws.classes.dir}"
        includes="**/com/mycompany/**,**/org/apache/xml/**" 
    />

Other Options

We could use fancier ant programming to only check in the .jar file if the .java files have changed.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

泪冰清 2024-12-09 10:26:43

我也遇到过类似的问题,但略有不同。我决定在这里分享它,因为它与问题的主题相关。为了在不同的时间生成两个字节相同的数字签名 JAR 文件,必须考虑以下几点:

  • 时间戳: **/*。 class 文件必须具有相同的时间戳 (java.util.zip.ZipEntry.setTime(long))。此外,META-INF/MANIFEST.MF 文件和证书文件(*.RSA*.DSA*.SF) 被添加到带有“现在”时间戳的 JAR 文件中。因此,即使您决定不编译这些类并使用已编译的类(即具有原始 JAR 时间戳的类),您生成的 JAR 也将是二进制的不同。
  • MANIFEST.MF 条目排序: 请注意,MANIFEST.MF 文件中的键值对表示为 java.util .HashMap 其中“不保证顺序随着时间的推移保持不变。”。因此,在使用 JDK v5 和 JDK v6 jarsigner 工具签署 JAR 文件时,您可能会遇到另一个二进制差异,因为 MANIFEST.MF 条目的顺序可能会发生变化(http://stackoverflow.com/questions/1879897/order-of-items-in-a-hashmap-differ-when-the-same-program-is-run-in-jvm5-vs-jvm6)。

所以基本上有两个层面的问题。首先,JAR/ZIP 工具将文件及其文件系统时间戳打包,从而为同一组 Java 类创建二进制不同的 JAR 文件,这些文件是二进制相等的,但在不同时间编译。其次,JAR 签名者工具修改 META-INF/MANIFEST-MF 文件并将更多文件附加到 JAR 存档(证书和类文件校验和)。

该解决方案可能是自定义 JAR 签名者,它将所有 JAR 文件项的时间戳设置为恒定时间并对 MANIFEST.MF 文件条目进行排序(例如按字母表)。到目前为止,据我所知,这是在不同时间点生成两个字节相同的数字签名 JAR 文件的唯一方法。

I have been facing a similar problem, yet slightly different. I decided to share it here as it relates to the topic of the question. In order to produce two byte-identical digitally signed JAR files in a different time one has to take the following points to consideration:

  • Timestamps: **/*.class files have to have the same timestamp (java.util.zip.ZipEntry.setTime(long)). In addition, the META-INF/MANIFEST.MF file and the certificate files (*.RSA, *.DSA, and *.SF) are added to the JAR file with a "now" timestamp. So even if you decide not to compile the classes and use the ones already compiled (i.e. the ones with the original JAR's timestamp), your resulting JAR will be binary different.
  • MANIFEST.MF Entries Ordering: Note that the key-value pairs in the MANIFEST.MF file are represented as a java.util.HashMap which "does not guarantee that the order will remain constant over time.". So you may run into another binary difference when signing the JAR files using JDK v5 and JDK v6 jarsigner tool as the order of the MANIFEST.MF entries may change (http://stackoverflow.com/questions/1879897/order-of-items-in-a-hashmap-differ-when-the-same-program-is-run-in-jvm5-vs-jvm6).

So basically there are two levels of the problem. Firstly, the JAR/ZIP tool that packages the files with their file-system timestamps and, thus, creates binary different JAR files for the same set of Java classes that are binary equal, but were compiled in a different time. Secondly, the JAR signer tool that modifies the META-INF/MANIFEST-MF file and appends more files to the JAR archive (certificates and class file check-sums).

The solution maybe a custom JAR signer, that sets the timestamps of all the JAR file items to a constant time and orders the MANIFEST.MF file entries (e.g. by alphabet). So far, this is, according to my knowledge, the only way to producing two byte-identical digitally signed JAR files in different time points.

一刻暧昧 2024-12-09 10:26:43

由于 jar 只是一个隐身的 zip 文件,您可以尝试使用 zip 任务手动在 META-INF/ 下添加清单文件。希望这可以避免与通过 jar 任务处理清单相关的任何内部魔法。

只是一个旁注,因为听起来具有相等的 MD5 是至关重要的,所以我建议您添加健全性测试作为构建的一部分,例如编译一些永远不会更改为 jar 的特殊“虚拟”代码,并检查 jar MD5 是否等于所期望的那个。这将保护构建免受意外更改的影响(例如,升级到 ant、JRE、操作系统、时区更改等后)

Since a jar is just a zip file incognito, you could try using the zip task to add the manifest file under META-INF/ by hand. Hopefully that circumvents any internal magic associated with handling the manifest by the jar task.

Just an side note, since it sounds like having equal MD5s is critical, I would recommend you add a sanity test as part of the build, such as compile some special "dummy" code that never changes into a jar and check the jar MD5 equals the one expected. This will safeguard the build against unexpected changes (e.g. after an upgrade to ant, JRE, OS, timezone change etc.)

可可 2024-12-09 10:26:43

遇到同样的问题,登陆此页面。 Jiri Patera 的上述答案非常有助于理解为什么在取消签名和重新签名 jar 文件后我无法获得我期望的两个相同文件的 md5sums。

这是我使用的解决方案:

jar -tvf $JARFILE | grep -v 元信息 | perl -p -e's/^\s+(\d+).*\s+([\w]+)/$1 $2/g' | md5sum

它并不能 100% 确定这些罐子是等效的,但它给出了相当可靠的指示。

它获取 jarfile 中所有文件的列表(减去 META_INF 文件),解析出文件大小和文件名,然后通过 md5sum 算法运行文件大小和文件名的文本。

Had this same problem, landed on this page. The answer above by Jiri Patera was very helpful in understanding why I could not get the md5sums of what I expected to be two identical files to be the same after unsigning and resigning the jar files.

This is the solution I used instead:

jar -tvf $JARFILE | grep -v META-INF | perl -p -e's/^\s+(\d+).*\s+([\w]+)/$1 $2/g' | md5sum

It doesn't give 100% certainty that the jars are equivalent but it gives a fairly reliable indication.

It takes a listing of all the files in the jarfile minus the META_INF files, parses out file size and file name, and then runs the text of filesizes plus filenames thru the md5sum algorithm.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文