Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Native Image of simplest Java Swing Application #2644

Closed
hanns-maulwurf opened this issue Jul 2, 2020 · 15 comments
Closed

Native Image of simplest Java Swing Application #2644

hanns-maulwurf opened this issue Jul 2, 2020 · 15 comments
Assignees

Comments

@hanns-maulwurf
Copy link

Describe the issue
I am trying to build a native executable out of a Java Swing application with the GraalVM native-image command.
As I did get so many errors I couldn't solve at first, I decided to just try a simple Hello-world style example app first, because if I couldn't get this to work, I don't have to bother trying a much more complex application.
And as it turned out, I can't get it to work, so this is why I am asking here what I might be doing wrong or if native-image can't handle Swing applications at all (in which case I would not need to spend any more time with this).

My progress so far:
I could get native-image to build an exe from the HelloWorld Swing app.
But when I run the exe, I get the following error:

$> .\helloswing.exe
Exception in thread "main" java.lang.IllegalArgumentException: AWT is currently not supported on Substrate VM
        at java.awt.Toolkit.getDefaultToolkit(Toolkit.java:37)
        at java.awt.Toolkit.getEventQueue(Toolkit.java:1494)
        at java.awt.EventQueue.invokeLater(EventQueue.java:1312)
        at HelloSwing.main(HelloSwing.java:8)

Steps to reproduce the issue
The code of the HelloSwing program is very simple:

import java.awt.*;
import javax.swing.*;

public class HelloSwing {


    public static void main(String[] args) {
        EventQueue.invokeLater(() -> {
            JPanel panel = new JPanel();
            panel.add(new JLabel("Hello Swing!"));
            panel.setPreferredSize(new Dimension(600,400));
            JFrame frame = new JFrame("Hello Swing App");
            frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
            frame.getContentPane().add(panel);
            frame.pack();
            frame.setVisible(true);
        });
        
    }

}

I first compiled the HelloSwing.java class with the GraalVM javac command.
Then I called native-image from the Visual Studio 2019 x64 Native Tools Command Prompt with the following parameters:

native-image --no-fallback --verbose --initialize-at-run-time=sun.awt.dnd.SunDropTargetContextPeer$EventDispatcher 
-H:ReflectionConfigurationFiles=reflection-config.json -H:NativeLinkerOption=prefs.lib -H:-CheckToolchain  
-H:+ReportExceptionStackTraces --native-image-info HelloSwing

Rational for the used options:

  • The "initialize-at-run-time" for the SunDropTargetContextPeer was inserted, because I first got an error telling me, that this class could not be initialized and I should delay initialization for it.
  • The NativeLinkerOption was added, because I got an linker error for "unresolved external symbol Java_java_util_prefs_WindowsPreferences_WindowsRegCloseKey", and I added it as suggest in linker cannot find symbols to edit the windows registry: LNK1120 unresolved extnerals #2363 which fixed that error.
  • The H:ReflectionConfigurationFiles option was added, because I got an error, that class javax.swing.plaf.metal.MetalLookAndFeel could not be found, as it was loaded trough reflection. So I created a JSON config file to tell native-image about that class with the following content:
[
  {
    "name" : "javax.swing.plaf.metal.MetalLookAndFeel",
    "allDeclaredConstructors" : true,
    "allPublicConstructors" : true,
    "allDeclaredMethods" : true,
    "allPublicMethods" : true,
    "allDeclaredFields" : true,
    "allPublicFields" : true
  }
]

Describe GraalVM and your environment:

  • GraalVM version CE 20.2.0-dev (build 11.0.7+10-jvmci-20.2-b02)
  • JDK major version: 11
  • OS: Windows 10
  • Architecture: AMD64
  • Visual Studio 2019 with x64 Native Tools Command Prompt

So my question(s) are:
Is it just not possible, to make a native image of an Swing application?
Has anyone here ever successfully built an exe of a Swing application that worked (even if just a HelloWorld example)?
Or am I doing something wrong here?
Any hints/comments appreciated.

