VSCode, Java 11 JavaFX 18.0.2
I am trying to package my code up for distribution as a desktop app. In my case I want a fully self-contained app because of my target user's profile.
I have been through Jenkov add the Oracle docs here and here which suggest I need ant-javafx.jar. That jar file seems to have been dropped from the standard Java SDK some time around Java 7 and put into the regular JavaFX install lib folder.
It's not there in the build I have.
JavaFX seems to have gone to openjfx.io and nowhere in there can I see support for the ant packaging jar. In fact I see openjfx as a retrograde step as they are increasingly forcing everyone into paid plans (try going round and round the loop of downloading anything that doesn't require an LTS payment).
I have a suspicion that there is some silent assumption that everyone will use something from maven or gradle, and maybe the packaging tools are buried away in one of those build tools. For historical reasons I don't use either and it should be possible to do this packaging without one of them.
So where do I get the JavaFX Ant build tasks from without having to pay someone?
I have found that the following works as an alternative with Java 19 and OpenJFX 19. I use the maven-dependency-plugin to copy all the dependency jars (excluding JavaFX, which I use as modules from a "full" JDK [one that includes JavaFX)] into the target/lib directory.
#!/bin/bash
set -o errexit
set -o noclobber
set -o xtrace
# find dependency modules of required modules
DEP_MODS=$(jdeps -quiet --class-path "target/lib/*" --add-modules java.base,java.logging,java.sql,javafx.controls,javafx.fxml --multi-release base --ignore-missing-deps --print-module-deps target/myapp-4.0-beta.jar)
# create a modular runtime image
jlink --compress=1 --no-header-files --no-man-pages --add-modules "java.logging,java.sql,javafx.controls,javafx.fxml,$DEP_MODS" --output target/myapp-4.0-beta
# Example of running it out of the runtime image
# TEST target/myapp-4.0-beta/bin/java -cp "../../myapp-4.0-beta.jar:../../lib/*" org.myapp.App
# symlink to the artifact jar from the lib directory
$(cd target/lib && ln -s ../myapp-4.0-beta.jar)
# use the lib directory and modular runtime image as input to jpackage
jpackage --input target/lib --runtime-image target/myapp-4.0-beta --main-jar myapp-4.0-beta.jar --main-class org.myapp.App --type app-image --app-version 4.0 --name app --dest target/dist/bundle --mac-entitlements src/dist/mac/entitlements.plist
Related
I know you can solve this by adding
--module-path "pathToLib" --add-modules javafx.controls,javafx.fxml,javafx.graphics when running the jar file in command line.
But my question is, Is there no permanent solution to solve this error in system settings or configurations and be able to run a jar file as normal as java -jar myfile.jar rather than every time I am suppose to add the module java --module-path "C:\Users\..\Downloads\javafx-sdk-17.0.2\lib" --add-modules javafx.controls,javafx.fxml,javafx.graphics -jar myfile.jar
Also I know you can make a script for this operation for every jar file, but I was thinking of something like system settings or configuration that will be applicable for all jar file with javafx, and be able to run the jar file as normal as java -jar myFile.jar
I am using Ant as a build tool.
Recommended Alternatives
See the packaging resources of the JavaFX tag for recommended alternate solutions to a jar distribution: jlink, jpackage, or native image.
Using JRE's that include JavaFX
Pre-installed JREs that include JavaFX, such as some Bellsoft, Zulu, and Corretto distributions, will execute JavaFX apps without additional module specifiers because they include the JavaFX modules in the base module setup for their distributions.
Note, you must use the correct versions of the JDKs if you want a JDK which includes JavaFX (not all JDKs include JavaFX):
for BellSoft, download and install the "Full JDK", not the "Standard JDK".
for Zulu, download and install the package type "JDK FX", not "JDK".
You can also create your own JRE distribution that includes JavaFX modules using jlink (which is actually simpler to do than it may sound).
Using ant to build a single JAR containing App and JavaFX components
But I still hope that there might be a solution for the above while working with ANT as building tool for JavaFX.
There is some info on building modular JavaFX apps with ant in this answer:
bad name in value for --add-modules when trying to compile through ant
It probably isn’t everything you are looking for though.
To create a single executable jar using ant, you could try emulating the output of this maven JavaFX shade on classpath answer:
Maven Shade JavaFX runtime components are missing
But use ant tasks to build the massive shaded jar instead of maven. I don’t have explicit instructions for that, you would need to work out to accomplish that non-trivial task yourself.
The created jar will include a launcher class, your application code, dependent library code, JavaFX java, and native code. The jar will run on any modern JRE as long as you have included the native code for the relevant platform. The jar will run in the unsupported classpath configuration.
Zip Distributions
Or (better) create a zip distribution:
only put your own code in your app jar.
place the dependent libraries and JavaFX modules in a lib directory.
Create a script that invokes Java with your jar file running with the modules in the lib directory added.
Make your app modular if possible:
Define a module-info.java.
This step isn’t strictly necessary or reasonably possible for some apps.
Use ant to place everything in a zip file for distribution.
Include a jlink generated JRE in the zip if you want.
Note: the maven JavaFX plugin, once properly configured, can accomplish most of these tasks with a single command:
mvn javafx:jlink
Additional info
See the eden guide for resolving JavaFX runtime components.
Add a module-info.java file under your java/ folder and populate it with the following content:
module module_name {
requires javafx.controls;
requires javafx.fxml;
requires javafx.graphics;
requires java.base;
requires java.desktop;
opens com.example.matformater to javafx.graphics;
opens com.example.matformater.controller to javafx.fxml;}
It's been a few days since I've been trying to export a very simple project made in JavaFX but I have a very frustrating problem: To run the jar I need to open cmd navigate to the jdk folder and execute the following code java --module-path %path_to_JavaFX_on_my_pc% --add modules=javafx.controls,javafx.fxml,javafx.graphics -jar %path_to_jar% where I point to the jfx folder on the pc and add the necessary modules to run the jar.
run the jar using java java -jar %path_to_jar% results in the following error: Error: JavaFX runtime components are missing, and are required to run this application
The project is modular, having declared module-info.java with the following code:
module Timer {
requires java.prefs;
requires com.jfoenix;
requires javafx.base;
requires javafx.controls;
requires javafx.fxml;
requires javafx.graphics;
requires javafx.media;
requires javafx.web;
requires javafx.swing;
opens main;
exports main;
}
when exporting the artifact I include all the .jar contained in the javafx, so why should I point to it externally?
The app runs well when I run it through the IDE, I didn't even have to add VM options.
My goal is to create an application that can actually be distributed, without the user needing to have any knowledge beyond the basics to run it, no jre, jdk, jfx, cmd code, etc... just click twice and done.
The question is: How do I generate an executable file that can be opened with 2 clicks like any other application on the pc on *any pc?
finally I got a solution to my problem.
1 ° - It was necessary to solve the problem when generating a java artifact using javaFx in intelliJ: In JDK 13 the IDE threw the following error
Can't build artifact - fx: deploy is not available in this JDK
the easiest solution for that was to return on JDK 9 ond the javaFx was still built in and everything worked fine. Having done that, I was able to generate .jar artifacts that worked without the need to use command line tools.
2 ° -So I needed to generate a native executable for my application: In this topic there is an excellent list of tools that create launchers for java artifacts (Ideal was to convert but there gets a little complicated). What worked best for me was Jsmooth where I was able to set up a launcher that built in my .jar and where I could also attach a copy of the JRE for distribution on computers without Java
It is worth noting that I develop desktop applications just for my use and that of some friends, they do not work with sensitive data and do not require a high level of security and therefore there is no problem using an old version of jdk, in any other case, no recommend this approach.
Thank you all for your help.
I ran into the same problem with JavaFX 11. The way I did it, to be able to generate the jar artifact, I set the Project Settings - Artifacts - Type to JAR rather than JavaFX Application. That enabled me to create a jar in the out directory of my project. Afterwards, I wrote a batch file that created a custom jre for my app (as small as ~40 MB for a small app), including JavaFX. I called that bat file create.bat and placed that bat file in the same folder as my jar artifact.
Now, provided
my jar artifact is called app.jar,
path to JDK is D:\jdks\jdk11,
path to JFX mods is D:\jdks\jfx11\jmods,
module name is com.epsilon, and
path to Main class is com.epsilon.Main,
below is the contents of the bat file to create a custom JRE, including JavaFX. It created a custom JRE in the folder dist, the launch file is in the dist\bin directory called run.bat.
rem This sets the variable DIR to the current directory with the jar artifact
set DIR=%~dp0
rem This creates a temporary mod file
D:\jdks\jdk11\bin\jmod create --class-path %DIR%app.jar %DIR%temp.mod
rem This creates distributable JRE
D:\jdks\jdk11\bin\jlink ^
--compress=2 ^
--strip-debug ^
--no-man-pages ^
--launcher run=com.epsilon/com.epsilon.Main ^
--module-path D:\jdks\jdk11\jmods;D:\jdks\jfx11\jmods;%DIR% ^
--add-modules com.epsilon ^
--output %DIR%dist
rem This command deletes the temporary mod file
del %DIR%temp.mod
rem You can create a shortcut to your app above the "dist" folder and enter the below line to the shortcut's target property
rem %windir%\system32\cmd.exe /c start "" "%CD%\dist\bin\javaw.exe" -m com.epsilon/com.epsilon.Main
So, this has enabled me to create a working distributable without downgrading Java.
From my previous question, I know that JavaFX is not supported in RedHat 5.8 meaning, even when I have Java 8 (jdk1.8.0_05) installed on my Linux, a JAR file created in win7 can't be executed via java -jar helloworld.jar. Does that mean there is NO way to run JavaFX jars on this machine?
The problem with running JavaFX applications on RHEL5 is the version of glib that comes with that OS is not new enough. The trick, then, is to provide a newer version of that library and all of the other libraries that depend on it to the JRE. The next hurdle is that RHEL5 shared library loader won't load those libraries. You have to use a compatible loader. But the JVM has the path to the loader hard-coded in the executable! So you need a separate JVM with a custom loader path patched in. Roughly, the steps to get this working are...
Unpack the following packages from RHEL6:
glib2
libffi
glibc
glibc-common
zlib
gtk2
pango
cairo
pixman
Put all of the shared libraries from those packages in a directory on your RHEL5 system. Let's call it /YOUR-ALIEN-RHEL6-LIBS-PATH.
Unpack another copy of a JRE to, say, /YOUR-ALIEN-JVM-PATH.
Use patchelf to point the JVM executable to the new loader.
./usr/bin/patchelf --set-interpreter /YOUR-ALIEN-RHEL6-LIBS-PATH/lib/amd64/ld-linux-x86-64.so.2 /YOUR-ALIEN-JVM-PATH/jre1.8.0_25/bin/java
Run the application after setting LD_LIBRARY_PATH=/YOUR-ALIEN-RHEL6-LIBS-PATH/lib/amd64:/YOUR-ALIEN-RHEL6-LIBS-PATH/lib/amd64/jli
Although it is not pretty, I have successfully run JavaFX applications on RHEL5 using this method. Having said that, I highly recommend just upgrading your OS if it is even remotely feasible.
Note this builds upon the existing answer from James with more concrete detail
Obtain RPMs from a RedHat 6.x, e.g. http://vault.centos.org/6.2/os/i386/Packages. Copy into directory rpms/
cairo-1.8.8-3.1.el6.i686.rpm
glib2-2.22.5-6.el6.i686.rpm
glibc-2.12-1.47.el6.i686.rpm
glibc-common-2.12-1.47.el6.i686.rpm
gtk2-2.18.9-6.el6.centos.i686.rpm
libffi-3.0.5-3.2.el6.i686.rpm
libXcomposite-0.4.1-2.el6.i686.rpm <== not mentioned in other answer
pango-1.28.1-3.el6_0.centos.5.i686.rpm
pixman-0.18.4-1.el6_0.1.i686.rpm
zlib-1.2.3-27.el6.i686.rpm
libXdamage-1.1.2-1.el6.i686.rpm <== not mentioned in other answer
Extract all the contents from the RPMs into separate directory. Use rpm2cpio and xzcat. xzcat can be installed from these RPMs if necessary [xz, xz-libs, xz-lzma-compat]
mkdir redhat-6u2-libs
cd redhat-6u2-libs/
ls -1 rpms/* | xargs -i{} bash -c "rpm2cpio {} | xzcat | cpio -idmv"
Obtain copy of patchelf. I built from source as couldn't find a Redhat 5 RPM. Only requires dependent RPMs [gcc, gcc-c++, glibc-devel, kernel-headers, libstdc++-devel]
wget https://nixos.org/releases/patchelf/patchelf-0.9/patchelf-0.9.tar.bz2
tar xjf patchelf-0.9.tar.bz2
cd patchelf-0.9
./configure --prefix /tmp/patchelf
make install
Use patchelf to set location of redhat 6u2 loader (aka interpreter)
/tmp/patchelf/bin/patchelf --set-interpreter ~/redhat-6u2-libs/lib/ld-linux.so.2 jdk1.8.0_40/bin/java
Set LD_LIBRARY_PATH, this needs to have both /usr/lib and /lib, otherwise you get a segfault.
export LD_LIBRARY_PATH=/home/user/redhat-6u2-libs/usr/lib:/home/user/redhat-6u2-libs/lib
(Note that any other applications run after LD_LIBRARY_PATH is set other than java which has had its interpreter location corrected will segfault.)
Now run java app...
./jdk1.8.0_40/bin/java -cp etc...
Happy days
Currently in our Android project, we're linking against guice-3.0-no_aop.jar for Guice. I need to do some timing measurement around injection, so I've check out the source code of Guice (git clone https://code.google.com/p/google-guice/), but don't know how to make the needed file. I've tried ant build with different options listed in build.xml (e.g. 'ant jar' or 'ant dist') but none of these produce the file.
So could anyone tell me how to build this jar from source?
From google-guice groups:
If you want to use Ant:
ant no_aop<br>
cd build/no_aop<br>
ant jar<br>
cd ../..
and the no_aop flavour jar can be found under:
build/no_aop/build/dist/guice-snapshot.jar
ie. the tree under "build/no_aop" is just like the original tree, but has been 'munged' to remove AOP, so it still uses the original filenames for the binaries
If you want to use Maven:
mvn package
and the no_aop flavour jar can be found under:
core/target/guice-<version>-no_aop.jar
the difference with Maven is that the 'munging' is done as part of the main build, and the "no_aop" flavour jar is attached alongside the original jar
I wanted to migrate my Qt 4 app to use Qt 5 instead. These instructions failed, due to some differences with how MXE builds Qt 5, including the fact that it uses modularised Qt tarballs, instead of one large tarball.
Here are the full instructions:
Get it:
git clone https://github.com/mxe/mxe.git
Install build dependencies
Build Qt 5 for Windows:
cd mxe && make qtbase
This will first build its dependencies and the cross-build tools;
It should take less than an hour on a fast machine with decent internet access.
Due to the new modular nature of Qt 5, various major Qt components are now in different tarballs. The one selected above, qtbase, should give you enough functionality to run ordinary GUI apps, which is all I needed for my own (smallish) app.
If you want to build all of Qt 5 instead, you'll need to run make qt5 (instead of make qtbase). Note that it will take a lot longer to complete, so be sure that you need the extra functionality.
Get to the directory of your app, and run the Qt Makefile generator tool:
<mxe root>/usr/bin/i686-w64-mingw32.static-qmake-qt5
Build your project:
make
You should find the binary in the ./release directory:
wine release/foo.exe
Some notes:
This was tested on my 64-bit Debian 8, and on Windows of course.
The output is a 32-bit static executable, which will work well on 64-bit Windows.
If you want a 64-bit executable, build Qt with:
make MXE_TARGETS=x86_64-w64-mingw32.static qtbase
The default MXE_TARGETS value is i686-w64-mingw32.static.
The git checkout command is not correct. You now have to get their stable branch or it will fail building.
git clone https://github.com/mxe/mxe.git
should be...
git clone -b stable https://github.com/mxe/mxe.git
That alone fixed all my issues with qtbase building but leaving no qt folder when done. Then qt5 target would fail with obscure errors. Deleted folder, checked out stable and it worked flawlessly.
For those who directly want a GCC10 64bit compiled Qt5 (for filesystem lib for example),
Here are the full instructions:
Get it:
git clone https://github.com/mxe/mxe.git
Install build dependencies
Build Qt 5 for Windows with gcc10 64bits plugin activated :
cd mxe && make MXE_TARGETS=x86_64-w64-mingw32.shared MXE_PLUGIN_DIRS=plugins/gcc10 qt5
After 2-3 hours of build you can build your app (in your .pro directory) :
<mxe root>/usr/x86_64-w64-mingw32.shared/qt5/bin/qmake
Export path of compiler & build your project:
export PATH=<mxe root>/usr/bin:$PATH
make
You should find the binary in the ./release directory & start it with wine (or wine64) :
wine foo.exe
I don't really know why, but I needed to add the MXE compiler directory to the wine path because it's couldn't find the DLLs :
WINEPATH="<mxe root>/usr/x86_64-w64-mingw32.shared/bin/" wine64 foo.exe
If you try to do this, for me work fine!
su
mv mxe /opt/mxe
cd /opt/mxe && make