Summary
Add support for linking a custom runtime without packaged modules being present. Instead, use the current run-time image (a.k.a. lib/modules
image) and associated native binaries and auxiliary files from the current installed image.
Problem
Linking custom run-time images, specific to particular applications, currently require packaged modules of the JDK to be present (jmods
folder in a JDK install with modules within, for example java.base.jmod
for the java.base
module). Packaged modules, however, duplicate content already present in the JDK runtime image and are only needed for linking custom run-time images. Packaged modules don't influence run-time behaviour. Since packaged modules can add to the total size that a JDK installation takes on disk (~ 80-90MB extra disk space), it's been fairly common to not include them by default and make them available with a separate installable unit (e.g. in Linux RPM installers[1]). When Linux installers choose to do this, linking custom run-time images is not possible without also bringing in the extra installable unit. This problem is exacerbated when the JDK installation has been provided by a third party in a container. Supporting links based on the run-time image would allow for more flexible usage of the jlink tool (e.g. to reduce the set of included modules in a custom JDK run-time image)
Solution
The proposed solution is to allow for an additional mode to link a custom run-time image that is based on the current run-time image of the system if a user enables such a mode with the --enable-linkable-runtime
configure option. The bytecode for the class files is being taken from the run-time image's jimage (lib/modules
) provided those bytecodes don't differ from the ones in packaged modules. If they differ, the original bytecodes from packaged modules are restored at link-time using a delta file packaged in the jimage part of the jdk.jlink
module. It's not a goal of this proposal to eliminate the packaged modules jlink workflow as the run-time image based link's primary goal would be to further reduce a larger JDK run-time image into a smaller one. The proposed solution also acknowledges the fact that cross-links for a platform other than the current run-time system would not be possible.
Alternatives are to add the --keep-packaged-modules
hidden jlink
option when linking custom run-time images. This option isn't very widely known and isn't turned on by default when linking custom run-time images. More importantly, using --keep-packaged-modules
doesn't solve the extra disk space problem.
Specification
The run-time image based link is implemented by comparing the optimized jimage of a JDK build, produced by jlink, with the classes and resources of packaged modules. This difference is then being used to create a run-time image of the JDK that can then be used for linking. It does so by serializing those differences into the jimage file on a per module basis. Furthermore, tracking of non-class and -resource files of a module is being done so as to be able to determine the correct module contents. Native resources, configuration and license files are being tracked in a small plain text file in order to support the run-time image based link. Those small text files are part of the jdk.jlink
module in package jdk.tools.jlink.internal.runtimelink
(e.g. for the java.base
module that file is called fs_java.base_files
). The differences to the packaged modules view of classes and resources are being recorded in the jdk.jlink
module's jdk.tools.jlink.internal.runtimelink
package (e.g. for the java.base
module that file is called diff_java.base
and might be potentially empty). Both files get generated at JDK build time when --enable-linkable-runtime
configure option is used. When a JDK installation has been enabled for run-time linking and the absence of packaged modules is being detected, i.e. the jmods
folder is missing in $JAVA_HOME
, then a run-time image based link is being performed.
The jdk.jlink module needs to be present in the base run-time image used for the link. In order to produce a run-time link enabled JDK, the JDK needs to be built with the --enable-linkable-runtime
configure option.
If the current JDK image hasn't been enabled for run-time image based linking at build time an error is shown:
$ jlink --add-modules java.base --output ./build/java.base-runlink
Error: This JDK does not support linking from the current run-time image
On a JDK build that has been run-time image link enabled, jlink --help
shows this capability in its output:
$ jlink --help
[...]
Capabilities:
Linking from run-time image enabled
Conversely, for a JDK build that doesn't have the run-time image link capability it shows this in jlink --help
:
$ jlink --help
[...]
Capabilities:
Linking from run-time image disabled
In addition, with the --verbose
option, the run-time image based link mentions that modules are being taken from the run-time image as well as that a run-time image based link is being performed:
$ jlink --add-modules java.compiler --output ./build/java.base-runlink --verbose
Linking based on the current run-time image
java.base jrt:/java.base (run-time image)
java.compiler jrt:/java.compiler (run-time image)
Providers:
java.base provides java.nio.file.spi.FileSystemProvider used by java.base
Recursive run-time image based links are being prohibited. That is, the jdk.jlink
module cannot be added as a module when performing a run-time image based link:
$ jlink --add-modules jdk.jlink --output ./build/jdk-including-image
Error: This JDK does not contain packaged modules and
cannot be used to create another image with the jdk.jlink module
$ echo $?
1
When a file part of the run-time image has been modified the link is aborted:
$ ./bin/jlink --add-modules java.base --output ./build/custom-java-base
Error: /path/to/jdk/conf/net.properties has been modified
$ echo $?
1
Third-party modules can be added to a custom run-time image, but must be specified with the --module-path
option. In that case no JDK provided modules can be on the module path since otherwise a jlink using packaged modules would be performed:
$ jlink --add-modules leaf1 --module-path=test/jmods --verbose --output ./build/custom-module-runlink
Linking based on the current run-time image
java.base jrt:/java.base (run-time image)
leaf1 file:///path/to/test/jmods/leaf1.jmod
Providers:
java.base provides java.nio.file.spi.FileSystemProvider used by java.base
In order to implement the build-time generation of the difference to packaged modules a new hidden option for jlink
has been added: --generate-linkable-runtime
. It is being used when the run-time image for the JDK image is being generated at JDK build time with the feature turned on at configure time.
The full implementation can be seen in the proposed pull request: https://github.com/openjdk/jdk/pull/14787
References
[1] Size example of a jmods
sub-package in Fedora: https://koji.fedoraproject.org/koji/rpminfo?rpmID=38044764
- csr of
-
JDK-8311302 Implement JEP 493: Linking Run-Time Images without JMODs
- Resolved