More details
Here is the output of the native-image command with --verbose and --native-image-info turned on:

Executing [
'C:\Applications\GraalVM\graalvm-ce-java11-20.2.0-dev\bin\java.exe' \
-XX:+UseParallelGC \
-XX:+UnlockExperimentalVMOptions \
-XX:+EnableJVMCI \
-Dtruffle.TrustAllTruffleRuntimeProviders=true \
-Dtruffle.TruffleRuntime=com.oracle.truffle.api.impl.DefaultTruffleRuntime \
-Dgraalvm.ForcePolyglotInvalid=true \
-Dgraalvm.locatorDisabled=true \
-Dsubstratevm.IgnoreGraalVersionCheck=true \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.aarch64=ALL-UNNAMED \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.amd64=ALL-UNNAMED \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.code.site=ALL-UNNAMED \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.code.stack=ALL-UNNAMED \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.code=ALL-UNNAMED \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.common=ALL-UNNAMED \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.hotspot.aarch64=ALL-UNNAMED \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.hotspot.amd64=ALL-UNNAMED \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.hotspot.sparc=ALL-UNNAMED \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.hotspot=ALL-UNNAMED \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.meta=ALL-UNNAMED \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.runtime=ALL-UNNAMED \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.services=ALL-UNNAMED \
--add-exports=jdk.internal.vm.ci/jdk.vm.ci.sparc=ALL-UNNAMED \
--add-exports=org.graalvm.truffle/com.oracle.truffle.api=ALL-UNNAMED \
--add-opens=jdk.internal.vm.compiler/org.graalvm.compiler.debug=ALL-UNNAMED \
--add-opens=jdk.internal.vm.compiler/org.graalvm.compiler.nodes=ALL-UNNAMED \
--add-opens=jdk.unsupported/sun.reflect=ALL-UNNAMED \
--add-opens=java.base/jdk.internal.module=ALL-UNNAMED \
--add-opens=java.base/jdk.internal.ref=ALL-UNNAMED \
--add-opens=java.base/jdk.internal.reflect=ALL-UNNAMED \
--add-opens=java.base/java.io=ALL-UNNAMED \
--add-opens=java.base/java.lang=ALL-UNNAMED \
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED \
--add-opens=java.base/java.lang.invoke=ALL-UNNAMED \
--add-opens=java.base/java.lang.ref=ALL-UNNAMED \
--add-opens=java.base/java.net=ALL-UNNAMED \
--add-opens=java.base/java.nio=ALL-UNNAMED \
--add-opens=java.base/java.nio.file=ALL-UNNAMED \
--add-opens=java.base/java.security=ALL-UNNAMED \
--add-opens=java.base/javax.crypto=ALL-UNNAMED \
--add-opens=java.base/java.util=ALL-UNNAMED \
--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED \
--add-opens=java.base/sun.security.x509=ALL-UNNAMED \
--add-opens=java.base/jdk.internal.logger=ALL-UNNAMED \
--add-opens=org.graalvm.sdk/org.graalvm.nativeimage.impl=ALL-UNNAMED \
--add-opens=org.graalvm.sdk/org.graalvm.polyglot=ALL-UNNAMED \
--add-opens=org.graalvm.truffle/com.oracle.truffle.polyglot=ALL-UNNAMED \
--add-opens=org.graalvm.truffle/com.oracle.truffle.api.impl=ALL-UNNAMED \
-XX:+UseJVMCINativeLibrary \
-Xss10m \
-Xms1g \
-Xmx13686882304 \
-Duser.country=US \
-Duser.language=en \
-Djava.awt.headless=true \
-Dorg.graalvm.version=20.2.0-dev \
-Dorg.graalvm.config= \
-Dcom.oracle.graalvm.isaot=true \
-Djava.system.class.loader=com.oracle.svm.hosted.NativeImageSystemClassLoader \
-Xshare:off \
--module-path \
'C:\Applications\GraalVM\graalvm-ce-java11-20.2.0-dev\lib\truffle\truffle-api.jar' \
'-javaagent:C:\Applications\GraalVM\graalvm-ce-java11-20.2.0-dev\lib\svm\builder\svm.jar' \
-Djdk.internal.lambda.disableEagerInitialization=true \
-Djdk.internal.lambda.eagerlyInitialize=false \
-Djava.lang.invoke.InnerClassLambdaMetafactory.initializeLambdas=false \
-cp \
'C:\Applications\GraalVM\graalvm-ce-java11-20.2.0-dev\lib\svm\builder\objectfile.jar;C:\Applications\GraalVM\graalvm-ce-java11-20.2.0-dev\lib\svm\builder\pointsto.jar;C:\Applications\GraalVM\graalvm-ce-java11-20.2.0-dev\lib\svm\builder\svm.jar' \
'com.oracle.svm.hosted.NativeImageGeneratorRunner$JDK9Plus' \
-imagecp \
'C:\Applications\GraalVM\graalvm-ce-java11-20.2.0-dev\lib\svm\library-support.jar;C:\Test' \
'-H:Path=c:\Test' \
-H:FallbackThreshold=0 \
'-H:ClassInitialization=sun.awt.dnd.SunDropTargetContextPeer$EventDispatcher:run_time' \
-H:NativeLinkerOption=prefs.lib \
-H:-CheckToolchain \
-H:+ReportExceptionStackTraces \
-H:+DumpTargetInfo \
'-H:CLibraryPath=C:\Applications\GraalVM\graalvm-ce-java11-20.2.0-dev\lib\svm\clibraries\windows-amd64' \
'-H:ReflectionConfigurationFiles=C:\Test\native-image-reflection-config.json' \
-H:Class=HelloSwing \
-H:Name=helloswing \

]
[helloswing:14824]    classlist:   1,133.62 ms,  0.96 GB
[helloswing:14824]        (cap):   2,861.50 ms,  0.96 GB
[helloswing:14824]        setup:   4,406.42 ms,  0.96 GB
# Building image for target platform: org.graalvm.nativeimage.Platform$WINDOWS_AMD64
# Using native toolchain:
#   Name: WindowsCCompilerInvoker (null)
#   Vendor: null
#   Version: 0.0.0
#   Target architecture: null
#   Path: C:\Applications\Visual Studio\2019 Community\VC\Tools\MSVC\14.26.28801\bin\HostX64\x64\cl.exe
# Using CLibrary: com.oracle.svm.core.c.libc.NoLibC
[helloswing:14824]     (clinit):     279.65 ms,  1.72 GB
# Static libraries:
#   ..\Applications\GraalVM\graalvm-ce-java11-20.2.0-dev\lib\svm\clibraries\windows-amd64\libchelper.lib
#   ..\Applications\GraalVM\graalvm-ce-java11-20.2.0-dev\lib\static\windows-amd64\net.lib
#   ..\Applications\GraalVM\graalvm-ce-java11-20.2.0-dev\lib\svm\clibraries\windows-amd64\ffi.lib
#   ..\Applications\GraalVM\graalvm-ce-java11-20.2.0-dev\lib\static\windows-amd64\nio.lib
#   ..\Applications\GraalVM\graalvm-ce-java11-20.2.0-dev\lib\static\windows-amd64\java.lib
#   ..\Applications\GraalVM\graalvm-ce-java11-20.2.0-dev\lib\static\windows-amd64\fdlibm.lib
#   ..\Applications\GraalVM\graalvm-ce-java11-20.2.0-dev\lib\static\windows-amd64\zip.lib
#   ..\Applications\GraalVM\graalvm-ce-java11-20.2.0-dev\lib\svm\clibraries\windows-amd64\jvm.lib
# Other libraries:
[helloswing:14824]   (typeflow):   6,569.90 ms,  1.72 GB
[helloswing:14824]    (objects):   5,403.03 ms,  1.72 GB
[helloswing:14824]   (features):     417.37 ms,  1.72 GB
[helloswing:14824]     analysis:  13,016.54 ms,  1.72 GB
[helloswing:14824]     universe:     474.81 ms,  1.72 GB
[helloswing:14824]      (parse):   1,270.33 ms,  1.72 GB
[helloswing:14824]     (inline):   1,265.05 ms,  2.22 GB
[helloswing:14824]    (compile):   6,488.15 ms,  3.16 GB
[helloswing:14824]      compile:   9,815.98 ms,  3.16 GB
[helloswing:14824]        image:   1,265.40 ms,  3.16 GB
[helloswing:14824]        write:     505.27 ms,  3.16 GB
[helloswing:14824]      [total]:  30,836.91 ms,  3.16 GB

