How to create cross platform executables for JDK9 application using JLink command - java-9

I am trying to create cross platform / platform independent executables for my JAVA-9 application / project jigsaw.
I think jlink command will create only platform specific executable/runtime.

JLink (covered by JEP 282) creates modular runtime images (covered by JEP 220, particularly the section New run-time image structure). These images are a generalization of JRE, JDK, and compact profiles and are OS specific like they are. JLink can hence not be used to create cross-platform executables.
That said, it is possible to run JLink on one operating system and create a runtime image for a different OS. All you have to do for that is to download and unpack a JDK 9 (same version as the one JLink comes from) for that and put its jmods folder on the module path for the JLink call.

I know this question is old, but since it was one of the top Google results for me before posting my own question I decided to document my findings here as well.
Faced the same problem while attempting to create runtime images with jlink for Java 11. The problem boiled down to incorrectly referencing the target JDK's jmods folder which in turn meant that the JDK's modules weren't found in the module path. jlink then defaulted to include the host JDK's module files (and corresponding binaries, libraries, etc) in the generated runtime image. By correctly referencing the target JDK's jmods directory then the generated runtime image contains the platform-specific executables and accompanying files.
This was tested on a Windows machine by creating runtime images for Windows, Linux and MacOS.

Related

"flutter run -d windows --release" works but executable doesn't

I do have a strange behavior with a flutter package I am building. It uses FFI to integrate a custom-made c++ library.
When I run flutter run -d windows --release the code starts and I do have the window with the code running.
However, when I go to the directory where the executable is stored and I run it, the program starts but the library is not loaded. I do see also that when I run flutter test, it complains that it cannot load the library. I have checked that the dll's needed are there using dependenciesGUI.exe and it seems that everything is fine, at least on my side. I do see however that within kernel32.dll I am missing ext-ms-win-oobe-query-l1-1-0.dll.
I am using Visual Studio 2022 with the x64 configuration.
Any idea on what could be the issue? For me it is VERY puzzling to be able to run the software through flutter but not with the executable directly.
Thanks!
Yours,
Pi-r
EDIT:
I compared my package with a fresh package built with flutter. With a fresh package, the behavior is the one expected: I can have the program run normally or with flutter run.
I compared the libraries of the clean package with the ones linked in my package. They are the same (with the same missing dlls which do not seem to pose an issue).
I also checked that the exported functions I needed where present -> It is the case.
The only difference I can see is that using flutter run adds a series of libraries to the path. Has I am a Linux person, I do not know of a tool that could be used to detect what is the missing library. I am open to write a separated c++ code that would load the library if it could help me identify what is the issue... ANY tips/tricks would be greatly appreciated :)
I finally found the issue I had and it is related to a different behavior under Linux and under Windows (as you will guess, I am a Linux person).
When compiled under Linux, I can force the compiler to link multiple libraries relatively to my main library. I discovered that this is not the case under Windows. Either the dlls are in the executable folder or in the Path.
For the sake of code clarity, my package uses two different libraries. Library A, which is compiled from flutter with the ffi package, called library B. First the second library was in the asset folder and with the relative linking of Linux, it was working perfectly. But it did not work under Windows until I explicitly copied the two in the same directory of the executable.
The solution was then to ensure that both libraries are copied correctly in the directory of the flutter executable. This can be done easily if you add the dependent libraries to the bundle variable in the CMakeLists.txt of the package.
However, this doesn't work when you do the testing (flutter test). As the bundle mechanism seems to be not propagated to the test function. Therefore here, the only solution is to copy the dependent libraries to the root directory of the source code :vomiting_face:
I must point out that this is only the case under Windows, for Linux, it works out of the box...

Is it possible to add/modify system include path without modifying cmake in clion?

I'm working on a cross-platform project which requires dependencies which are not available on my machine. I basically use a cross-platform tool-chain in docker to build everything. Using buildroot I build a whole Linux system for an ARM platform.
So, I was wondering if there is an option to let Clion know or pick another path for system include header files? Then at least clion can help with code completion etc.

TOOLCHAIN_HOST_TASK Vs TOOLCHAIN_TARGET_TASK

