jlink packages current platform's binaries - java

I am trying to build cross-platform archives of an application built using Java 11 and packaged with jlink.
For the cross-platform packaging I am basing my build on this answer. I have managed to make my Gradle build download the target platform's JDK and invoke jlink with the appropriate jmods folder, however the target image always includes the binaries and JRE structure of the host platform (in my case Windows, meaning the generated bin folder always includes DLLs and Windows executables). If I supply the --strip-native-commands flag then no executables are included at all, although the DLLs still are.
Is there any way to make jlink package the correct JRE files?
Host JDK: Windows Oracle JDK 11.0.10 x64
Target JDK: OpenJDK 11.0.2 x64
Sample Linux invocation:
C:\Program Files\Java\jdk-11.0.10/bin/jlink.exe
--module-path C:\projectdir\build\install\project-linux\lib;C:\projectdir\build\JREs\linux\jmods
--add-modules com.acme.app
--compress 2
--launcher app=com.acme.app/com.acme.app.Main
--no-header-files
--no-man-pages
--strip-debug
--dedup-legal-notices=error-if-not-same-content
--output C:\projectdir\build\packageFiles\linux
GraalVM
Using GraalVM CE Java 11 21.0.0 yields:
java.io.IOException: Invalid JMOD file: C:\jdks\graalvm-ce-java11-21.0.0\jmods\java.base.jmod
Which makes it seem like GraalVM's jlink always attempts to use the host's JMOD files.
OpenJDK
Using OpenJDK 11.0.2 x64 yields the same result of including the host's binary files in the created runtime image. The same behaviour is true for Zulu OpenJDK 11.0.10+9 x64.

Found the issue: the problem was with my reference to the jmods directory of both the Linux and the MacOS JDK distributions.
For the Linux one I mistakenly setup the build to download version 11.0.1 instead of 11.0.2, which ended up leading to the logic to flatten the hierarchy not flattening it. This means that the build/JREs/linux/jmods reference wasn't targeting any existing folder, meaning that jlink doesn't find the JDK modules there hence the host files being included.
The MacOS JDK has a completely different file structure so the flattening logic was just wrong. Ultimately this lead to the same missing jmods folder symptom.
With both issues fixed the jlink tool now correctly packages the target JDK's files when building cross-platform runtime images.

Related

UnsatisfiedLinkError: no lcms in system library path: /usr/lib/jvm/java-17-openjdk/lib