@fniephaus
Copy link
Member

Hi @hanns-maulwurf,
It should be possible to support Swing in native image, but AFAIK it's currently not a priority for neither the GraalVM team nor anyone else in the community.
I'm maintaining TruffleSqueak, a Smalltalk implementation in Truffle, and for that, we use a JFrame in JVM mode. TruffleSqueak can be compiling with native image and in that case, we use an SDL2-based substitution. You can find all of this infrastructure at:
https://github.com/hpi-swa/trufflesqueak/tree/master/src/de.hpi.swa.trufflesqueak/src/de/hpi/swa/trufflesqueak/aot

@hanns-maulwurf
Copy link
Author

Hello @fniephaus,
thank you for replying to my question.
But I have some trouble to understand, how what you did relates to my problem.
As I understand, you replace the de.hpi.swa.trufflesqueak.io.SqueakDisplay class (using Swing to create a window and showing some image content) with class de.hpi.swa.trufflesqueak.aot.Target_de_hpi_swa_trufflesqueak_io_SqueakDisplay (A class using SDL to create a window to do the same).
But if that is correct, your native-image will not use your SqueakDisplay Swing-class at all? So basically, you wrote a second GUI in SDL to replace the Swing-GUI in the native image? Or am I getting this wrong?
Because that is not what I am looking for, because I already have a Swing based application. And if I would have to reimplement the whole GUI, I could just use some non-Swing Java GUI framework like JavaFX or SWT or reimplement the whole thing e.g. using Qt, as that would all be much easier I guess.

