[PATCH 0/8] Towards reproducible openjdk

OpenSubmitted by dannym.
Details
2 participants
  • dannym
  • Maxime Devos
Owner
unassigned
Severity
normal
D
D
dannym wrote on 1 Jun 14:57 +0200
(address . guix-patches@gnu.org)(name . Danny Milosavljevic)(address . dannym@scratchpost.org)
20220601125741.9898-1-dannym@scratchpost.org
From: Danny Milosavljevic <dannym@scratchpost.org>

This patchseries improves the reproducibility of openjdk.

After it:
* openjdk9 is reproducible.
* openjdk10 has only a few non-reproducible parts.
* openjdk11 has a number of non-reproducible parts.
* openjdk12's "doc" output is still not reproducible ("Generated by javadoc" comment with timestamp in it)
* openjdk13 still has non-reproducible parts (jmod, modules, classes.jsa, src.zip)
* openjdk14 still has very few non-reproducible parts (jmod, modules, classes.jsa)
* openjdk15 still has a number of non-reproducible parts (diz files only).
* openjdk16 still has one non-reproducible part (classes*.jsa)

Danny Milosavljevic (8):
gnu: openjdk9: Make build reproducible.
gnu: openjdk10: Make more reproducible.
gnu: openjdk11: Make more reproducible.
gnu: openjdk12: Make reproducible.
gnu: openjdk13: Make reproducible.
gnu: openjdk14: Make reproducible.
gnu: openjdk15: Make reproducible.
gnu: openjdk16: Make reproducible.

gnu/local.mk | 16 +
gnu/packages/java.scm | 123 ++++++-
.../openjdk-10-char-reproducibility.patch | 12 +
...openjdk-10-classlist-reproducibility.patch | 27 ++
.../openjdk-10-corba-reproducibility.patch | 12 +
.../openjdk-10-jar-reproducibility.patch | 103 ++++++
.../openjdk-10-jtask-reproducibility.patch | 53 +++
.../openjdk-10-module-reproducibility.patch | 305 ++++++++++++++++++
.../openjdk-10-module3-reproducibility.patch | 34 ++
.../openjdk-10-module4-reproducibility.patch | 14 +
...openjdk-11-classlist-reproducibility.patch | 11 +
...openjdk-13-classlist-reproducibility.patch | 11 +
.../openjdk-9-classlist-reproducibility.patch | 31 ++
.../openjdk-9-idlj-reproducibility.patch | 37 +++
.../openjdk-9-jar-reproducibility.patch | 107 ++++++
.../openjdk-9-module-reproducibility.patch | 296 +++++++++++++++++
.../openjdk-9-module2-reproducibility.patch | 125 +++++++
.../openjdk-9-module3-reproducibility.patch | 36 +++
18 files changed, 1342 insertions(+), 11 deletions(-)
create mode 100644 gnu/packages/patches/openjdk-10-char-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-10-classlist-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-10-corba-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-10-jar-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-10-jtask-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-10-module-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-10-module3-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-10-module4-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-11-classlist-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-13-classlist-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-9-classlist-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-9-idlj-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-9-jar-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-9-module-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-9-module2-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-9-module3-reproducibility.patch

--
2.36.1
D
D
dannym wrote on 1 Jun 15:00 +0200
[PATCH 1/8] gnu: openjdk9: Make build reproducible.
(address . 55751@debbugs.gnu.org)(name . Danny Milosavljevic)(address . dannym@scratchpost.org)
20220601130011.9910-2-dannym@scratchpost.org
From: Danny Milosavljevic <dannym@scratchpost.org>

* gnu/packages/patches/openjdk-9-classlist-reproducibility.patch: New file.
* gnu/packages/patches/openjdk-9-jar-reproducibility.patch: New file.
* gnu/packages/patches/openjdk-9-module-reproducibility.patch: New file.
* gnu/packages/patches/openjdk-9-module2-reproducibility.patch: New file.
* gnu/packages/patches/openjdk-9-module3-reproducibility.patch: New file.
* gnu/packages/patches/openjdk-9-idlj-reproducibility.patch: New file.
* gnu/packages/java.scm (openjdk9)[source]: Add patches.
[arguments]<#:phases>[strip-zip-timestamps]: Modify.
* gnu/local/mk (dist_patch_DATA): Add patches.
---
gnu/local.mk | 6 +
gnu/packages/java.scm | 61 +++-
.../openjdk-9-classlist-reproducibility.patch | 31 ++
.../openjdk-9-idlj-reproducibility.patch | 37 +++
.../openjdk-9-jar-reproducibility.patch | 107 +++++++
.../openjdk-9-module-reproducibility.patch | 296 ++++++++++++++++++
.../openjdk-9-module2-reproducibility.patch | 125 ++++++++
.../openjdk-9-module3-reproducibility.patch | 36 +++
8 files changed, 692 insertions(+), 7 deletions(-)
create mode 100644 gnu/packages/patches/openjdk-9-classlist-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-9-idlj-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-9-jar-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-9-module-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-9-module2-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-9-module3-reproducibility.patch

Toggle diff (779 lines)
diff --git a/gnu/local.mk b/gnu/local.mk
index bc82c5ba9f..5ba5af94a6 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -1567,6 +1567,12 @@ dist_patch_DATA =						\
   %D%/packages/patches/openboardview-use-system-utf8.patch	\
   %D%/packages/patches/opencascade-oce-glibc-2.26.patch		\
   %D%/packages/patches/openfoam-4.1-cleanup.patch			\
+  %D%/packages/patches/openjdk-9-classlist-reproducibility.patch	\
+  %D%/packages/patches/openjdk-9-idlj-reproducibility.patch	\
+  %D%/packages/patches/openjdk-9-jar-reproducibility.patch	\
+  %D%/packages/patches/openjdk-9-module-reproducibility.patch	\
+  %D%/packages/patches/openjdk-9-module2-reproducibility.patch	\
+  %D%/packages/patches/openjdk-9-module3-reproducibility.patch	\
   %D%/packages/patches/openjdk-10-idlj-reproducibility.patch	\
   %D%/packages/patches/openjdk-15-xcursor-no-dynamic.patch	\
   %D%/packages/patches/openmpi-mtl-priorities.patch		\