We are using Apache pdfbox. After switching from Java 8 on RedHat Linux, to Java 11 or Java 17 on Alpine linux, we get the following error:
java.lang.NoClassDefFoundError: Could not initialize class
org.apache.pdfbox.pdmodel.PDDocument at
com.openhtmltopdf.pdfboxout.PdfBoxRenderer.<init>(PdfBoxRenderer.java:118) at
com.openhtmltopdf.pdfboxout.PdfRendererBuilder.buildPdfRenderer(PdfRendererBuilder
com.openhtmltopdf.pdfboxout.PdfRendererBuilder.run(PdfRendererBuilder.java:35) at
The root error is:
UnsatisfiedLinkError: no lcms in system library path: /usr/lib/jvm/java-17-openjdk/lib
The root cause was that the default JRE for Alpine is a "headless" distribution that does not include graphics libraries such as the lcms library. To fix the issue we updated our docker build instructions to install the non headless version:
ENV JAVA_VERSION 17.0.3_p7-r2
# use full version of JRE!
RUN apk add --no-cache curl openjdk17-jre
If you want to see the differences between the openjdk17-jre and open-jdk17-headless, you can do so at:
https://pkgs.alpinelinux.org/packages
Note that the "non headless" package is additional. i.e. the base JRE package is installed first, then the non headless package simply adds the graphics libraries.

What are the parameters set by the JRE installer in my linux machine apart from copying JRE files?

I am writing a Java Swing application. I downloaded JRE for Linux platfrom from Oracle website and just bundled this JRE my application.
I have given a launcher script, in which I am referring the bundled JRE bin/java executable. So it works fine.
My question is, what is the difference between installing the JRE by downloading from the Oracle website and this procedure?
What are the extra parameters set by the JRE installer in my Linux machine apart from copying JRE files?
What are the environment variables set and what are the shared libraries copied? Any idea?
It depends a lot on how you install.
First, I assume you are talking about Java 8, since later versions of Java don't come with a separate JRE.
For Oracle Java 8 installations for Linux, there is a choice of rpm or other package installers or the basic Linux manual installation. The latter is described here. As you can see from the documentation, it's just a simple tar.gz which you unzip/untar into a directory of your choice, and that's it. The same as your bundled JRE.
if you want develop a application. you should download jdk, not jre.
jdk: java develop tookit
jre: java runtime.
linux has an old openjdk, but you can download jdk from oracle website. just download a xx.tar.gz, and untar it into:
/usr/java/jdk1.8xx
and set path:
JAVA_HOME=/usr/java/jdk1.8.0_121
CLASSPATH=.:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar
PATH=$PATH:$JAVA_HOME/bin
export JAVA_HOME PATH CLASSPATH

Create jre from OpenJDK Windows

We are switching from Oracle JDK/JRE to OpenJDK. Now I found only the JDK but I want to have a JRE as well from OpenJDK. This is for installing our application on the clients without the need of having the full JDK.
Is there a way to create a JRE package from the OpenJDK for Windows X64?
Inspired by the article Using jlink to Build Java Runtimes for non-Modular Applications I used the commands:
java --list-modules to get a list of all openjdk modules available
jlink --no-header-files --no-man-pages --compress=2 --add-modules <module-list from step 1> --output java-runtime to create a compact jre.
For OpendJDK 12 this is the command I ended up with:
jlink --no-header-files --no-man-pages --compress=2 --add-modules java.base,java.compiler,java.datatransfer,java.desktop,java.instrument,java.logging,java.management,java.management.rmi,java.naming,java.net.http,java.prefs,java.rmi,java.scripting,java.se,java.security.jgss,java.security.sasl,java.smartcardio,java.sql,java.sql.rowset,java.transaction.xa,java.xml,java.xml.crypto,jdk.accessibility,jdk.aot,jdk.attach,jdk.charsets,jdk.compiler,jdk.crypto.cryptoki,jdk.crypto.ec,jdk.crypto.mscapi,jdk.dynalink,jdk.editpad,jdk.hotspot.agent,jdk.httpserver,jdk.internal.ed,jdk.internal.jvmstat,jdk.internal.le,jdk.internal.opt,jdk.internal.vm.ci,jdk.internal.vm.compiler,jdk.internal.vm.compiler.management,jdk.jartool,jdk.javadoc,jdk.jcmd,jdk.jconsole,jdk.jdeps,jdk.jdi,jdk.jdwp.agent,jdk.jfr,jdk.jlink,jdk.jshell,jdk.jsobject,jdk.jstatd,jdk.localedata,jdk.management,jdk.management.agent,jdk.management.jfr,jdk.naming.dns,jdk.naming.rmi,jdk.net,jdk.pack,jdk.rmic,jdk.scripting.nashorn,jdk.scripting.nashorn.shell,jdk.sctp,jdk.security.auth,jdk.security.jgss,jdk.unsupported,jdk.unsupported.desktop,jdk.xml.dom,jdk.zipfs --output java-runtime
As others have mentioned, there's no longer a separate JRE distributed with the JDK since Java 9. You will need to use jlink and specify the modules your code depends on to generate a custom jre.
Because this can be a hassle, I've created a web-based tool to make it easier to create a custom JRE from an OpenJDK implementation (such as Oracle HotSpot, Eclipse OpenJ9, or Amazon Corretto) using jlink. The tool will give you the correct jlink command to run depending on your needs.
I've also included a way to make a standard Java SE JRE for those who just want a basic lightweight (~40-60 MB) JRE. If you know how to use a terminal, it'll take you less than 2 minutes to create a general-use JRE for JDK 9 and up.
Give it a try here - EasyJRE: https://justinmahar.github.io/easyjre/
Amazon Corretto OpenJDK https://aws.amazon.com/corretto/ has the builds for JDK and JRE
So I'm going to post something a little bit easier than what was posted by SteinarH. I didn't want to have to compile that list myself so.... this does it for you. Also for the sense of being a bit more concise I wouldn't label it java-runtime but instead jre-11 (or whatever version you are using).
This is PowerShell:
jlink --no-header-files --no-man-pages --compress=2 --add-modules $($(java --list-modules) -join "," -replace "#[0-9]*") --output jre-11
According to the Building OpenJDK document1:
Windows XP is not a supported platform, but all newer Windows should be able to build OpenJDK.
It then goes on to explain that Cygwin is required to do the build, the requirements for native compilers and libraries, and the issue of the "bootstrap" JDK that is required to compile the Java classes in the source tree.
But the clear implication is that you can build OpenJDK on Windows and for Windows ... even though the end result is not supported by Oracle or the OpenJDK project.
Note that the build document describes the make targets for creating JRE and JDK "images". I think it is saying that these are binary trees that can be copied to a target system and used. You could create ZIPs from them ...
But a simpler approach is to use "jlink" to generate a JRE-like executable; see the accepted answer.
#Andrew Henle points out that there are costs and (if you put yourself in the mindset of a corporate lawyer) risks in rolling your own JRE. Whether you just use it internally or you provide it to customers. If this is a concern, you are in a bit of a bind:
From Java 9 onwards, Oracle does not ship JRE distributions at all. Not for Oracle Java. Not for OpenJDK Java. As far as Oracle is concerned, JREs end after Java 8.
Anything that you build for yourself is a cost and a (erm) risk.
Fortunately, there are 3rd-party vendors who ship JRE distributions for Java on Windows. (Both AdoptOpenJDK and Azul do at the time of writing).
Alternatively, just use an Oracle JDK distro. Disk space is cheap, networks are fast.
1 - That link is for the Java 9 version of the document. For others, you should be able to find a corresponding "building.html" document at the same place in the source tree.
Since Java 9, you can use jlink to create a custom runtime environment for your application, using only the modules you actually need to run, which is typically even smaller than the traditional JRE was.
I'm using openjdk 11 in place of jre8 since oracle announced the license change. My customers were unhappy about them changing the agreement.
To get it to work, all I had to do was rename the sdk folder to jre.
One problem I did have was an external library dll. where open jdk complained it could no longer find in the class path. To fix that I just copied the dlls to the system32 folder.
Hope this helps
Stuart
On this site you can get jdk and jre (the jdk contains jre)
https://adoptopenjdk.net/upstream.html.
But if you need to build a jre you can use the following code in python (I have taken the answer from #SteinarH), the code assumes that you are in the jdk bin and that there is no directory called jre at the previous level.
import os
jmod_str = os.popen('java --list-modules').read()
init = jmod_str.index('#')
end = jmod_str.index('\n')
version = jmod_str[init:end]
jmod_list = jmod_str.replace(version, '').replace('\n', ',')
jmod_list = jmod_list[:-1] if jmod_list[-1] == ',' else jmod_list
cmd = 'jlink --no-header-files --no-man-pages --compress=2 --module-path ..\jmods --add-modules '+ jmod_list + ' --output ..\jre'
As far as I know the only place you can download OpenJDK for Windows is Azul website. However, they only seem to provide full JDK, so if you want just the JRE you need to build it yourself as Stephen C suggested.
For a more straightforward approach i wrote this little tool, which you can use under Windows:
https://github.com/g3t00ls/OpenJDKtoOpenJRE
I personally use OpenJDK from:
https://jdk.java.net/
It basicly does exactly what SteinarH wrote.
Currently it includes all java modules and exludes all jdk modules! A GUI to select required modules / an auto detect function for required modules for even smaller JRE's will probably be added soon!
Currently it still needs jlink, so only >=v9 JDK's will work! This could change in the future!
Reasons for making another answer:
I needed a single line to make a standard JRE to put in my Windows installer
I didn't want to have to update it when I upgrade java
Method:
I back engineered the output from the page that Justin made: https://stackoverflow.com/a/54997476/1280293 (Excellent utility)
I took the output of java --list-modules
selected only lines that start with java
removed the #versionnumber from the end of each line
joined the array into a comma separated string
appended it to jlink --output jre --compress=2 --no-header-files --no-man-pages --module-path ../jmods --add-modules
Notes:
This command assumes you have added your java bin to your path
This creates it's output directory in the folder you run the command from
PowerShell:
jlink --output jre --compress=2 --no-header-files --no-man-pages --module-path ../jmods --add-modules "$((java --list-modules | Select-String -Pattern '^(java[^#]+?)#' | % {"$($_.Matches.Groups[1].value)"}) -join ',')"
Azul Systems provides up-to date Windows JREs.
Here the link to Java 18 Windows JRE:
https://www.azul.com/downloads/?os=windows&architecture=x86-64-bit&package=jre
Amazon Corretto nor AdoptOpenJDK provide Windows JREs.
We are using the Azul distribution since Oracle decided to change its licensing and made very good experience.
Also previous versions can be found:

Make .deb for JDK8 with JavaPackage

I'm trying to install JDK8 on Debian Stretch. The recommended way is to use JavaPackage.
I have successfully packaged JDK6 and JDK7 using this method:
Download the JDK archive from Oracle
fakeroot make-jpkg jdk-7u55-linux-x64.tar.gz
dpkg -i the-resulting.deb
I can successfully create a .deb from the JDK8 archive, but when I install it with dpkg I'm missing a lot of dependencies.
gnome-icon-theme gtk-update-icon-cache java-common libasound2 libasound2-data libatk1.0-0 libatk1.0-data libcroco3 libdrm-amdgpu1 libdrm-intel1 libdrm-nouveau2 libdrm-radeon1 libdrm2 libgail-common libgail18 libgl1-mesa-dri libgl1-mesa-glx libglapi-mesa libgtk2.0-0 libgtk2.0-bin libgtk2.0-common libllvm3.9 libpciaccess0 librsvg2-2 librsvg2-common libtxc-dxtn-s2tc libx11-xcb1 libxcb-dri2-0 libxcb-dri3-0 libxcb-glx0 libxcb-present0 libxcb-sync1 libxcomposite1 libxcursor1 libxdamage1 libxfixes3 libxi6 libxinerama1 libxrandr2 libxshmfence1 libxtst6 libxxf86vm1 x11-common
I can install them manually but I'm not sure why I didn't have this dependency problem with the earlier JDKs. I'm writing an install script and it would please me to only install a single .deb rather than having to install all the extra dependencies separately.
make-jpkg supports JDK8 according to its man page.
make-jpkg builds a Debian package from the given Java distribution FILE.
Supported java binary distributions currently include:
* Oracle (http://www.oracle.com/technetwork/java/javase/downloads) :
- The Java Development Kit (JDK), version 6, 7 and 8
- The Java Runtime Environment (JRE), version 6, 7 and 8
- The Java API Javadoc, version 6, 7 and 8
(Choose tar.gz archives or self-extracting archives, do _not_ choose the RPM!)
Can anyone provide some insight as to why the .deb's created from earlier JDKs don't require any extra dependencies. Or perhaps it's just a case of their dependencies already existing in a stock Debian install.
Edit: I found this thread at Server Fault which goes some way to explaining it:
The reason this happens is that you are building a deb package from a binary distribution, i.e. a precompiled JDK. Usually, Debian packages are built from source, not from binaries. In order to do so, the person building the package would add all libraries the source depends on to a certain file (debian/control). Without those libraries installed, the source cannot be compiled and therefore would not result in a package.

Where is tools.jar located?

Running CentOS 6, Java 1.7.0_25 OpenJDK
Upon installing the RPM I saw it say
Unpacking JAR files...
rt.jar
jsee.jar
charsets.jar
>tools.jar
Where is tools.jar located? I checked /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.25.x86_64
No where to be found.
Not sure what rpm you used, but if you install from yum repo, you should install java-1.7.0-openjdk-devel in addition to java-1.7.0-openjdk.
Then you will find tools.jar in /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.xx.x86_64/lib directory.
On Linux, you can use locate tools.jar to find where the file is.
Typically, it should be in the lib/ directory of your jvm. On Ubuntu/Debian, it is located in directory /usr/lib/jvm/java-xxxxx/lib/tools.jar.
For example, with openjdk 7, on amd64, I'll find it under /usr/lib/jvm/java-7-openjdk-amd64/lib/tools.jar.
I have no installation to check it, but I think that the directory structure is the same under CentOS (cf. https://serverfault.com/questions/50883/what-is-the-value-of-java-home-for-centos)
Linux Centos 6,
you can use sudo find / -name "tools.jar" command to find the file location.
tools.jar is normally located under /usr/lib/jvm/java-1.7.0.70.x86_64/lib/tools.jar
tools.jar is not in JRE.
My case, tools.jar file is generated only after installing java-1.7.0-openjdk-devel.
sudo yum install java-1.7.0-openjdk-devel
On windows, I could find it at \jdk1.7.0\lib. You can find java directory structure here
No,it should be in in Lib folder
JDK and JRE File Structure
c:\jdkx.x.x\lib
Files used by the development tools. These include tools.jar, which contains non-core classes for support of the tools and utilities in the JDK. Also includes dt.jar, the DesignTime archive of BeanInfo files that tell interactive development environments (IDE's) how to display the Java components and how to let the developer customize them for an application.

Categories

Resources