@fniephaus
Copy link
Member

But if that is correct, your native-image will not use your SqueakDisplay Swing-class at all? So basically, you wrote a second GUI in SDL to replace the Swing-GUI in the native image?

That's right. If this is not what you want, you either have to wait or use a different UI framework. IIRC JavaFX is somewhat supported.

@hanns-maulwurf
Copy link
Author

Na, another UI framework is too much effort, just to get a native image.
I will just stick with Launch4J to get a native starter for the application for the time being.

Or does anyone else has some other suggestions, that could bring that simple Swing Appliation to work with native-image?
Or is there anything I could do, to help bring support for Swing to GraalVM (what would there need to be changed/added?)

@munishchouhan
Copy link
Contributor

@hanns-maulwurf I tried your example and it worked on my machine
please provide a reproducer more close to your application, so that I can check for that too

@munishchouhan munishchouhan self-assigned this Jul 21, 2020
@pquiring
Copy link

Java Bug https://bugs.openjdk.java.net/browse/JDK-8130266 should help fix this issue which was delivered in JDK13.

@hanns-maulwurf
Copy link
Author

hanns-maulwurf commented Jul 25, 2020

@hanns-maulwurf I tried your example and it worked on my machine
please provide a reproducer more close to your application, so that I can check for that too

You can compile the example (HelloSwing.java) I provided above to a native image and execute it and you get the "Hello Swing App" window shown? As I said, I can compile without error, but running the native image produces an IllegalArgumentException ("AWT is currently not supported on Substrate VM").