I am sorry for naive question. I could not understand the difference between these Yocto variables. The Manual says
TOOLCHAIN_HOST_TASK: Lists packages that make up the host part of the
SDK (i.e. the part that runs on the SDKMACHINE). When you use bitbake
-c populate_sdk to create the SDK, a set of default packages apply. This variable allows you to add more packages.
And
TOOLCHAIN_TARGET_TASK: Lists packages that make up the target part of
the SDK (i.e. the part built for the target hardware).
I could not understand what is difference between Host part of SDK and target part of SDK ?
As for I understand, Host part is that we expanded on our host PC and use it for cross-development. What is target part of SDK ?
The recipes added to TOOLCHAIN_TARGET_TASK will be cross-compiled for the target architecture, and included in the target sysroot in the SDK.
The recipes added to TOOLCHAIN_HOST_TASK will be built to run on the developer machine.
So if you want a certain library available in the SDK, so that you can develop applications linking to it, add it to TOOLCHAIN_TARGET_TASK. Then the cross-compiles library and its header files will be available in the SDK.
If you on the other hand have a tool that's need during building, like a code-generator or cmake, you add it to TOOLCHAIN_HOST_TASK so that it's available on the developer machine during the build of the target software.

Defining a heirarchy for native code via ABIs

Please forgive my poor terminology, I'm not very familiar with the NDK.
I use two libraries. One generates native *.so libaries for armeabi, the other for armeabi-v7a. I would like to define a hierarchy to use the arm v7a libraries first, then basic arm second. At the moment, I'm using:
ndk {
abiFilters "armeabi-v7a", "x86", "armeabi"
}
To define the chipsets that I have libraries for, but that will only pull in the specific chipset of the decide. I.E., if the device is armeabi-v7a, the "armeabi-v7a" *.so libraries will be pulled in, and not "armeabi". If I remove "armeabi-v7a" from the config, "armeabi" will be pulled in.
Is there a way to define a hierarchy inside the app's build.gradle using flavours, or some other mechanism? This seems possible using Android.mk, but that seems more appropriate for if I was generating these *.so files myself, which I'm not. I'm just trying to use *.so files included in .jar(s) or .aar(s) that I'm including in my project.
For a fat APK (where you have multiple ABIs worth of libraries in one APK), Android's package manager will handle selecting the right libraries for the device you're running on.
For a split APK (with one APK per ABI), the play store is responsible for installing the correct one: http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits

Stripping the JRE to be bundled with an application - what can I omit?

I've been bundling JRE with my app by simply copying the files from $JAVA_HOME/jre to my app's distribution. This may be against the spirit of Java, but it reduces potential problems by ensuring that my app runs on a version of JRE that it was tested on (including the bitness; I use some JNI which requires that the JRE is a 32-bit version).
It works fine, but the whole distribution is somewhat big, so maybe some unnecessary files could be left out? Indeed, $JAVA_HOME/jre/README.txt contains the following advice:
The files that make up the Java SE Runtime Environment are divided into
two categories: required and optional. Optional files may be excluded
from redistributions of the Java SE Runtime Environment at the
vendor's discretion.
The following section contains a list of the files and directories that
may optionally be omitted from redistributions with the Java SE Runtime
Environment. All files not in these lists of optional files must be
included in redistributions of the runtime environment.
...When redistributing the JRE on Microsoft Windows as a private
application runtime (not accessible by other applications)
with a custom launcher, the following files are also
optional. These are libraries and executables that are used
for Java support in Internet Explorer and Mozilla family browsers;
these files are not needed in a private JRE redistribution.
What puzzles me is that the list of optional files includes, among others:
bin\java.exe
bin\javaw.exe
bin\javaws.exe
How can java/javaw.exe be optional? How am I supposed to start a Java application without them? Apparently I don't know something (likely), or the instructions are simply wrong.
When redistributing the JRE on Microsoft Windows as a private application runtime (not accessible by other applications) with a custom launcher, the following files are also optional.
If you embed the JVM (by linking against its shared libraries) in your own application, you do not need the standalone launcher executables. I think Eclipse works that way, for example.
If your app uses the java executable (via a batch file for example), then you need them, of course.
While this doesn't strictly relate to the question, for whole-program (or whole-platform) optimization of removing "un-needed code", I have found ProGuard to be a good tool. YMMV.

Resources