diff --git a/gnu/packages/java.scm b/gnu/packages/java.scm
index 336e84e3e5..3d36849f7d 100644
--- a/gnu/packages/java.scm
+++ b/gnu/packages/java.scm
@@ -1526,7 +1526,16 @@ (define-public openjdk9
               (sha256
                (base32
                 "01ihmyf7k5z17wbr7xig7y40l9f01d5zjgkcmawn1102hw5kchpq"))
-              (modules '((guix build utils)))
+              (patches
+                (search-patches "openjdk-9-classlist-reproducibility.patch"
+                                "openjdk-9-jar-reproducibility.patch"
+                                "openjdk-9-module-reproducibility.patch"
+                                "openjdk-9-module2-reproducibility.patch"
+                                "openjdk-9-module3-reproducibility.patch"
+                                "openjdk-9-idlj-reproducibility.patch"))
+              (modules '((guix build utils)
+                         (srfi srfi-35)
+                         (ice-9 binary-ports)))
               (snippet
                `(begin
                   (for-each delete-file
@@ -1539,6 +1548,7 @@ (define-public openjdk9
        #:make-flags '("all")
        #:imported-modules
        ((guix build syscalls)
+        (srfi srfi-35)
         ,@%gnu-build-system-modules)
 
        #:disallowed-references ,(list (gexp-input icedtea-8)
@@ -1658,18 +1668,55 @@ (define (icedtea-or-openjdk? path)
              (for-each (lambda (zip)
                          (let ((dir (mkdtemp! "zip-contents.XXXXXX")))
                            (with-directory-excursion dir
-                             (invoke "unzip" zip))
+                             (let ((code (system* "unzip" "--" zip)))
+                               (write code)
+                               (newline)
+                               (when (> (status:exit-val code) 1) ; 1 is just a warning
+                                 (raise (condition (&invoke-error
+                                                    (program "unzip")
+                                                    (arguments (list "--" zip))
+                                                    (exit-status (status:exit-val code))
+                                                    (term-signal (status:term-sig code))
+                                                    (stop-signal (status:stop-sig code))))))))
                            (delete-file zip)
                            (for-each (lambda (file)
                                        (let ((s (lstat file)))
-                                         (unless (eq? (stat:type s) 'symlink)
                                            (format #t "reset ~a~%" file)
-                                           (utime file 0 0 0 0))))
+                                           (utime file 1 1 0 0
+                                                       AT_SYMLINK_NOFOLLOW)))
                                      (find-files dir #:directories? #t))
                            (with-directory-excursion dir
-                             (let ((files (find-files "." ".*" #:directories? #t)))
-                               (apply invoke "zip" "-0" "-X" zip files)))))
-                       (find-files (assoc-ref outputs "doc") ".*.zip$"))
+                             (let ((files (cons "./META-INF/MANIFEST.MF"
+                                                (append (find-files "./META-INF" ".*")
+                                                        ;; for jmod:
+                                                        (list "./classes/module-info.class")
+                                                        (find-files "." ".*")))))
+                               (apply invoke "zip" "--symlinks" "-0" "-X" zip files)
+                               (when (string-suffix? ".jmod" zip)
+                                 (let ((new-zip (string-append zip "n"))
+                                       (contents (call-with-input-file zip
+                                                   (@ (ice-9 binary-ports) get-bytevector-all))))
+                                   (call-with-output-file new-zip
+                                     (lambda (output-port)
+                                       ((@ (ice-9 binary-ports) put-bytevector) output-port
+                                                       #vu8(#x4a #x4d #x01 #x00)) ; JM
+                                       ((@ (ice-9 binary-ports) put-bytevector) output-port
+                                                       contents)))
+                                   (rename-file new-zip zip)))))))
+                       (append (find-files (string-append
+                                            (assoc-ref outputs "doc")
+                                            "/api")
+                                           "\\.zip$")
+                               (find-files (assoc-ref outputs "doc") "src\\.zip$")
+                               (find-files (assoc-ref outputs "jdk") "src\\.zip$")
+                               (find-files (assoc-ref outputs "jdk") "\\.jmod$")
+                               (find-files (assoc-ref outputs "jdk") "\\.diz$")
+                               (find-files (assoc-ref outputs "out") "\\.diz$")
+
+                               (list (string-append (assoc-ref outputs "jdk") "/lib/jrt-fs.jar"))
+                               (find-files (string-append (assoc-ref outputs "jdk")
+                                                          "/demo")
+                                           "\\.jar$")))
              #t)))))
     (inputs
      `(("alsa-lib" ,alsa-lib)
diff --git a/gnu/packages/patches/openjdk-9-classlist-reproducibility.patch b/gnu/packages/patches/openjdk-9-classlist-reproducibility.patch
new file mode 100644
index 0000000000..d0ce7bc4d6
--- /dev/null
+++ b/gnu/packages/patches/openjdk-9-classlist-reproducibility.patch
@@ -0,0 +1,31 @@
+From: Danny Milosavljevic <dannym@scratchpost.org>
+Date: Wed, 18 Apr 2022 18:38:28 +0100
+Subject: Make classlist reproducible
+
+--- jdk-09/make/GenerateLinkOptData.gmk.orig	2022-04-05 10:05:35.892134188 +0200
++++ jdk-09/make/GenerateLinkOptData.gmk	2022-04-05 10:06:07.885003056 +0200
+@@ -61,11 +61,12 @@
+ 	$(call MakeDir, $(LINK_OPT_DIR))
+ 	$(call LogInfo, Generating $(patsubst $(OUTPUT_ROOT)/%, %, $@))
+ 	$(call LogInfo, Generating $(patsubst $(OUTPUT_ROOT)/%, %, $(JLI_TRACE_FILE)))
+-	$(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -XX:DumpLoadedClassList=$@ \
++	$(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -XX:DumpLoadedClassList=$@.tmp \
+ 	    -Djava.lang.invoke.MethodHandle.TRACE_RESOLVE=true \
+ 	    -cp $(SUPPORT_OUTPUTDIR)/classlist.jar \
+ 	    build.tools.classlist.HelloClasslist \
+ 	    $(LOG_DEBUG) 2>&1 > $(JLI_TRACE_FILE)
++	sort $@.tmp >$@
+ 
+ # The jli trace is created by the same recipe as classlist. By declaring these
+ # dependencies, make will correctly rebuild both jli trace and classlist
+--- jdk-09/langtools/make/gendata/Gendata-jdk.compiler.gmk.orig	2022-04-08 22:04:05.784424812 +0200
++++ jdk-09/langtools/make/gendata/Gendata-jdk.compiler.gmk	2022-04-08 22:09:36.333575143 +0200
+@@ -79,6 +79,8 @@
+ 	    $(CT_MODULESOURCEPATH) \
+ 	    $(CT_MODULES) \
+ 	    >$(@D)/9/system-modules
++	# Make files reproducible
++	find $(@D) -exec $(TOUCH) -h -c -t 197001010000.01 {} \;
+ 	$(TOUCH) $@
+ 
+ # Can't generate ct.sym directly into modules libs as the SetupJarArchive macro
diff --git a/gnu/packages/patches/openjdk-9-idlj-reproducibility.patch b/gnu/packages/patches/openjdk-9-idlj-reproducibility.patch
new file mode 100644
index 0000000000..30dcdf2496
--- /dev/null
+++ b/gnu/packages/patches/openjdk-9-idlj-reproducibility.patch
@@ -0,0 +1,37 @@
+From: Danny Milosavljevic <dannym@scratchpost.org>
+Date: Wed, 18 Apr 2022 19:28:00 +0100
+Subject: Make IDL reproducible
+
+--- jdk-09/corba/src/java.corba/share/classes/com/sun/tools/corba/se/idl/toJavaPortable/Util.java.orig	2022-04-05 02:46:26.805340292 +0200
++++ jdk-09/corba/src/java.corba/share/classes/com/sun/tools/corba/se/idl/toJavaPortable/Util.java	2022-04-05 02:48:23.152494213 +0200
+@@ -1146,7 +1146,7 @@
+     else
+       formatter.setTimeZone (java.util.TimeZone.getDefault ());
+ 
+-    stream.println ("* " + formatter.format (new Date ()));
++    stream.println ("* " + formatter.format (System.getenv("SOURCE_DATE_EPOCH") == null ? new Date () : new Date(1000 * Long.parseLong(System.getenv("SOURCE_DATE_EPOCH")))));
+ 
+     // <daz>
+     ///////////////
+--- jdk-09/corba/make/src/classes/build/tools/logutil/MC.java.orig	2022-04-05 11:09:43.824720493 +0200
++++ jdk-09/corba/make/src/classes/build/tools/logutil/MC.java	2022-04-05 11:10:46.518435511 +0200
+@@ -154,7 +154,7 @@
+                   groupName);
+     pw.println("//");
+     pw.printMsg("// Generated by MC.java version @, DO NOT EDIT BY HAND!", VERSION);
+-    pw.printMsg("// Generated from input file @ on @", inFile, new Date());
++    pw.printMsg("// Generated from input file @ on @", inFile, System.getenv("SOURCE_DATE_EPOCH") == null ? new Date() : new Date(1000 * Long.parseLong(System.getenv("SOURCE_DATE_EPOCH"))));
+     pw.println();
+   }
+ 
+--- jdk-09/jdk/make/src/classes/build/tools/generatecharacter/GenerateCharacter.java.orig	2022-04-05 11:14:29.228526408 +0200
++++ jdk-09/jdk/make/src/classes/build/tools/generatecharacter/GenerateCharacter.java	2022-04-05 11:15:32.658260748 +0200
+@@ -693,7 +693,7 @@
+         PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(theOutputFileName)));
+         out.println(commentStart +
+             " This file was generated AUTOMATICALLY from a template file " +
+-            new java.util.Date() + commentEnd);
++            (System.getenv("SOURCE_DATE_EPOCH") == null ? new java.util.Date() : new java.util.Date(1000 * Long.parseLong(System.getenv("SOURCE_DATE_EPOCH")))) + commentEnd);
+         int marklen = commandMarker.length();
+         LOOP: while(true) {
+             try {
diff --git a/gnu/packages/patches/openjdk-9-jar-reproducibility.patch b/gnu/packages/patches/openjdk-9-jar-reproducibility.patch
new file mode 100644
index 0000000000..130eacd867
--- /dev/null
+++ b/gnu/packages/patches/openjdk-9-jar-reproducibility.patch
@@ -0,0 +1,107 @@
+From: Danny Milosavljevic <dannym@scratchpost.org>
+Date: Wed, 18 Apr 2022 20:10:01 +0100
+Subject: Make JARs reproducible
+
+--- jdk-09/make/common/JarArchive.gmk.orig	2022-04-08 21:56:04.075111687 +0200
++++ jdk-09/make/common/JarArchive.gmk	2022-04-11 00:49:16.809140388 +0200
+@@ -249,12 +249,16 @@
+ 	    $(ECHO) "Main-Class: $$(strip $$($1_JARMAIN))" >> $$($1_MANIFEST_FILE) $$(NEWLINE)) \
+ 	  $$(if $$($1_EXTRA_MANIFEST_ATTR), \
+ 	    $(PRINTF) "$$($1_EXTRA_MANIFEST_ATTR)\n" >> $$($1_MANIFEST_FILE) $$(NEWLINE)) \
+-	  $(ECHO) Creating $$($1_NAME) $$(NEWLINE) \
++	  $(TOUCH) -h -c -t 197001010000.00 $$($1_MANIFEST_FILE) $$(NEWLINE) \
++	  $(ECHO) XCreating $$($1_NAME) $(JAR) $$($1_JAR_CREATE_OPTIONS) $$@ $$($1_MANIFEST_FILE) $$(NEWLINE) \
+ 	  $(JAR) $$($1_JAR_CREATE_OPTIONS) $$@ $$($1_MANIFEST_FILE) $$(NEWLINE) \
+ 	  $$($1_SCAPTURE_CONTENTS) \
+ 	  $$($1_SCAPTURE_METAINF) \
+ 	  $$($1_SUPDATE_CONTENTS) \
+-	  $$($1_JARINDEX) && true \
++	  $$($1_JARINDEX) && true $$(NEWLINE) \
++	  $(ECHO) Kreppel2 $$@ $$(NEWLINE) \
++	  unzip -v $$@ $$(NEWLINE) \
++	  d="`mktemp -d`" && $(CP) -f $$@ "$$$$d/a.jar" && (cd "$$$$d" && unzip a.jar META-INF/MANIFEST.MF && $(TOUCH) -h -c -t 197001010000.00 META-INF &&  $(TOUCH) -h -c -t 197001010000.00 META-INF/MANIFEST.MF && (zip --symlinks -0 -X a.jar META-INF META-INF/MANIFEST.MF; zip --symlinks -0 -X a.jar META-INF META-INF/MANIFEST.MF)) && $(CP) -f "$$$$d/a.jar" $$@ \
+ 	, \
+ 	  $(ECHO) Modifying $$($1_NAME) $$(NEWLINE) \
+ 	  $$($1_CAPTURE_CONTENTS) \
+--- jdk-09/make/JrtfsJar.gmk.orig	2022-04-10 13:48:57.385120008 +0200
++++ jdk-09/make/JrtfsJar.gmk	2022-04-10 13:58:04.688158538 +0200
+@@ -57,13 +57,18 @@
+ # file will not be copied unless META-INF/services would also be added to the INCLUDES.
+ # Adding META-INF/services would include all files in that directory when only the one
+ # is needed, which is why this explicit copy is defined instead.
+-$(eval $(call SetupCopyFiles, COPY_JIMAGE_SERVICE_PROVIDER, \
++$(eval $(call SetupCopyFiles, COPY_JIMAGE_SERVICE_PROVIDER1, \
+     SRC := $(JDK_TOPDIR)/src/java.base/share/classes, \
+     DEST := $(SUPPORT_OUTPUTDIR)/jrtfs_classes, \
+     FILES := META-INF/services/java.nio.file.spi.FileSystemProvider))
+ 
++.PHONY: jrtfsfixtimestamps47
++jrtfsfixtimestamps47: $(COPY_JIMAGE_SERVICE_PROVIDER1)
++	find $(SUPPORT_OUTPUTDIR)/jrtfs_classes -exec $(TOUCH) -h -c -t 197001010000.00 {} \;
++	$(TOUCH) -h -c -t 197001010000.00 $(SUPPORT_OUTPUTDIR)/java-main-manifest.mf
++
+ $(eval $(call SetupJarArchive,BUILD_JRTFS_JAR, \
+-    DEPENDENCIES := $(BUILD_JRTFS) $(COPY_JIMAGE_SERVICE_PROVIDER), \
++    DEPENDENCIES := $(BUILD_JRTFS) jrtfsfixtimestamps47, \
+     SRCS := $(SUPPORT_OUTPUTDIR)/jrtfs_classes, \
+     JAR := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/jrt-fs.jar, \
+     MANIFEST := $(SUPPORT_OUTPUTDIR)/java-main-manifest.mf, \
+--- jdk-09/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java.orig	2022-04-10 02:05:50.983247794 +0200
++++ jdk-09/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	2022-04-10 02:13:01.638960337 +0200
+@@ -850,12 +850,18 @@
+                     output(getMsg("out.added.manifest"));
+                 }
+                 ZipEntry e = new ZipEntry(MANIFEST_DIR);
+-                e.setTime(System.currentTimeMillis());
++                if (System.getenv("SOURCE_DATE_EPOCH") != null)
++                    e.setTime(1000 * Long.parseLong(System.getenv("SOURCE_DATE_EPOCH")));
++                else
++                    e.setTime(System.currentTimeMillis());
+                 e.setSize(0);
+                 e.setCrc(0);
+                 zos.putNextEntry(e);
+                 e = new ZipEntry(MANIFEST_NAME);
+-                e.setTime(System.currentTimeMillis());
++                if (System.getenv("SOURCE_DATE_EPOCH") != null)
++                    e.setTime(1000 * Long.parseLong(System.getenv("SOURCE_DATE_EPOCH")));
++                else
++                    e.setTime(System.currentTimeMillis());
+                 if (flag0) {
+                     crc32Manifest(e, manifest);
+                 }
+@@ -1022,7 +1028,10 @@
+         throws IOException
+     {
+         ZipEntry e = new ZipEntry(INDEX_NAME);
+-        e.setTime(System.currentTimeMillis());
++        if (System.getenv("SOURCE_DATE_EPOCH") != null)
++            e.setTime(1000 * Long.parseLong(System.getenv("SOURCE_DATE_EPOCH")));
++        else
++            e.setTime(System.currentTimeMillis());
+         if (flag0) {
+             CRC32OutputStream os = new CRC32OutputStream();
+             index.write(os);
+@@ -1041,7 +1050,10 @@
+             String name = mi.getKey();
+             byte[] bytes = mi.getValue();
+             ZipEntry e = new ZipEntry(name);
+-            e.setTime(System.currentTimeMillis());
++            if (System.getenv("SOURCE_DATE_EPOCH") != null)
++                e.setTime(1000 * Long.parseLong(System.getenv("SOURCE_DATE_EPOCH")));
++            else
++                e.setTime(System.currentTimeMillis());
+             if (flag0) {
+                 crc32ModuleInfo(e, bytes);
+             }
+@@ -1066,7 +1078,10 @@
+             addMultiRelease(m);
+         }
+         ZipEntry e = new ZipEntry(MANIFEST_NAME);
+-        e.setTime(System.currentTimeMillis());
++        if (System.getenv("SOURCE_DATE_EPOCH") != null)
++            e.setTime(1000 * Long.parseLong(System.getenv("SOURCE_DATE_EPOCH")));
++        else
++            e.setTime(System.currentTimeMillis());
+         if (flag0) {
+             crc32Manifest(e, m);
+         }
diff --git a/gnu/packages/patches/openjdk-9-module-reproducibility.patch b/gnu/packages/patches/openjdk-9-module-reproducibility.patch
new file mode 100644
index 0000000000..80b6808395
--- /dev/null
+++ b/gnu/packages/patches/openjdk-9-module-reproducibility.patch
@@ -0,0 +1,296 @@
+From a52c4ef44c0553a399a8a47e528db92e3bf51c6c Mon Sep 17 00:00:00 2001
+From: Alan Bateman <alanb@openjdk.org>
+Date: Wed, 29 Apr 2020 08:38:28 +0100
+Subject: [PATCH] 8243666: ModuleHashes attribute generated for JMOD and JAR
+ files depends on timestamps
+
+Reviewed-by: mchung
+---
+
+diff -ru orig/jdk-3cc80be736f2/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashesBuilder.java jdk-3cc80be736f2/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashesBuilder.java
+--- orig/jdk-3cc80be736f2/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashesBuilder.java	1970-01-01 01:00:01.000000000 +0100
++++ jdk-3cc80be736f2/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashesBuilder.java	2022-04-12 16:47:15.690423653 +0200
+@@ -27,9 +27,8 @@
+ 
+ import java.io.PrintStream;
+ import java.lang.module.Configuration;
++import java.lang.module.ModuleReference;
+ import java.lang.module.ResolvedModule;
+-import java.net.URI;
+-import java.nio.file.Path;
+ import java.nio.file.Paths;
+ import java.util.ArrayDeque;
+ import java.util.Collections;
+@@ -40,7 +39,6 @@
+ import java.util.Map;
+ import java.util.Set;
+ import java.util.function.Consumer;
+-import java.util.function.Function;
+ import java.util.stream.Stream;
+ import static java.util.stream.Collectors.*;
+ 
+@@ -116,27 +114,17 @@
+                    mods.addAll(ns);
+ 
+                    if (!ns.isEmpty()) {
+-                       Map<String, Path> moduleToPath = ns.stream()
+-                           .collect(toMap(Function.identity(), this::moduleToPath));
+-                       hashes.put(mn, ModuleHashes.generate(moduleToPath, "SHA-256"));
++                       Set<ModuleReference> mrefs = ns.stream()
++                               .map(name -> configuration.findModule(name)
++                                                         .orElseThrow(InternalError::new))
++                               .map(ResolvedModule::reference)
++                               .collect(toSet());
++                       hashes.put(mn, ModuleHashes.generate(mrefs, "SHA-256"));
+                    }
+                });
+         return hashes;
+     }
+ 
+-    private Path moduleToPath(String name) {
+-        ResolvedModule rm = configuration.findModule(name).orElseThrow(
+-            () -> new InternalError("Selected module " + name + " not on module path"));
+-
+-        URI uri = rm.reference().location().get();
+-        Path path = Paths.get(uri);
+-        String fn = path.getFileName().toString();
+-        if (!fn.endsWith(".jar") && !fn.endsWith(".jmod")) {
+-            throw new UnsupportedOperationException(path + " is not a modular JAR or jmod file");
+-        }
+-        return path;
+-    }
+-
+     /*
+      * Utility class
+      */
+diff -ru orig/jdk-3cc80be736f2/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java jdk-3cc80be736f2/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java
+--- orig/jdk-3cc80be736f2/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java	1970-01-01 01:00:01.000000000 +0100
++++ jdk-3cc80be736f2/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java	2022-04-12 16:58:05.639985936 +0200
+@@ -26,17 +26,21 @@
+ package jdk.internal.module;
+ 
+ import java.io.IOException;
++import java.io.InputStream;
+ import java.io.UncheckedIOException;
+-import java.nio.ByteBuffer;
+-import java.nio.channels.FileChannel;
+-import java.nio.file.Path;
++import java.lang.module.ModuleReader;
++import java.lang.module.ModuleReference;
++import java.nio.charset.StandardCharsets;
+ import java.security.MessageDigest;
+ import java.security.NoSuchAlgorithmException;
++import java.util.Arrays;
+ import java.util.Collections;
+ import java.util.HashMap;
+ import java.util.Map;
+ import java.util.Objects;
+ import java.util.Set;
++import java.util.TreeMap;
++import java.util.function.Supplier;
+ 
+ /**
+  * The result of hashing the contents of a number of module artifacts.
+@@ -60,8 +64,8 @@
+      * @param algorithm   the algorithm used to create the hashes
+      * @param nameToHash  the map of module name to hash value
+      */
+-    public ModuleHashes(String algorithm, Map<String, byte[]> nameToHash) {
+-        this.algorithm = algorithm;
++    ModuleHashes(String algorithm, Map<String, byte[]> nameToHash) {
++        this.algorithm = Objects.requireNonNull(algorithm);
+         this.nameToHash = Collections.unmodifiableMap(nameToHash);
+     }
+ 
+@@ -95,54 +99,125 @@
+     }
+ 
+     /**
+-     * Computes the hash for the given file with the given message digest
+-     * algorithm.
++     * Computes a hash from the names and content of a module.
+      *
++     * @param reader the module reader to access the module content
++     * @param algorithm the name of the message digest algorithm to use
++     * @return the hash
++     * @throws IllegalArgumentException if digest algorithm is not supported
+      * @throws UncheckedIOException if an I/O error occurs
+      * @throws RuntimeException if the algorithm is not available
+      */
+-    public static byte[] computeHash(Path file, String algorithm) {
++    private static byte[] computeHash(ModuleReader reader, String algorithm) {
++        MessageDigest md;
+         try {
+-            MessageDigest md = MessageDigest.getInstance(algorithm);
+-
+-            // Ideally we would just mmap the file but this consumes too much
+-            // memory when jlink is running concurrently on very large jmods
+-            try (FileChannel fc = FileChannel.open(file)) {
+-                ByteBuffer bb = ByteBuffer.allocate(32*1024);
+-                while (fc.read(bb) > 0) {
+-                    bb.flip();
+-                    md.update(bb);
+-                    assert bb.remaining() == 0;
+-                    bb.clear();
+-                }
+-            }
+-
+-            return md.digest();
++            md = MessageDigest.getInstance(algorithm);
+         } catch (NoSuchAlgorithmException e) {
+-            throw new RuntimeException(e);
++            throw new IllegalArgumentException(e);
++        }
++        try {
++            byte[] buf = new byte[32*1024];
++            reader.list().sorted().forEach(rn -> {
++                md.update(rn.getBytes(StandardCharsets.UTF_8));
++                try (InputStream in = reader.open(rn).orElseThrow(java.util.NoSuchElementException::new)) {
++                    int n;
++                    while ((n = in.read(buf)) > 0) {
++                        md.update(buf, 0, n);
++                    }
++                } catch (IOException ioe) {
++                    throw new UncheckedIOException(ioe);
++                }
++            });
+         } catch (IOException ioe) {
+             throw new UncheckedIOException(ioe);
+         }
++        return md.digest();
+     }
+ 
+     /**
+-     * Computes the hash for every entry in the given map, returning a
+-     * {@code ModuleHashes} to encapsulate the result. The map key is
+-     * the entry name, typically the module name. The map value is the file
+-     * path to the entry (module artifact).
++     * Computes a hash from the names and content of a module.
+      *
++     * @param supplier supplies the module reader to access the module content
++     * @param algorithm the name of the message digest algorithm to use
++     * @return the hash
++     * @throws IllegalArgumentException if digest algorithm is not supported
++     * @throws UncheckedIOException if an I/O error occurs
++     */
++    static byte[] computeHash(Supplier<ModuleReader> supplier, String algorithm) {
++        try (ModuleReader reader = supplier.get()) {
++            return computeHash(reader, algorithm);
++        } catch (IOException ioe) {
++            throw new UncheckedIOException(ioe);
++        }
++    }
++
++    /**
++     * Computes the hash from the names and content of a set of modules. Returns
++     * a {@code ModuleHashes} to encapsulate the result.
++     * @param mrefs the set of modules
++     * @param algorithm the name of the message digest algorithm to use
+      * @return ModuleHashes that encapsulates the hashes
++     * @throws IllegalArgumentException if digest algorithm is not supported
++     * @throws UncheckedIOException if an I/O error occurs
+      */
+-    public static ModuleHashes generate(Map<String, Path> map, String algorithm) {
++    static ModuleHashes generate(Set<ModuleReference> mrefs, String algorithm) {
+         Map<String, byte[]> nameToHash = new HashMap<>();
+-        for (Map.Entry<String, Path> entry: map.entrySet()) {
+-            String name = entry.getKey();
+-            Path path = entry.getValue();
+-            nameToHash.put(name, computeHash(path, algorithm));
++        for (ModuleReference mref : mrefs) {
++            try (ModuleReader reader = mref.open()) {
++                byte[] hash = computeHash(reader, algorithm);
++                nameToHash.put(mref.descriptor().name(), hash);
++            } catch (IOException ioe) {
++                throw new UncheckedIOException(ioe);
++            }
+         }
+         return new ModuleHashes(algorithm, nameToHash);
+     }
+ 
++    @Override
++    public int hashCode() {
++        int h = algorithm.hashCode();
++        for (Map.Entry<String, byte[]> e : nameToHash.entrySet()) {
++            h = h * 31 + e.getKey().hashCode();
++            h = h * 31 + Arrays.hashCode(e.getValue());
++        }
++        return h;
++    }
++
++    @Override
++    public boolean equals(Object obj) {
++        if (!(obj instanceof ModuleHashes))
++            return false;
++        ModuleHashes other = (ModuleHashes) obj;
++        if (!algorithm.equals(other.algorithm)
++                || nameToHash.size() != other.nameToHash.size())
++            return false;
++        for (Map.Entry<String, byte[]> e : nameToHash.entrySet()) {
++            String name = e.getKey();
++            byte[] hash = e.getValue();
++            if (!Arrays.equals(hash, other.nameToHash.get(name)))
++                return false;
++        }
++        return true;
++    }
++
++    @Override
++    public String toString() {
++        StringBuilder sb = new StringBuilder(algorithm);
++        sb.append(" ");
++        nameToHash.entrySet()
++                .stream()
++                .sorted(Map.Entry.comparingByKey())
++                .forEach(e -> {
++                    sb.append(e.getKey());
++                    sb.append("=");
++                    byte[] ba = e.getValue();
++                    for (byte b : ba) {
++                        sb.append(String.format("%02x", b & 0xff));
++                    }
++                });
++        return sb.toString();
++    }
++
+     /**
+      * This is used by jdk.internal.module.SystemModules class
+      * generated at link time.
+diff -ru orig/jdk-3cc80be736f2/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java jdk-3cc80be736f2/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java
+--- orig/jdk-3cc80be736f2/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java	1970-01-01 01:00:01.000000000 +0100
++++ jdk-3cc80be736f2/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java	2022-04-12 16:43:12.967868689 +0200
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
++ * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
+  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+  *
+  * This code is free software; you can redistribute it and/or modify it
+diff -ru orig/jdk-3cc80be736f2/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java jdk-3cc80be736f2/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java
+--- orig/jdk-3cc80be736f2/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java	1970-01-01 01:00:01.000000000 +0100
++++ jdk-3cc80be736f2/jdk/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java	2022-04-12 16:43:12.971868797 +0200
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
++ * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
+  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+  *
+  * This code is free software; you can redistribute it and/or modify it
+@@ -95,7 +95,7 @@
+                                         Path file) {
+         URI uri = file.toUri();
+         Supplier<ModuleReader> supplier = () -> new JarModuleReader(file, uri);
+-        HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
++        HashSupplier hasher = (a) -> ModuleHashes.computeHash(supplier, a);
+         return newModule(attrs, uri, supplier, patcher, hasher);
+     }
+ 
+@@ -105,7 +105,7 @@
+     static ModuleReference newJModModule(ModuleInfo.Attributes attrs, Path file) {
+         URI uri = file.toUri();
+         Supplier<ModuleReader> supplier = () -> new JModModuleReader(file, uri);
+-        HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
++        HashSupplier hasher = (a) -> ModuleHashes.computeHash(supplier, a);
+         return newModule(attrs, uri, supplier, null, hasher);
+     }
+ 
diff --git a/gnu/packages/patches/openjdk-9-module2-reproducibility.patch b/gnu/packages/patches/openjdk-9-module2-reproducibility.patch
new file mode 100644
index 0000000000..f167d94dc8
--- /dev/null
+++ b/gnu/packages/patches/openjdk-9-module2-reproducibility.patch
@@ -0,0 +1,125 @@
+Backport from openjdk 10
+
+--- orig/jdk-3cc80be736f2/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModuleSorter.java	1970-01-01 01:00:01.000000000 +0100
++++ jdk-3cc80be736f2/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ModuleSorter.java	2022-04-12 20:48:04.474353305 +0200
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
++ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+  *
+  * This code is free software; you can redistribute it and/or modify it
+@@ -30,13 +30,16 @@
+ import jdk.tools.jlink.plugin.ResourcePoolModuleView;
+ 
+ import java.lang.module.ModuleDescriptor;
++import java.lang.module.ModuleDescriptor.Requires;
+ import java.lang.module.ModuleDescriptor.Requires.Modifier;
+ 
+ import java.nio.ByteBuffer;
+-import java.util.Deque;
++import java.util.ArrayList;
++import java.util.Comparator;
+ import java.util.HashMap;
+ import java.util.HashSet;
+-import java.util.LinkedList;
++import java.util.LinkedHashSet;
++import java.util.List;
+ import java.util.Map;
+ import java.util.Set;
+ import java.util.stream.Stream;
+@@ -45,9 +48,8 @@
+  * Helper class to sort modules in topological order
+  */
+ public final class ModuleSorter {
+-    private final Deque<ResourcePoolModule> nodes = new LinkedList<>();
+-    private final Map<String, Set<ResourcePoolModule>> edges = new HashMap<>();
+-    private final Deque<ResourcePoolModule> result = new LinkedList<>();
++    private final Map<ResourcePoolModule, Set<ResourcePoolModule>> graph = new HashMap<>();
++    private final List<ResourcePoolModule> result = new ArrayList<>();
+ 
+     private final ResourcePoolModuleView moduleView;
+ 
+@@ -69,11 +71,17 @@
+ 
+     private ModuleSorter addModule(ResourcePoolModule module) {
+         addNode(module);
+-        readModuleDescriptor(module).requires().forEach(req -> {
++        // the module graph will be traversed in a stable order for
++        // the topological sort. So add the dependences in the module name order
++        readModuleDescriptor(module).requires()
++                                    .stream()
++                                    .sorted(Comparator.comparing(Requires::name))
++                                    .forEach(req ->
++        {
+             ResourcePoolModule dep = moduleView.findModule(req.name()).orElse(null);
+             if (dep != null) {
+                 addNode(dep);
+-                edges.get(module.name()).add(dep);
++                graph.get(module).add(dep);
+             } else if (!req.modifiers().contains(Modifier.STATIC)) {
+                 throw new PluginException(req.name() + " not found");
+             }
+@@ -82,22 +90,23 @@
+     }
+ 
+     private void addNode(ResourcePoolModule module) {
+-        nodes.add(module);
+-        edges.computeIfAbsent(module.name(), _n -> new HashSet<>());
++        graph.computeIfAbsent(module, _n -> new LinkedHashSet<>());
+     }
+ 
++    /*
++     * The module graph will be traversed in a stable order
++     * (traversing the modules and their dependences in alphabetical order)
++     * so that it will produce the same result of a given module graph.
++     */
+     private synchronized void build() {
+-        if (!result.isEmpty() || nodes.isEmpty())
++        if (!result.isEmpty() || graph.isEmpty())
+             return;
+ 
+-        Deque<ResourcePoolModule> visited = new LinkedList<>();
+-        Deque<ResourcePoolModule> done = new LinkedList<>();
+-        ResourcePoolModule node;
+-        while ((node = nodes.poll()) != null) {
+-            if (!visited.contains(node)) {
+-                visit(node, visited, done);
+-            }
+-        }
++        Set<ResourcePoolModule> visited = new HashSet<>();
++        Set<ResourcePoolModule> done = new HashSet<>();
++        graph.keySet().stream()
++             .sorted(Comparator.comparing(ResourcePoolModule::name))
++             .forEach(node -> visit(node, visited, done));
+     }
+ 
+     public Stream<ResourcePoolModule> sorted() {
+@@ -106,19 +115,21 @@
+     }
+ 
+     private void visit(ResourcePoolModule node,
+-                       Deque<ResourcePoolModule> visited,
+-                       Deque<ResourcePoolModule> done) {
++                       Set<ResourcePoolModule> visited,
++                       Set<ResourcePoolModule> done) {
+         if (visited.contains(node)) {
+             if (!done.contains(node)) {
+                 throw new IllegalArgumentException("Cyclic detected: " +
+-                    node + " " + edges.get(node.name()));
++                    node + " " + graph.get(node));
+             }
+             return;
+         }
++
++        // traverse the dependences of the given module which are
++        // also sorted in alphabetical order
+         visited.add(node);
+-        edges.get(node.name())
+-             .forEach(x -> visit(x, visited, done));
++        graph.get(node).forEach(x -> visit(x, visited, done));
+         done.add(node);
+-        result.addLast(node);
++        result.add(node);
+     }
+ }
diff --git a/gnu/packages/patches/openjdk-9-module3-reproducibility.patch b/gnu/packages/patches/openjdk-9-module3-reproducibility.patch
new file mode 100644
index 0000000000..9db54f5531
--- /dev/null
+++ b/gnu/packages/patches/openjdk-9-module3-reproducibility.patch
@@ -0,0 +1,36 @@
+From: Danny Milosavljevic <dannym@scratchpost.org>
+Date: Wed, 18 Apr 2022 21:50:00 +0100
+Subject: Make module descriptor reproducible
+
+--- orig/jdk-3cc80be736f2/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java	1970-01-01 01:00:01.000000000 +0100
++++ jdk-3cc80be736f2/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java	2022-04-13 17:30:37.242775977 +0200
+@@ -43,6 +43,7 @@
+ import java.util.Objects;
+ import java.util.Optional;
+ import java.util.Set;
++import java.util.TreeSet;
+ import java.util.function.Supplier;
+ import java.util.stream.Collectors;
+ import java.util.stream.Stream;
+@@ -2155,9 +2156,9 @@
+          * @return The module descriptor
+          */
+         public ModuleDescriptor build() {
+-            Set<Requires> requires = new HashSet<>(this.requires.values());
+-            Set<Exports> exports = new HashSet<>(this.exports.values());
+-            Set<Opens> opens = new HashSet<>(this.opens.values());
++            Set<Requires> requires = new TreeSet<>(this.requires.values());
++            Set<Exports> exports = new TreeSet<>(this.exports.values());
++            Set<Opens> opens = new TreeSet<>(this.opens.values());
+ 
+             // add dependency on java.base
+             if (strict
+@@ -2169,7 +2170,7 @@
+                                           null));
+             }
+ 
+-            Set<Provides> provides = new HashSet<>(this.provides.values());
++            Set<Provides> provides = new TreeSet<>(this.provides.values());
+ 
+             return new ModuleDescriptor(name,
+                                         version,
-- 
2.36.1
D
D
dannym wrote on 1 Jun 15:00 +0200
[PATCH 3/8] gnu: openjdk11: Make more reproducible.
(address . 55751@debbugs.gnu.org)(name . Danny Milosavljevic)(address . dannym@scratchpost.org)
20220601130011.9910-4-dannym@scratchpost.org
From: Danny Milosavljevic <dannym@scratchpost.org>

* gnu/packages/java.scm (openjdk11)[source]: Add patches.
[arguments]<#:phases>[remove-timestamping]: Add phase.
* gnu/packages/patches/openjdk-11-classlist-reproducibility.patch: New file.
* gnu/local.mk (dist_patch_DATA): Add patches.
---
gnu/local.mk | 1 +
gnu/packages/java.scm | 21 ++++++++++++++++++-
...openjdk-11-classlist-reproducibility.patch | 11 ++++++++++
3 files changed, 32 insertions(+), 1 deletion(-)
create mode 100644 gnu/packages/patches/openjdk-11-classlist-reproducibility.patch

Toggle diff (77 lines)
diff --git a/gnu/local.mk b/gnu/local.mk
index 0a81e0fe75..eaf0e306fb 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -1582,6 +1582,7 @@ dist_patch_DATA =						\
   %D%/packages/patches/openjdk-10-module-reproducibility.patch	\
   %D%/packages/patches/openjdk-10-module3-reproducibility.patch	\
   %D%/packages/patches/openjdk-10-module4-reproducibility.patch	\
+  %D%/packages/patches/openjdk-11-classlist-reproducibility.patch	\
   %D%/packages/patches/openjdk-15-xcursor-no-dynamic.patch	\
   %D%/packages/patches/openmpi-mtl-priorities.patch		\
   %D%/packages/patches/openssh-hurd.patch			\
diff --git a/gnu/packages/java.scm b/gnu/packages/java.scm
index 37b310141e..5a1e45ca68 100644
--- a/gnu/packages/java.scm
+++ b/gnu/packages/java.scm
@@ -1842,7 +1842,17 @@ (define-public openjdk11
               (snippet
                `(begin
                   (for-each delete-file (find-files "." ".*.(bin|exe|jar)$"))
-                  #t))))
+                  #t))
+              (patches
+               (search-patches ;"openjdk-10-module-reproducibility.patch"
+                        "openjdk-10-module3-reproducibility.patch"
+                        "openjdk-10-module4-reproducibility.patch"
+                        "openjdk-10-char-reproducibility.patch"
+                        "openjdk-11-classlist-reproducibility.patch"
+                        ;"openjdk-10-corba-reproducibility.patch"
+                        ;"openjdk-10-idlj-reproducibility.patch"
+                        "openjdk-10-jar-reproducibility.patch"
+                        "openjdk-10-jtask-reproducibility.patch"))))
     (build-system gnu-build-system)
     (outputs '("out" "jdk" "doc"))
     (arguments
@@ -1869,6 +1879,10 @@ (define-public openjdk11
          "--with-libjpeg=system"
          "--with-libpng=system"
          "--with-version-pre="
+         ;; should be set by SOURCE_DATE_EPOCH handler, but
+         ;; isn't being set. So manually do it.
+         "--with-hotspot-build-time=1970-01-01T00:00:01"
+         "--enable-reproducible-build" ; to be sure
          ;; allow the build system to locate the system freetype
          ,(string-append "--with-freetype-include="
                          (assoc-ref %build-inputs "freetype") "/include")
@@ -1883,6 +1897,11 @@ (define-public openjdk11
              (substitute* "make/data/blockedcertsconverter/blocked.certs.pem"
                (("^#!.*") "#! java BlockedCertsConverter SHA-256\n"))
              #t))
+         (add-after 'unpack 'remove-timestamping
+           (lambda _
+             (substitute* "src/hotspot/share/runtime/abstract_vm_version.cpp"
+              (("__DATE__") "")
+              (("__TIME__") ""))))
          (add-after 'unpack 'patch-jni-libs
            ;; Hardcode dynamically loaded libraries.
            (lambda _
diff --git a/gnu/packages/patches/openjdk-11-classlist-reproducibility.patch b/gnu/packages/patches/openjdk-11-classlist-reproducibility.patch
new file mode 100644
index 0000000000..2ac7c2b664
--- /dev/null
+++ b/gnu/packages/patches/openjdk-11-classlist-reproducibility.patch
@@ -0,0 +1,11 @@
+--- jdk-11.0.13-ga/make/GenerateLinkOptData.gmk.orig	2022-04-04 17:18:56.801929954 +0200
++++ jdk-11.0.13-ga/make/GenerateLinkOptData.gmk	2022-04-04 17:19:14.962422622 +0200
+@@ -66,7 +66,7 @@
+ 	    -cp $(SUPPORT_OUTPUTDIR)/classlist.jar \
+ 	    build.tools.classlist.HelloClasslist \
+ 	    $(LOG_DEBUG) 2>&1 > $(JLI_TRACE_FILE)
+-	$(GREP) -v HelloClasslist $@.raw > $@
++	$(GREP) -v HelloClasslist $@.raw |sort > $@
+ 
+ # The jli trace is created by the same recipe as classlist. By declaring these
+ # dependencies, make will correctly rebuild both jli trace and classlist
-- 
2.36.1
D
D
dannym wrote on 1 Jun 15:00 +0200
[PATCH 4/8] gnu: openjdk12: Make reproducible.
(address . 55751@debbugs.gnu.org)(name . Danny Milosavljevic)(address . dannym@scratchpost.org)
20220601130011.9910-5-dannym@scratchpost.org
From: Danny Milosavljevic <dannym@scratchpost.org>

* gnu/packages/java.scm (openjdk12)[arguments]<#:phases>[remove-timestamping]:
Modify phase.
---
gnu/packages/java.scm | 5 +++++
1 file changed, 5 insertions(+)

Toggle diff (18 lines)
diff --git a/gnu/packages/java.scm b/gnu/packages/java.scm
index 5a1e45ca68..1a872ce786 100644
--- a/gnu/packages/java.scm
+++ b/gnu/packages/java.scm
@@ -2138,6 +2138,11 @@ (define-public openjdk12
      (substitute-keyword-arguments (package-arguments openjdk11)
        ((#:phases phases)
         `(modify-phases ,phases
+           (replace 'remove-timestamping
+             (lambda _
+               (substitute* "src/hotspot/share/runtime/vm_version.cpp"
+                (("__DATE__") "")
+                (("__TIME__") ""))))
            (replace 'fix-java-shebangs
              (lambda _
                ;; This file was "fixed" by patch-source-shebangs, but it requires
-- 
2.36.1
D
D
dannym wrote on 1 Jun 15:00 +0200
[PATCH 6/8] gnu: openjdk14: Make reproducible.
(address . 55751@debbugs.gnu.org)(name . Danny Milosavljevic)(address . dannym@scratchpost.org)
20220601130011.9910-7-dannym@scratchpost.org
From: Danny Milosavljevic <dannym@scratchpost.org>

* gnu/packages/java.scm (openjdk14)[source]: Add patches.
---
gnu/packages/java.scm | 3 +++
1 file changed, 3 insertions(+)

Toggle diff (16 lines)
diff --git a/gnu/packages/java.scm b/gnu/packages/java.scm
index 7bf8527d67..2599170d84 100644
--- a/gnu/packages/java.scm
+++ b/gnu/packages/java.scm
@@ -2245,6 +2245,9 @@ (define-public openjdk14
               (sha256
                (base32
                 "07k9bsbxwyf2z2n50z96nvhsdai916mxdxcr5lm44jz7f6xrwfq6"))
+              (patches
+                (search-patches "openjdk-13-classlist-reproducibility.patch"
+                                "openjdk-10-jtask-reproducibility.patch"))
               (modules '((guix build utils)))
               (snippet
                `(begin
-- 
2.36.1
D
D
dannym wrote on 1 Jun 15:00 +0200
[PATCH 5/8] gnu: openjdk13: Make reproducible.
(address . 55751@debbugs.gnu.org)(name . Danny Milosavljevic)(address . dannym@scratchpost.org)
20220601130011.9910-6-dannym@scratchpost.org
From: Danny Milosavljevic <dannym@scratchpost.org>

* gnu/packages/patches/openjdk-13-classlist-reproducibility.patch: New file.
* gnu/local.mk (dist_patch_DATA): Add patch.
* gnu/packages/java.scm (openjdk13)[source]: Add patch.
[arguments]<#:phases>[remove-timestamping]: Modify phase.
---
gnu/local.mk | 1 +
gnu/packages/java.scm | 12 ++++++++++++
.../openjdk-13-classlist-reproducibility.patch | 11 +++++++++++
3 files changed, 24 insertions(+)
create mode 100644 gnu/packages/patches/openjdk-13-classlist-reproducibility.patch

Toggle diff (59 lines)
diff --git a/gnu/local.mk b/gnu/local.mk
index eaf0e306fb..aab850b4f7 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -1583,6 +1583,7 @@ dist_patch_DATA =						\
   %D%/packages/patches/openjdk-10-module3-reproducibility.patch	\
   %D%/packages/patches/openjdk-10-module4-reproducibility.patch	\
   %D%/packages/patches/openjdk-11-classlist-reproducibility.patch	\
+  %D%/packages/patches/openjdk-13-classlist-reproducibility.patch	\
   %D%/packages/patches/openjdk-15-xcursor-no-dynamic.patch	\
   %D%/packages/patches/openmpi-mtl-priorities.patch		\
   %D%/packages/patches/openssh-hurd.patch			\
diff --git a/gnu/packages/java.scm b/gnu/packages/java.scm
index 1a872ce786..7bf8527d67 100644
--- a/gnu/packages/java.scm
+++ b/gnu/packages/java.scm
@@ -2189,11 +2189,23 @@ (define-public openjdk13
               (sha256
                (base32
                 "0wrrr0d7lz1v8qqm752mn4gz5l2vpl2kmx4ac3ysvk4mljc924hp"))
+              (patches
+                (search-patches "openjdk-13-classlist-reproducibility.patch"
+                                "openjdk-10-jtask-reproducibility.patch"))
               (modules '((guix build utils)))
               (snippet
                `(begin
                   (for-each delete-file (find-files "." ".*.(bin|exe|jar)$"))
                   #t))))
+    (arguments
+     (substitute-keyword-arguments (package-arguments openjdk12)
+       ((#:phases phases)
+        `(modify-phases ,phases
+           (replace 'remove-timestamping
+             (lambda _
+               (substitute* "src/hotspot/share/runtime/abstract_vm_version.cpp"
+                (("__DATE__") "")
+                (("__TIME__") ""))))))))
     (inputs
      `(("alsa-lib" ,alsa-lib)
        ("cups" ,cups)
diff --git a/gnu/packages/patches/openjdk-13-classlist-reproducibility.patch b/gnu/packages/patches/openjdk-13-classlist-reproducibility.patch
new file mode 100644
index 0000000000..326f6875ec
--- /dev/null
+++ b/gnu/packages/patches/openjdk-13-classlist-reproducibility.patch
@@ -0,0 +1,11 @@
+--- 6cllxkf0narh0b4wgx8npwjkznd7ifq0-openjdk-13.0.7-checkout/make/GenerateLinkOptData.gmk.orig	2022-04-04 17:20:33.012539984 +0200
++++ 6cllxkf0narh0b4wgx8npwjkznd7ifq0-openjdk-13.0.7-checkout/make/GenerateLinkOptData.gmk	2022-04-04 17:20:51.181032859 +0200
+@@ -78,7 +78,7 @@
+ 	        $(CAT) $(LINK_OPT_DIR)/stderr $(JLI_TRACE_FILE) ; \
+ 	        exit $$exitcode \
+ 	    )
+-	$(GREP) -v HelloClasslist $@.raw > $@
++	$(GREP) -v HelloClasslist $@.raw | sort > $@
+ 
+ # The jli trace is created by the same recipe as classlist. By declaring these
+ # dependencies, make will correctly rebuild both jli trace and classlist
-- 
2.36.1
D
D
dannym wrote on 1 Jun 15:00 +0200
[PATCH 7/8] gnu: openjdk15: Make reproducible.
(address . 55751@debbugs.gnu.org)(name . Danny Milosavljevic)(address . dannym@scratchpost.org)
20220601130011.9910-8-dannym@scratchpost.org
From: Danny Milosavljevic <dannym@scratchpost.org>

* gnu/packages/java.scm (openjdk15)[source]: Add patch.
---
gnu/packages/java.scm | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

Toggle diff (16 lines)
diff --git a/gnu/packages/java.scm b/gnu/packages/java.scm
index 2599170d84..368abf8ba6 100644
--- a/gnu/packages/java.scm
+++ b/gnu/packages/java.scm
@@ -2297,7 +2297,8 @@ (define-public openjdk15
                (base32
                 "168cr08nywp0q3vyj8njkhsmmnyd8rz9r58hk4xhzdzc6bdfkl1i"))
               (patches
-                (search-patches "openjdk-15-xcursor-no-dynamic.patch"))))
+                (search-patches "openjdk-15-jtask-reproducibility.patch"
+                                "openjdk-15-xcursor-no-dynamic.patch"))))
     (inputs
      (cons `("libxcursor" ,libxcursor) ; for our patch to work
            (package-inputs openjdk14)))
-- 
2.36.1
D
D
dannym wrote on 1 Jun 15:00 +0200
[PATCH 8/8] gnu: openjdk16: Make reproducible.
(address . 55751@debbugs.gnu.org)(name . Danny Milosavljevic)(address . dannym@scratchpost.org)
20220601130011.9910-9-dannym@scratchpost.org
From: Danny Milosavljevic <dannym@scratchpost.org>

* gnu/packages/java.scm (openjdk16)[source]: Add patch.
---
gnu/packages/java.scm | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

Toggle diff (16 lines)
diff --git a/gnu/packages/java.scm b/gnu/packages/java.scm
index 368abf8ba6..d1538d0afa 100644
--- a/gnu/packages/java.scm
+++ b/gnu/packages/java.scm
@@ -2326,7 +2326,8 @@ (define-public openjdk16
                (base32
                 "1ggddsbsar4dj2fycfqqqagqil7prhb30afvq6933rz7pa9apm2f"))
               (patches
-                (search-patches "openjdk-15-xcursor-no-dynamic.patch"))))
+                (search-patches "openjdk-15-jtask-reproducibility.patch"
+                                "openjdk-15-xcursor-no-dynamic.patch"))))
     (native-inputs
      `(("autoconf" ,autoconf)
        ("openjdk15:jdk" ,openjdk15 "jdk")
-- 
2.36.1
D
D
dannym wrote on 1 Jun 15:00 +0200
[PATCH 2/8] gnu: openjdk10: Make more reproducible.
(address . 55751@debbugs.gnu.org)(name . Danny Milosavljevic)(address . dannym@scratchpost.org)
20220601130011.9910-3-dannym@scratchpost.org
From: Danny Milosavljevic <dannym@scratchpost.org>

* gnu/packages/patches/openjdk-10-char-reproducibility.patch: New file.
* gnu/packages/patches/openjdk-10-classlist-reproducibility.patch: New file.
* gnu/packages/patches/openjdk-10-corba-reproducibility.patch: New file.
* gnu/packages/patches/openjdk-10-jar-reproducibility.patch: New file.
* gnu/packages/patches/openjdk-10-jtask-reproducibility.patch: New file.
* gnu/packages/patches/openjdk-10-module-reproducibility.patch: New file.
* gnu/packages/patches/openjdk-10-module3-reproducibility.patch: New file.
* gnu/packages/patches/openjdk-10-module4-reproducibility.patch: New file.
* gnu/packages/java.scm (openjdk10)[source]: Add patches.
[arguments]<#:phases>[remove-timestamping]: New phase.
* gnu/local.mk (dist_patch_DATA): Add patches.
---
gnu/local.mk | 8 +
gnu/packages/java.scm | 15 +-
.../openjdk-10-char-reproducibility.patch | 12 +
...openjdk-10-classlist-reproducibility.patch | 27 ++
.../openjdk-10-corba-reproducibility.patch | 12 +
.../openjdk-10-jar-reproducibility.patch | 103 ++++++
.../openjdk-10-jtask-reproducibility.patch | 53 +++
.../openjdk-10-module-reproducibility.patch | 305 ++++++++++++++++++
.../openjdk-10-module3-reproducibility.patch | 34 ++
.../openjdk-10-module4-reproducibility.patch | 14 +
10 files changed, 582 insertions(+), 1 deletion(-)
create mode 100644 gnu/packages/patches/openjdk-10-char-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-10-classlist-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-10-corba-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-10-jar-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-10-jtask-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-10-module-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-10-module3-reproducibility.patch
create mode 100644 gnu/packages/patches/openjdk-10-module4-reproducibility.patch

Toggle diff (663 lines)
diff --git a/gnu/local.mk b/gnu/local.mk
index 5ba5af94a6..0a81e0fe75 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -1573,7 +1573,15 @@ dist_patch_DATA =						\
   %D%/packages/patches/openjdk-9-module-reproducibility.patch	\
   %D%/packages/patches/openjdk-9-module2-reproducibility.patch	\
   %D%/packages/patches/openjdk-9-module3-reproducibility.patch	\
+  %D%/packages/patches/openjdk-10-char-reproducibility.patch	\
+  %D%/packages/patches/openjdk-10-classlist-reproducibility.patch	\
+  %D%/packages/patches/openjdk-10-corba-reproducibility.patch	\
   %D%/packages/patches/openjdk-10-idlj-reproducibility.patch	\
+  %D%/packages/patches/openjdk-10-jar-reproducibility.patch	\
+  %D%/packages/patches/openjdk-10-jtask-reproducibility.patch	\
+  %D%/packages/patches/openjdk-10-module-reproducibility.patch	\
+  %D%/packages/patches/openjdk-10-module3-reproducibility.patch	\
+  %D%/packages/patches/openjdk-10-module4-reproducibility.patch	\
   %D%/packages/patches/openjdk-15-xcursor-no-dynamic.patch	\
   %D%/packages/patches/openmpi-mtl-priorities.patch		\
   %D%/packages/patches/openssh-hurd.patch			\
diff --git a/gnu/packages/java.scm b/gnu/packages/java.scm
index 3d36849f7d..37b310141e 100644
--- a/gnu/packages/java.scm
+++ b/gnu/packages/java.scm
@@ -1763,7 +1763,15 @@ (define-public openjdk10
                (base32
                 "0zywq2203b4hx4jms9vbwvjcj1d3k2v3qpx4s33729fkpmid97r4"))
               (patches (search-patches
-                        "openjdk-10-idlj-reproducibility.patch"))
+                        "openjdk-10-module-reproducibility.patch"
+                        "openjdk-10-module3-reproducibility.patch"
+                        "openjdk-10-module4-reproducibility.patch"
+                        "openjdk-10-char-reproducibility.patch"
+                        "openjdk-10-classlist-reproducibility.patch"
+                        "openjdk-10-corba-reproducibility.patch"
+                        "openjdk-10-idlj-reproducibility.patch"
+                        "openjdk-10-jar-reproducibility.patch"
+                        "openjdk-10-jtask-reproducibility.patch"))
               (modules '((guix build utils)))
               (snippet
                `(begin
@@ -1780,6 +1788,11 @@ (define-public openjdk10
                (substitute* "make/data/blacklistedcertsconverter/blacklisted.certs.pem"
                  (("^#!.*") "#! java BlacklistedCertsConverter SHA-256\n"))
                #t))
+           (add-after 'unpack 'remove-timestamping
+             (lambda _
+               (substitute* "./src/hotspot/share/runtime/vm_version.cpp"
+                 (("__DATE__") "")
+                 (("__TIME__") ""))))
            (replace 'configure
              (lambda* (#:key inputs outputs #:allow-other-keys)
                (invoke "bash" "./configure"
diff --git a/gnu/packages/patches/openjdk-10-char-reproducibility.patch b/gnu/packages/patches/openjdk-10-char-reproducibility.patch
new file mode 100644
index 0000000000..a7932678af
--- /dev/null
+++ b/gnu/packages/patches/openjdk-10-char-reproducibility.patch
@@ -0,0 +1,12 @@
+Danny
+--- orig/jdk-6fa770f9f8ab/make/jdk/src/classes/build/tools/generatecharacter/GenerateCharacter.java	2022-04-13 19:24:10.211683257 +0200
++++ jdk-6fa770f9f8ab/make/jdk/src/classes/build/tools/generatecharacter/GenerateCharacter.java	2022-04-13 22:51:50.680487330 +0200
+@@ -693,7 +693,7 @@
+         PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(theOutputFileName)));
+         out.println(commentStart +
+             " This file was generated AUTOMATICALLY from a template file " +
+-            new java.util.Date() + commentEnd);
++            (System.getenv("SOURCE_DATE_EPOCH") == null ? new java.util.Date() : new java.util.Date(1000 * Long.parseLong(System.getenv("SOURCE_DATE_EPOCH")))) + commentEnd);
+         int marklen = commandMarker.length();
+         LOOP: while(true) {
+             try {
diff --git a/gnu/packages/patches/openjdk-10-classlist-reproducibility.patch b/gnu/packages/patches/openjdk-10-classlist-reproducibility.patch
new file mode 100644
index 0000000000..e1292ba82d
--- /dev/null
+++ b/gnu/packages/patches/openjdk-10-classlist-reproducibility.patch
@@ -0,0 +1,27 @@
+--- orig/jdk-6fa770f9f8ab/make/GenerateLinkOptData.gmk	2022-04-04 17:16:29.365930149 +0200
++++ jdk-6fa770f9f8ab/make/GenerateLinkOptData.gmk	2022-04-04 17:16:54.954624358 +0200
+@@ -61,11 +61,12 @@
+ 	$(call MakeDir, $(LINK_OPT_DIR))
+ 	$(call LogInfo, Generating $(patsubst $(OUTPUTDIR)/%, %, $@))
+ 	$(call LogInfo, Generating $(patsubst $(OUTPUTDIR)/%, %, $(JLI_TRACE_FILE)))
+-	$(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -XX:DumpLoadedClassList=$@ \
++	$(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -XX:DumpLoadedClassList=$@.tmp \
+ 	    -Djava.lang.invoke.MethodHandle.TRACE_RESOLVE=true \
+ 	    -cp $(SUPPORT_OUTPUTDIR)/classlist.jar \
+ 	    build.tools.classlist.HelloClasslist \
+ 	    $(LOG_DEBUG) 2>&1 > $(JLI_TRACE_FILE)
++	sort $@.tmp > $@
+ 
+ # The jli trace is created by the same recipe as classlist. By declaring these
+ # dependencies, make will correctly rebuild both jli trace and classlist
+--- orig/jdk-6fa770f9f8ab/make/gendata/Gendata-jdk.compiler.gmk	2022-04-13 19:24:10.191682716 +0200
++++ jdk-6fa770f9f8ab/make/gendata/Gendata-jdk.compiler.gmk	2022-04-13 20:58:57.891368216 +0200
+@@ -83,6 +83,8 @@
+ 	    $(CT_MODULESOURCEPATH) \
+ 	    $(CT_MODULES) \
+ 	    >$(@D)/A/system-modules
++	# Make files reproducible
++	find $(@D) -exec $(TOUCH) -h -c -t 197001010000.01 {} \;
+ 	$(TOUCH) $@
+ 
+ # Can't generate ct.sym directly into modules libs as the SetupJarArchive macro
diff --git a/gnu/packages/patches/openjdk-10-corba-reproducibility.patch b/gnu/packages/patches/openjdk-10-corba-reproducibility.patch
new file mode 100644
index 0000000000..bd5ce1fd2b
--- /dev/null
+++ b/gnu/packages/patches/openjdk-10-corba-reproducibility.patch
@@ -0,0 +1,12 @@
+Danny
+--- orig/jdk-6fa770f9f8ab/make/corba/src/classes/build/tools/logutil/MC.java	2022-04-13 19:24:10.111680549 +0200
++++ jdk-6fa770f9f8ab/make/corba/src/classes/build/tools/logutil/MC.java	2022-04-13 22:51:13.399462259 +0200
+@@ -154,7 +154,7 @@
+                   groupName);
+     pw.println("//");
+     pw.printMsg("// Generated by MC.java version @, DO NOT EDIT BY HAND!", VERSION);
+-    pw.printMsg("// Generated from input file @ on @", inFile, new Date());
++    pw.printMsg("// Generated from input file @ on @", inFile, System.getenv("SOURCE_DATE_EPOCH") == null ? new Date() : new Date(1000 * Long.parseLong(System.getenv("SOURCE_DATE_EPOCH"))));
+     pw.println();
+   }
+ 
diff --git a/gnu/packages/patches/openjdk-10-jar-reproducibility.patch b/gnu/packages/patches/openjdk-10-jar-reproducibility.patch
new file mode 100644
index 0000000000..176eedfce6
--- /dev/null
+++ b/gnu/packages/patches/openjdk-10-jar-reproducibility.patch
@@ -0,0 +1,103 @@
+diff -ru orig/jdk-6fa770f9f8ab/make/common/JarArchive.gmk jdk-6fa770f9f8ab/make/common/JarArchive.gmk
+--- orig/jdk-6fa770f9f8ab/make/common/JarArchive.gmk	2022-04-13 19:24:10.107680441 +0200
++++ jdk-6fa770f9f8ab/make/common/JarArchive.gmk	2022-04-13 19:31:18.031271019 +0200
+@@ -251,12 +251,14 @@
+ 	    $(ECHO) "Main-Class: $$(strip $$($1_JARMAIN))" >> $$($1_MANIFEST_FILE) $$(NEWLINE)) \
+ 	  $$(if $$($1_EXTRA_MANIFEST_ATTR), \
+ 	    $(PRINTF) "$$($1_EXTRA_MANIFEST_ATTR)\n" >> $$($1_MANIFEST_FILE) $$(NEWLINE)) \
++	  $(TOUCH) -h -c -t 197001010000.00 $$($1_MANIFEST_FILE) $$(NEWLINE) \
+ 	  $(ECHO) Creating $$($1_NAME) $$(NEWLINE) \
+ 	  $$($1_JAR_CMD) $$($1_JAR_CREATE_OPTIONS) $$@ $$($1_MANIFEST_FILE) $$(NEWLINE) \
+ 	  $$($1_SCAPTURE_CONTENTS) \
+ 	  $$($1_SCAPTURE_METAINF) \
+ 	  $$($1_SUPDATE_CONTENTS) \
+-	  $$($1_JARINDEX) && true \
++	  $$($1_JARINDEX) && true $$(NEWLINE) \
++	  d="`mktemp -d`" && $(CP) -f $$@ "$$$$d/a.jar" && (cd "$$$$d" && unzip a.jar META-INF/MANIFEST.MF && $(TOUCH) -h -c -t 197001010000.00 META-INF &&  $(TOUCH) -h -c -t 197001010000.00 META-INF/MANIFEST.MF && (zip --symlinks -0 -X a.jar META-INF META-INF/MANIFEST.MF; zip --symlinks -0 -X a.jar META-INF META-INF/MANIFEST.MF)) && $(CP) -f "$$$$d/a.jar" $$@ \
+ 	, \
+ 	  $(ECHO) Modifying $$($1_NAME) $$(NEWLINE) \
+ 	  $$($1_CAPTURE_CONTENTS) \
+diff -ru orig/jdk-6fa770f9f8ab/make/JrtfsJar.gmk jdk-6fa770f9f8ab/make/JrtfsJar.gmk
+--- orig/jdk-6fa770f9f8ab/make/JrtfsJar.gmk	2022-04-13 19:24:10.091680007 +0200
++++ jdk-6fa770f9f8ab/make/JrtfsJar.gmk	2022-04-13 19:29:30.044346222 +0200
+@@ -57,13 +57,18 @@
+ # file will not be copied unless META-INF/services would also be added to the INCLUDES.
+ # Adding META-INF/services would include all files in that directory when only the one
+ # is needed, which is why this explicit copy is defined instead.
+-$(eval $(call SetupCopyFiles, COPY_JIMAGE_SERVICE_PROVIDER, \
++$(eval $(call SetupCopyFiles, COPY_JIMAGE_SERVICE_PROVIDER, \
+     SRC := $(TOPDIR)/src/java.base/share/classes, \
+     DEST := $(SUPPORT_OUTPUTDIR)/jrtfs_classes, \
+     FILES := META-INF/services/java.nio.file.spi.FileSystemProvider))
+ 
++.PHONY: $(COPY_JIMAGE_SERVICE_PROVIDER)_fix
++$(COPY_JIMAGE_SERVICE_PROVIDER)_fix: $(COPY_JIMAGE_SERVICE_PROVIDER)
++	find $(SUPPORT_OUTPUTDIR)/jrtfs_classes -exec $(TOUCH) -h -c -t 197001010000.00 {} \;
++	$(TOUCH) -h -c -t 197001010000.00 $(SUPPORT_OUTPUTDIR)/java-main-manifest.mf
++
+ $(eval $(call SetupJarArchive,BUILD_JRTFS_JAR, \
+-    DEPENDENCIES := $(BUILD_JRTFS) $(COPY_JIMAGE_SERVICE_PROVIDER), \
++    DEPENDENCIES := $(BUILD_JRTFS) $(COPY_JIMAGE_SERVICE_PROVIDER)_fix, \
+     SRCS := $(SUPPORT_OUTPUTDIR)/jrtfs_classes, \
+     JAR := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/jrt-fs.jar, \
+     MANIFEST := $(SUPPORT_OUTPUTDIR)/java-main-manifest.mf, \
+diff -ru orig/jdk-6fa770f9f8ab/src/jdk.jartool/share/classes/sun/tools/jar/Main.java jdk-6fa770f9f8ab/src/jdk.jartool/share/classes/sun/tools/jar/Main.java
+--- orig/jdk-6fa770f9f8ab/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	2022-04-13 19:24:12.555746751 +0200
++++ jdk-6fa770f9f8ab/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	2022-04-13 19:25:34.117955999 +0200
+@@ -849,12 +849,18 @@
+                     output(getMsg("out.added.manifest"));
+                 }
+                 ZipEntry e = new ZipEntry(MANIFEST_DIR);
+-                e.setTime(System.currentTimeMillis());
++                if (System.getenv("SOURCE_DATE_EPOCH") != null)
++                    e.setTime(1000 * Long.parseLong(System.getenv("SOURCE_DATE_EPOCH")));
++                else
++                    e.setTime(System.currentTimeMillis());
+                 e.setSize(0);
+                 e.setCrc(0);
+                 zos.putNextEntry(e);
+                 e = new ZipEntry(MANIFEST_NAME);
+-                e.setTime(System.currentTimeMillis());
++                if (System.getenv("SOURCE_DATE_EPOCH") != null)
++                    e.setTime(1000 * Long.parseLong(System.getenv("SOURCE_DATE_EPOCH")));
++                else
++                    e.setTime(System.currentTimeMillis());
+                 if (flag0) {
+                     crc32Manifest(e, manifest);
+                 }
+@@ -1021,7 +1027,10 @@
+         throws IOException
+     {
+         ZipEntry e = new ZipEntry(INDEX_NAME);
+-        e.setTime(System.currentTimeMillis());
++        if (System.getenv("SOURCE_DATE_EPOCH") != null)
++            e.setTime(1000 * Long.parseLong(System.getenv("SOURCE_DATE_EPOCH")));
++        else
++            e.setTime(System.currentTimeMillis());
+         if (flag0) {
+             CRC32OutputStream os = new CRC32OutputStream();
+             index.write(os);
+@@ -1040,7 +1049,10 @@
+             String name = mi.getKey();
+             byte[] bytes = mi.getValue();
+             ZipEntry e = new ZipEntry(name);
+-            e.setTime(System.currentTimeMillis());
++            if (System.getenv("SOURCE_DATE_EPOCH") != null)
++                e.setTime(1000 * Long.parseLong(System.getenv("SOURCE_DATE_EPOCH")));
++            else
++                e.setTime(System.currentTimeMillis());
+             if (flag0) {
+                 crc32ModuleInfo(e, bytes);
+             }
+@@ -1065,7 +1077,10 @@
+             addMultiRelease(m);
+         }
+         ZipEntry e = new ZipEntry(MANIFEST_NAME);
+-        e.setTime(System.currentTimeMillis());
++        if (System.getenv("SOURCE_DATE_EPOCH") != null)
++            e.setTime(1000 * Long.parseLong(System.getenv("SOURCE_DATE_EPOCH")));
++        else
++            e.setTime(System.currentTimeMillis());
+         if (flag0) {
+             crc32Manifest(e, m);
+         }
diff --git a/gnu/packages/patches/openjdk-10-jtask-reproducibility.patch b/gnu/packages/patches/openjdk-10-jtask-reproducibility.patch
new file mode 100644
index 0000000000..3411ca12ae
--- /dev/null
+++ b/gnu/packages/patches/openjdk-10-jtask-reproducibility.patch
@@ -0,0 +1,53 @@
+--- jdk-10/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java.orig	2022-04-04 11:18:52.760626467 +0200
++++ jdk-10/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java	2022-04-04 12:03:40.645325687 +0200
+@@ -105,6 +105,7 @@
+ import jdk.internal.module.ModuleTarget;
+ import jdk.internal.module.Resources;
+ import jdk.tools.jlink.internal.Utils;
++import java.util.TreeSet;
+ 
+ import static java.util.stream.Collectors.joining;
+ 
+@@ -768,6 +769,7 @@
+         void processSection(JmodOutputStream out, Section section, Path path)
+             throws IOException
+         {
++            TreeSet<Path> paths = new TreeSet<>();
+             Files.walkFileTree(path, Set.of(FileVisitOption.FOLLOW_LINKS),
+                 Integer.MAX_VALUE, new SimpleFileVisitor<Path>() {
+                     @Override
+@@ -781,20 +783,24 @@
+ 
+                         if (!relPath.toString().equals(MODULE_INFO)
+                                 && !matches(relPath, excludes)) {
+-                            try (InputStream in = Files.newInputStream(file)) {
+-                                out.writeEntry(in, section, relPath.toString());
+-                            } catch (IOException x) {
+-                                if (x.getMessage().contains("duplicate entry")) {
+-                                    warning("warn.ignore.duplicate.entry",
+-                                            relPath.toString(), section);
+-                                    return FileVisitResult.CONTINUE;
+-                                }
+-                                throw x;
+-                            }
++                            paths.add(file);
+                         }
+                         return FileVisitResult.CONTINUE;
+                     }
+                 });
++            for (Path file : paths) {
++                Path relPath = path.relativize(file);
++                try (InputStream in = Files.newInputStream(file)) {
++                    out.writeEntry(in, section, relPath.toString());
++                } catch (IOException x) {
++                    if (x.getMessage().contains("duplicate entry")) {
++                        warning("warn.ignore.duplicate.entry",
++                                  relPath.toString(), section);
++                        continue;
++                    }
++                    throw x;
++                }
++            }
+         }
+ 
+         boolean matches(Path path, List<PathMatcher> matchers) {
diff --git a/gnu/packages/patches/openjdk-10-module-reproducibility.patch b/gnu/packages/patches/openjdk-10-module-reproducibility.patch
new file mode 100644
index 0000000000..165edd3b4a
--- /dev/null
+++ b/gnu/packages/patches/openjdk-10-module-reproducibility.patch
@@ -0,0 +1,305 @@
+From a52c4ef44c0553a399a8a47e528db92e3bf51c6c Mon Sep 17 00:00:00 2001
+From: Alan Bateman <alanb@openjdk.org>
+Date: Wed, 29 Apr 2020 08:38:28 +0100
+Subject: [PATCH] 8243666: ModuleHashes attribute generated for JMOD and JAR
+ files depends on timestamps
+
+Reviewed-by: mchung
+---
+
+--- orig/jdk-3cc80be736f2/src/java.base/share/classes/jdk/internal/module/ModuleHashesBuilder.java	2022-04-13 19:24:10.655695284 +0200
++++ jdk-3cc80be736f2/src/java.base/share/classes/jdk/internal/module/ModuleHashesBuilder.java	2022-04-14 02:43:48.610326492 +0200
+@@ -27,9 +27,8 @@
+ 
+ import java.io.PrintStream;
+ import java.lang.module.Configuration;
++import java.lang.module.ModuleReference;
+ import java.lang.module.ResolvedModule;
+-import java.net.URI;
+-import java.nio.file.Path;
+ import java.nio.file.Paths;
+ import java.util.ArrayDeque;
+ import java.util.Collections;
+@@ -39,8 +38,8 @@
+ import java.util.LinkedList;
+ import java.util.Map;
+ import java.util.Set;
++import java.util.TreeMap;
+ import java.util.function.Consumer;
+-import java.util.function.Function;
+ import java.util.stream.Stream;
+ import static java.util.stream.Collectors.*;
+ 
+@@ -101,7 +100,7 @@
+         // the modules to record the hashes - it is the first matching
+         // module and has not been hashed during the traversal.
+         Set<String> mods = new HashSet<>();
+-        Map<String, ModuleHashes> hashes = new HashMap<>();
++        Map<String, ModuleHashes> hashes = new TreeMap<>();
+         builder.build()
+                .orderedNodes()
+                .filter(mn -> roots.contains(mn) && !mods.contains(mn))
+@@ -116,27 +115,17 @@
+                    mods.addAll(ns);
+ 
+                    if (!ns.isEmpty()) {
+-                       Map<String, Path> moduleToPath = ns.stream()
+-                           .collect(toMap(Function.identity(), this::moduleToPath));
+-                       hashes.put(mn, ModuleHashes.generate(moduleToPath, "SHA-256"));
++                       Set<ModuleReference> mrefs = ns.stream()
++                               .map(name -> configuration.findModule(name)
++                                                         .orElseThrow(InternalError::new))
++                               .map(ResolvedModule::reference)
++                               .collect(toSet());
++                       hashes.put(mn, ModuleHashes.generate(mrefs, "SHA-256"));
+                    }
+                });
+         return hashes;
+     }
+ 
+-    private Path moduleToPath(String name) {
+-        ResolvedModule rm = configuration.findModule(name).orElseThrow(
+-            () -> new InternalError("Selected module " + name + " not on module path"));
+-
+-        URI uri = rm.reference().location().get();
+-        Path path = Paths.get(uri);
+-        String fn = path.getFileName().toString();
+-        if (!fn.endsWith(".jar") && !fn.endsWith(".jmod")) {
+-            throw new UnsupportedOperationException(path + " is not a modular JAR or jmod file");
+-        }
+-        return path;
+-    }
+-
+     /*
+      * Utility class
+      */diff -ru orig/jdk-3cc80be736f2/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java jdk-3cc80be736f2/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java
+--- orig/jdk-3cc80be736f2/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java	1970-01-01 01:00:01.000000000 +0100
++++ jdk-3cc80be736f2/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java	2022-04-12 16:58:05.639985936 +0200
+@@ -26,17 +26,21 @@
+ package jdk.internal.module;
+ 
+ import java.io.IOException;
++import java.io.InputStream;
+ import java.io.UncheckedIOException;
+-import java.nio.ByteBuffer;
+-import java.nio.channels.FileChannel;
+-import java.nio.file.Path;
++import java.lang.module.ModuleReader;
++import java.lang.module.ModuleReference;
++import java.nio.charset.StandardCharsets;
+ import java.security.MessageDigest;
+ import java.security.NoSuchAlgorithmException;
++import java.util.Arrays;
+ import java.util.Collections;
+ import java.util.HashMap;
+ import java.util.Map;
+ import java.util.Objects;
+ import java.util.Set;
++import java.util.TreeMap;
++import java.util.function.Supplier;
+ 
+ /**
+  * The result of hashing the contents of a number of module artifacts.
+@@ -60,8 +64,8 @@
+      * @param algorithm   the algorithm used to create the hashes
+      * @param nameToHash  the map of module name to hash value
+      */
+-    public ModuleHashes(String algorithm, Map<String, byte[]> nameToHash) {
+-        this.algorithm = algorithm;
++    ModuleHashes(String algorithm, Map<String, byte[]> nameToHash) {
++        this.algorithm = Objects.requireNonNull(algorithm);
+         this.nameToHash = Collections.unmodifiableMap(nameToHash);
+     }
+ 
+@@ -95,54 +99,125 @@
+     }
+ 
+     /**
+-     * Computes the hash for the given file with the given message digest
+-     * algorithm.
++     * Computes a hash from the names and content of a module.
+      *
++     * @param reader the module reader to access the module content
++     * @param algorithm the name of the message digest algorithm to use
++     * @return the hash
++     * @throws IllegalArgumentException if digest algorithm is not supported
+      * @throws UncheckedIOException if an I/O error occurs
+      * @throws RuntimeException if the algorithm is not available
+      */
+-    public static byte[] computeHash(Path file, String algorithm) {
++    private static byte[] computeHash(ModuleReader reader, String algorithm) {
++        MessageDigest md;
+         try {
+-            MessageDigest md = MessageDigest.getInstance(algorithm);
+-
+-            // Ideally we would just mmap the file but this consumes too much
+-            // memory when jlink is running concurrently on very large jmods
+-            try (FileChannel fc = FileChannel.open(file)) {
+-                ByteBuffer bb = ByteBuffer.allocate(32*1024);
+-                while (fc.read(bb) > 0) {
+-                    bb.flip();
+-                    md.update(bb);
+-                    assert bb.remaining() == 0;
+-                    bb.clear();
+-                }
+-            }
+-
+-            return md.digest();
++            md = MessageDigest.getInstance(algorithm);
+         } catch (NoSuchAlgorithmException e) {
+-            throw new RuntimeException(e);
++            throw new IllegalArgumentException(e);
++        }
++        try {
++            byte[] buf = new byte[32*1024];
++            reader.list().sorted().forEach(rn -> {
++                md.update(rn.getBytes(StandardCharsets.UTF_8));
++                try (InputStream in = reader.open(rn).orElseThrow(java.util.NoSuchElementException::new)) {
++                    int n;
++                    while ((n = in.read(buf)) > 0) {
++                        md.update(buf, 0, n);
++                    }
++                } catch (IOException ioe) {
++                    throw new UncheckedIOException(ioe);
++                }
++            });
+         } catch (IOException ioe) {
+             throw new UncheckedIOException(ioe);
+         }
++        return md.digest();
+     }
+ 
+     /**
+-     * Computes the hash for every entry in the given map, returning a
+-     * {@code ModuleHashes} to encapsulate the result. The map key is
+-     * the entry name, typically the module name. The map value is the file
+-     * path to the entry (module artifact).
++     * Computes a hash from the names and content of a module.
+      *
++     * @param supplier supplies the module reader to access the module content
++     * @param algorithm the name of the message digest algorithm to use
++     * @return the hash
++     * @throws IllegalArgumentException if digest algorithm is not supported
++     * @throws UncheckedIOException if an I/O error occurs
++     */
++    static byte[] computeHash(Supplier<ModuleReader> supplier, String algorithm) {
++        try (ModuleReader reader = supplier.get()) {
++            return computeHash(reader, algorithm);
++        } catch (IOException ioe) {
++            throw new UncheckedIOException(ioe);
++        }
++    }
++
++    /**
++     * Computes the hash from the names and content of a set of modules. Returns
++     * a {@code ModuleHashes} to encapsulate the result.
++     * @param mrefs the set of modules
++     * @param algorithm the name of the message digest algorithm to use
+      * @return ModuleHashes that encapsulates the hashes
++     * @throws IllegalArgumentException if digest algorithm is not supported
++     * @throws UncheckedIOException if an I/O error occurs
+      */
+-    public static ModuleHashes generate(Map<String, Path> map, String algorithm) {
++    static ModuleHashes generate(Set<ModuleReference> mrefs, String algorithm) {
+         Map<String, byte[]> nameToHash = new HashMap<>();
+-        for (Map.Entry<String, Path> entry: map.entrySet()) {
+-            String name = entry.getKey();
+-            Path path = entry.getValue();
+-            nameToHash.put(name, computeHash(path, algorithm));
++        for (ModuleReference mref : mrefs) {
++            try (ModuleReader reader = mref.open()) {
++                byte[] hash = computeHash(reader, algorithm);
++                nameToHash.put(mref.descriptor().name(), hash);
++            } catch (IOException ioe) {
++                throw new UncheckedIOException(ioe);
++            }
+         }
+         return new ModuleHashes(algorithm, nameToHash);
+     }
+ 
++    @Override
++    public int hashCode() {
++        int h = algorithm.hashCode();
++        for (Map.Entry<String, byte[]> e : nameToHash.entrySet()) {
++            h = h * 31 + e.getKey().hashCode();
++            h = h * 31 + Arrays.hashCode(e.getValue());
++        }
++        return h;
++    }
++
++    @Override
++    public boolean equals(Object obj) {
++        if (!(obj instanceof ModuleHashes))
++            return false;
++        ModuleHashes other = (ModuleHashes) obj;
++        if (!algorithm.equals(other.algorithm)
++                || nameToHash.size() != other.nameToHash.size())
++            return false;
++        for (Map.Entry<String, byte[]> e : nameToHash.entrySet()) {
++            String name = e.getKey();
++            byte[] hash = e.getValue();
++            if (!Arrays.equals(hash, other.nameToHash.get(name)))
++                return false;
++        }
++        return true;
++    }
++
++    @Override
++    public String toString() {
++        StringBuilder sb = new StringBuilder(algorithm);
++        sb.append(" ");
++        nameToHash.entrySet()
++                .stream()
++                .sorted(Map.Entry.comparingByKey())
++                .forEach(e -> {
++                    sb.append(e.getKey());
++                    sb.append("=");
++                    byte[] ba = e.getValue();
++                    for (byte b : ba) {
++                        sb.append(String.format("%02x", b & 0xff));
++                    }
++                });
++        return sb.toString();
++    }
++
+     /**
+      * This is used by jdk.internal.module.SystemModules class
+      * generated at link time.
+diff -ru orig/jdk-3cc80be736f2/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java jdk-3cc80be736f2/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java
+--- orig/jdk-3cc80be736f2/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java	1970-01-01 01:00:01.000000000 +0100
++++ jdk-3cc80be736f2/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java	2022-04-12 16:43:12.967868689 +0200
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
++ * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
+  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+  *
+  * This code is free software; you can redistribute it and/or modify it
+diff -ru orig/jdk-3cc80be736f2/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java jdk-3cc80be736f2/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java
+--- orig/jdk-3cc80be736f2/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java	1970-01-01 01:00:01.000000000 +0100
++++ jdk-3cc80be736f2/src/java.base/share/classes/jdk/internal/module/ModuleReferences.java	2022-04-12 16:43:12.971868797 +0200
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
++ * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
+  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+  *
+  * This code is free software; you can redistribute it and/or modify it
+@@ -95,7 +95,7 @@
+                                         Path file) {
+         URI uri = file.toUri();
+         Supplier<ModuleReader> supplier = () -> new JarModuleReader(file, uri);
+-        HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
++        HashSupplier hasher = (a) -> ModuleHashes.computeHash(supplier, a);
+         return newModule(attrs, uri, supplier, patcher, hasher);
+     }
+ 
+@@ -105,7 +105,7 @@
+     static ModuleReference newJModModule(ModuleInfo.Attributes attrs, Path file) {
+         URI uri = file.toUri();
+         Supplier<ModuleReader> supplier = () -> new JModModuleReader(file, uri);
+-        HashSupplier hasher = (a) -> ModuleHashes.computeHash(file, a);
++        HashSupplier hasher = (a) -> ModuleHashes.computeHash(supplier, a);
+         return newModule(attrs, uri, supplier, null, hasher);
+     }
+ 
diff --git a/gnu/packages/patches/openjdk-10-module3-reproducibility.patch b/gnu/packages/patches/openjdk-10-module3-reproducibility.patch
new file mode 100644
index 0000000000..bc54803bea
--- /dev/null
+++ b/gnu/packages/patches/openjdk-10-module3-reproducibility.patch
@@ -0,0 +1,34 @@
+Danny wrote.
+
+--- orig/jdk-3cc80be736f2/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java	1970-01-01 01:00:01.000000000 +0100
++++ jdk-3cc80be736f2/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java	2022-04-13 17:30:37.242775977 +0200
+@@ -43,6 +43,7 @@
+ import java.util.Objects;
+ import java.util.Optional;
+ import java.util.Set;
++import java.util.TreeSet;
+ import java.util.function.Supplier;
+ import java.util.stream.Collectors;
+ import java.util.stream.Stream;
+@@ -2155,9 +2156,9 @@
+          * @return The module descriptor
+          */
+         public ModuleDescriptor build() {
+-            Set<Requires> requires = new HashSet<>(this.requires.values());
+-            Set<Exports> exports = new HashSet<>(this.exports.values());
+-            Set<Opens> opens = new HashSet<>(this.opens.values());
++            Set<Requires> requires = new TreeSet<>(this.requires.values());
++            Set<Exports> exports = new TreeSet<>(this.exports.values());
++            Set<Opens> opens = new TreeSet<>(this.opens.values());
+ 
+             // add dependency on java.base
+             if (strict
+@@ -2169,7 +2170,7 @@
+                                           null));
+             }
+ 
+-            Set<Provides> provides = new HashSet<>(this.provides.values());
++            Set<Provides> provides = new TreeSet<>(this.provides.values());
+ 
+             return new ModuleDescriptor(name,
+                                         version,
diff --git a/gnu/packages/patches/openjdk-10-module4-reproducibility.patch b/gnu/packages/patches/openjdk-10-module4-reproducibility.patch
new file mode 100644
index 0000000000..051c9344eb
--- /dev/null
+++ b/gnu/packages/patches/openjdk-10-module4-reproducibility.patch
@@ -0,0 +1,14 @@
+Danny wrote it
+
+--- orig/jdk-6fa770f9f8ab/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java	2022-04-13 19:24:12.655749459 +0200
++++ jdk-6fa770f9f8ab/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java	2022-04-14 01:53:23.555465018 +0200
+@@ -861,7 +861,8 @@
+          */
+         private void genModuleReads(ClassWriter cw, Configuration cf) {
+             // module name -> names of modules that it reads
+-            Map<String, Set<String>> map = cf.modules().stream()
++            Map<String, Set<String>> map = cf.modules().stream()
++                    .sorted(java.util.Comparator.comparing(ResolvedModule::name))
+                     .collect(Collectors.toMap(
+                             ResolvedModule::name,
+                             m -> m.reads().stream()
-- 
2.36.1
M
M
Maxime Devos wrote on 1 Jun 15:12 +0200
Re: [bug#55751] [PATCH 1/8] gnu: openjdk9: Make build reproducible.
7a65304d61319d38300eb2dafed2fa0ed60e5afe.camel@telenet.be
dannym@scratchpost.org schreef op wo 01-06-2022 om 15:00 [+0200]:
Toggle quote (6 lines)
>         #:imported-modules
>         ((guix build syscalls)
> +        (srfi srfi-35)
>          ,@%gnu-build-system-modules)


#:imported-modules is not for importing modules as in use-modules, but
for copying modules. By adding (srfi srfi-35), you copy (srfi srfi-35)
from the Guile against which Guix is compiled. Use #:modules instead.

Greetings,
Maxime;
-----BEGIN PGP SIGNATURE-----

iI0EABYKADUWIQTB8z7iDFKP233XAR9J4+4iGRcl7gUCYpdlyRccbWF4aW1lZGV2
b3NAdGVsZW5ldC5iZQAKCRBJ4+4iGRcl7qAXAP0dqMPhw9BJyvfpoUYxOJNXN6pj
Lqx1cBxfWEtpZlDEMQEAuGXwYwoQvstCSxwPnVcOI8eJZNUY3QHVEyhZ9l0tPAM=
=2cP9
-----END PGP SIGNATURE-----


M
M
Maxime Devos wrote on 1 Jun 15:14 +0200
2991291cc72e170010e11f782943675e309cae32.camel@telenet.be
dannym@scratchpost.org schreef op wo 01-06-2022 om 15:00 [+0200]:
Toggle quote (10 lines)
> +++ b/gnu/packages/patches/openjdk-9-module-reproducibility.patch
> @@ -0,0 +1,296 @@
> +From a52c4ef44c0553a399a8a47e528db92e3bf51c6c Mon Sep 17 00:00:00 2001
> +From: Alan Bateman <alanb@openjdk.org>
> +Date: Wed, 29 Apr 2020 08:38:28 +0100
> +Subject: [PATCH] 8243666: ModuleHashes attribute generated for JMOD and JAR
> + files depends on timestamps
> +
> +Reviewed-by: mchung

IIUC, "guix lint" will want you tu put a link to upstream.

Greetings,
Maxime.
-----BEGIN PGP SIGNATURE-----

iI0EABYKADUWIQTB8z7iDFKP233XAR9J4+4iGRcl7gUCYpdmNBccbWF4aW1lZGV2
b3NAdGVsZW5ldC5iZQAKCRBJ4+4iGRcl7vLjAQDh/QsZBDDHzA3zeShpIz1MJJ2G
5Uz+qtcXVdB1c4dRgwD/QL1MSSF9LLF80fb0xVh0QYhbPPRejSEtn0FdrkYt6gs=
=MBk5
-----END PGP SIGNATURE-----


M
M
Maxime Devos wrote on 1 Jun 15:18 +0200
e26ec38cbd9238b9a2c3b77ba0f42985a5a2eb23.camel@telenet.be
dannym@scratchpost.org schreef op wo 01-06-2022 om 15:00 [+0200]:
Toggle quote (5 lines)
> +                             (let ((code (system* "unzip" "--" zip)))
> +                               (write code)
> +                               (newline)
> +                               (when (> (status:exit-val code) 1) ; 1 is just a warning

What's the warning? Maybe the warning can be addressed or we could ask
unzip to not do warnings and then this could simplified to (invoke
"unzip" ...).

Toggle quote (7 lines)
> +                                 (raise (condition (&invoke-error
> +                                                    (program "unzip")
> +                                                    (arguments (list "--" zip))
> +                                                    (exit-status (status:exit-val code))
> +                                                    (term-signal (status:term-sig code))
> +                                                    (stop-signal (status:stop-sig code))))))))

This block could use a block explaining what it's for.
Likewise for the other undocumented block of code.
-----BEGIN PGP SIGNATURE-----

iI0EABYKADUWIQTB8z7iDFKP233XAR9J4+4iGRcl7gUCYpdnIBccbWF4aW1lZGV2
b3NAdGVsZW5ldC5iZQAKCRBJ4+4iGRcl7uR/AQC6CUjopSoGWJMdpYZ1cTsHnISm
QN2DBUa/ndxGTi3gYAEAvpGjOKVH3viNm0tbgGY8ge8luCixo7kC+pnbhCJO0ws=
=BDil
-----END PGP SIGNATURE-----


M
M
Maxime Devos wrote on 1 Jun 15:20 +0200
Re: [bug#55751] [PATCH 0/8] Towards reproducible openjdk
045d010bee264dc8e257fb594f2791b1d6cfe80f.camel@telenet.be
dannym@scratchpost.org schreef op wo 01-06-2022 om 14:57 [+0200]:
Toggle quote (14 lines)
> From: Danny Milosavljevic <dannym@scratchpost.org>
>
> This patchseries improves the reproducibility of openjdk.
>
> After it:
> * openjdk9 is reproducible.
> * openjdk10 has only a few non-reproducible parts.
> * openjdk11 has a number of non-reproducible parts.
> * openjdk12's "doc" output is still not reproducible ("Generated by javadoc" comment with timestamp in it)
> * openjdk13 still has non-reproducible parts (jmod, modules, classes.jsa, src.zip)
> * openjdk14 still has very few non-reproducible parts (jmod, modules, classes.jsa)
> * openjdk15 still has a number of non-reproducible parts (diz files only).
> * openjdk16 still has one non-reproducible part (classes*.jsa)

Now we are rebuilding everything Java anyway, could this be followed by
a patch removing the input labels and removing trailing #t?

Greetings,
Maxime.
?