Summary
How can you make ant repeatedly generate byte-identical jar files from the same .class files?
Background
Our build process does the following:
- gets web-services-definition (wsdl) files from another application’s source repository
- runs wsdl2java to generate .java file for use by web-service clients (i.e. our app)
- compiles the java files
- generates a .jar file from the compiler output
- 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:
- setting the timestamp to ‘0’ on all .class files before jarring
- 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.
Since a jar is just a zip file incognito, you could try using the
ziptask to add the manifest file underMETA-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.)