What GraalVM version etc did you use for that and on what system did you compile/run it?
I used:
GraalVM version CE 20.2.0-dev (build 11.0.7+10-jvmci-20.2-b02)
JDK major version: 11
OS: Windows 10
Architecture: AMD64
Visual Studio 2019 with x64 Native Tools Command Prompt

I do not have a more complex example, because if I can't run even the simplest application, there is IMO no benefit in creating one. If the provided example runs at your machine, than I should figure out first why it doesn't run on my machine?
Could you may be upload the native image you built that is working? Then I could run it here on my machine and see if the error will show up or not here. Because if your image runs at your machine but not on mine, then that would suggest that my machine setup is the problem (maybe some dlls missing etc?)

@hanns-maulwurf
Copy link
Author

hanns-maulwurf commented Jul 25, 2020

Java Bug https://bugs.openjdk.java.net/browse/JDK-8130266 should help fix this issue which was delivered in JDK13.

OK, that would be great. Unfortunately there is as far as i see no GraalVM that is based on JDK 13 or newer. The latest nightly-build is also based on JDK11. Or is there somewhere a GraalVM build with JDK 13?

@fernando-valdez
Copy link
Member

Hello @hanns-maulwurf, I just built and executed your example without issues.
Here how I did it:

@ECHO OFF
ECHO Running Java Swing native image
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
echo ----------
native-image HelloSwing
PAUSE

Used:
GraalVM 20.1.0
Java 11
Windows 10

@hanns-maulwurf
Copy link
Author

Hello @mcraj017 and @fernando-valdez ,

If you build it like that, this will generate a fallback image.
It won't work without the HelloSwing.class file and it requires a Java Runtime to be present.
But my point of creating a native image is, that I don't need to distribute a Java Runtime along with the application and have a real "native" image.

In the output from the native-image command it states:

Warning: Aborting stand-alone image build due to unsupported features
Warning: Use -H:+ReportExceptionStackTraces to print stacktrace of underlying exception
Warning: Image 'helloswing' is a fallback image that requires a JDK for execution 
         (use --no-fallback to suppress fallback image generation and to print more detailed information why a fallback image was necessary).

If you then add the --no-fallback parameter you will first get errors (at least I do), because it can't resolve some stuff.
That is why I had to use the following command line to build the image:

native-image --no-fallback --verbose --initialize-at-run-time=sun.awt.dnd.SunDropTargetContextPeer$EventDispatcher 
-H:ReflectionConfigurationFiles=reflection-config.json -H:NativeLinkerOption=prefs.lib -H:-CheckToolchain  
-H:+ReportExceptionStackTraces --native-image-info HelloSwing

With this command line I was able to build the image with the --no-fallback option, but running the resulting image produced the error I described in this issue.

So a fallback-image is not what I am looking for, because then I will have to bundle the .class files and a JDK with the application which is what I wanted to avoid and what was the point of the whole thing.

Or am I getting something wrong here for example what a fallback-image is?

@munishchouhan
Copy link
Contributor

munishchouhan commented Aug 17, 2020

@hanns-maulwurf Check this ticket #1327,
I suppose the issues are same and will be fixed in jdk 13, currently we have support for jdk 8 and 11 only, once we have GraalVM for latest JDK versions, you can test it again

@munishchouhan
Copy link
Contributor

Closing the issue as this will be resolved once graalvm have support for jdk 13 or latter

@ScottPierce
Copy link

@mcraj017 When will JDK 13 be supported?

@munishchouhan
Copy link
Contributor

@ScottPierce next release 21.1 will have eperimental support for Java 16
You can try the dev builds from here
https://github.com/graalvm/graalvm-ce-dev-builds/releases/tag/21.1.0-dev-20210406_2231

@rubyFeedback
Copy link

A "hello world" example via swing + native-image on the official documentation would be super-useful IMO.

Does not have to be a complicated GUI, just something we can quickly compile via native-image and then
distribute as-is e. g. for elderly people (that's actually one primary use case of mine; I myself am fine with
Linux, but tons of people are stuck on windows, so GraalVM could really tap into that "niche").

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants