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

Create Native Image failed for Swing App under MacOS 10 #664

Closed
jdevp opened this issue Sep 9, 2018 · 20 comments
Closed

Create Native Image failed for Swing App under MacOS 10 #664

jdevp opened this issue Sep 9, 2018 · 20 comments
Assignees

Comments

@jdevp
Copy link

jdevp commented Sep 9, 2018

The the following error when creating native image for MacOS

Error: Class initialization failed: DesktopAPI

Original exception that caused the problem: java.lang.NoClassDefFoundError: Could not initialize class sun.lwawt.macosx.LWCToolkit

Original exception that caused the problem: java.lang.NoClassDefFoundError: Could not initialize class sun.font.FontManagerNativeLibrary

I have attached the output file.
native-image_error.txt

@christianwimmer
Copy link
Member

This is one of the use cases where you need to delay class initialization from image build time to image run time: https://medium.com/graalvm/understanding-class-initialization-in-graalvm-native-image-generation-d765b7e4d6ed

Swing (and all other window toolkits like AWT or SWT) need to load native libraries and allocate native resources. A common pattern in Java is to do that in class initializers. In your exception stack trace, there is one class initializer in the trace:

at DesktopAPI.<clinit>(DesktopAPI.java:9)

I assume the class DesktopAPI is one of your classes (since it has no package name), so you could refactor that class to not use a class initializer. Or you can initialize that class at run time using --delay-class-initialization-to-runtime=DesktopAPI. This is likely only the starting point - you will need to add more classes to that list until you hit no more errors during image building.

@jdevp
Copy link
Author

jdevp commented Sep 13, 2018

Thanks Chris.

I put delay initialization for some classes. But I got stuck with the following

java.lang.NoClassDefFoundError: Could not initialize class sun.awt.dnd.SunDropTargetContextPeer$EventDispatcher

When I put delay initialization for sun.awt.dnd.SunDropTargetContextPeer$EventDispatcher, I got the message that initialization is already completed, it's too late:

"error: Class is already initialized, so it is too late to register delaying class initialization: sun.awt.dnd.SunDropTargetContextPeer

Error: Processing image build request failed"

@jdevp
Copy link
Author

jdevp commented Sep 19, 2018

Any update on this issue ? It doesn't allow me to put delay initialization of class "sun.awt.dnd.SunDropTargetContextPeer"

@christianwimmer
Copy link
Member

There is currently no easy way to find out why a class is already initialized. The best way I found is using a Java debugger, as explained in the blog article.
We are thinking about ways to improve the user experience, i.e., give you a trace why a class is initialized. But it will be a while before we have that ready.

@Hugolarson
Copy link

Hugolarson commented May 17, 2019

Hi,
Sorry to hijack this thread with a question.
Will GraalVM support JavaFx and Swing applications native image?

@SwingGuy1024
Copy link

SwingGuy1024 commented May 17, 2019

I've also been having trouble with my Swing application. The problem has a lot to do with the AWT's event-dispatch thread, which gets launched by my main Thread. When running in a Java VM, I need to launch this from my main method, which probably causes all my native-image build problems. The main build problem is class sun.java2d.opengl.OGLRenderQueue, which I don't understand, because I don't call it directly. It's a singleton. The first time it gets used, its getInstance() method launches a Thread by calling AccessController.doPrivileged(). This may have something to do with why I can't build it. I've tried it by specifying it three ways:

-H:ClassInitialization=sun.java2d.opengl.OGLRenderQueue:run_time
This gives me this error: Error: Class is already initialized, so it is too late to register delaying class initialization: sun.java2d.opengl.OGLRenderQueue for reason: from the command line

-H:ClassInitialization=sun.java2d.opengl.OGLRenderQueue:build_time
I didn't expect this to work. It gives me this error: Error: Detected a started Thread in the image heap. Threads running in the image generator are no longer running at image run time. The object was probably created by a class initializer and is reachable from a static field. By default, all class initialization is done during native image building.You can manually delay class initialization to image run time by using the option -H:ClassInitialization=. Or you can write your own initialization methods and call them explicitly from your main entry point.

-H:ClassInitialization=sun.java2d.opengl.OGLRenderQueue:rerun
I have no idea what rerun means. Here's the error: Error: No instances are allowed in the image heap for a class that is initialized or reinitialized at image runtime: sun.java2d.opengl.OGLRenderQueue. Try marking this class for build-time initialization with --initialize-at-build-time=sun.java2d.opengl.OGLRenderQueue

It's not clear why it sometimes tells me to use the --initialize-at-build-time=, and other times it suggests using -H:ClassInitialization=sun.java2d.opengl.OGLRenderQueue:run_time. I'm not sure what the difference is between these two options. Typing native-image --help doesn't describe the -H option.

However, specifying --initialize-at-run-time=sun.java2d.opengl.OGLRenderQueue instead of -H:ClassInitialization=sun.java2d.opengl.OGLRenderQueue:run_time, and I got this error message: Error: Class is already initialized, so it is too late to register delaying class initialization: sun.java2d.opengl.OGLRenderQueue for reason: from the command line

Using both --initialize-at-run-time=sun.java2d.opengl.OGLRenderQueue and -H:ClassInitialization=sun.java2d.opengl.OGLRenderQueue:run_time gave me the same error as just using --initialize-at-run-time=sun.java2d.opengl.OGLRenderQueue.

I'm going to try restructuring the program. I may have to declare a class be initialed at run time that I normally launch from my main method. This would mean that the code would only work in the native image mode.

Please document the -H options, especially the -H:ClassInitialization option in your --help text.

@cstancu
Copy link
Member

cstancu commented May 17, 2019

You can get info on all options via --expert-options-all, e.g.:

$ native-image --expert-options-all | grep ClassInitialization
  -H:ClassInitialization=...                   A comma-separated list of classes appended with their initialization strategy (':build_time', ':rerun', or ':run_time').
  -H:±PrintClassInitialization                 Prints class initialization info for all classes detected by analysis. Default: - (disabled).

Also here is some more documentation.

@MiguelMunoz
Copy link

Very helpful. Thank you. But I have a new suggestion. Please add reference to native-image --expert-options-all in the --help text.

@cstancu
Copy link
Member

cstancu commented May 18, 2019

It sort of does already:

  • native-image --help mentions
   --help                print this help message
   --help-extra          print help on non-standard options
  • native-image --help-extra mentions
    --expert-options      lists image build options for experts
    --expert-options-all  lists all image build options for experts (use at your own risk)

@MiguelMunoz
Copy link

Thanks. I missed that.

In my experiments, it looks like there is simply no way to use GraalVM native image building with a Swing or AWT application. I tried delaying the loading to run_time for the java.awt.Component class, but I still got an error that said this:

Class is already initialized, so it is too late to register delaying class initialization: java.awt.Component for reason: from the command line

It did this even when my main class did nothing. It didn't even try to launch a window.

You may experiment with my swing application by checking out the repository at https://github.com/MiguelMunoz/Clock

(It's a very small repository, to build a very small Swing application.)

@Hugolarson
Copy link

Very interesting.
But I still don't get it if GraalVM native image will work with Java GUI.
Are they working it?

@MiguelMunoz
Copy link

MiguelMunoz commented May 18, 2019

In my experiments, I was able to build, but I always required a fallback image, because of Threading issues. This means I still need a JDK to launch it, which defeats the purpose. (My tests show it doesn't load any faster.) My suggestion: Add an AWT option, which would delay the start of the Event Dispatch Thread until runtime. The option would probably require the name of a class to load at runtime. There doesn't seem to be any way to do this using the options that are currently available.

As an alternative, add an option to load a specific class at runtime. This would be a class that doesn't get loaded when the application is run in a Java VM, but it could contain the code that opens the first Frame, which would start the event thread.

@Hugolarson
Copy link

Did you ever try JavaFX? It's not dependent of AWT.

@MiguelMunoz
Copy link

MiguelMunoz commented May 18, 2019

I have not tried that yet. The application that I want to convert doesn't use it. But if you can get it to work, please let us know.

@Hugolarson
Copy link

I'm not good with Linux so need to wait for Windows GraalVM.

@SwingGuy1024
Copy link

SwingGuy1024 commented May 24, 2019

Christian Wimmer mentions an article called Understanding Class Initialization in GraalVM Native Image Generation. But it seems to be out-of-date. It shows how you can set a static variable in your main method, and it will retain the value it had at build time. But in my experiments, that's not what happens. Now, the value gets set at runtime. I was hoping to use this feature to work around my build problems, but the new behavior prevents me from doing that. And you can no longer print at build time either, which I was counting on for debugging purposes. (I even tried writing values to a file, which also didn't work at build time.) I wish the new behavior was documented. That might help.

@SwingGuy1024
Copy link

On another project, I wrote a command-line utility that, among other things, tried to copy something to the clipboard, which I built as a native-image. When I ran it, I got this error message: AWT is currently not supported on Substrate VM. I hope they change that policy sometime soon. I also hope they make an exception for the system clipboard, which doesn't have the same Threading issues that the AWT has.

@jdevp
Copy link
Author

jdevp commented May 28, 2019 via email

@Hugolarson
Copy link

What do you think about this:
https://gluonhq.com/a-boost-for-java-on-the-client/

yusuke added a commit to yusuke/shogun that referenced this issue Jul 6, 2019
…load main class Shogun"

Add options for GraalVM to include image and class resources.
https://blog.frankel.ch/configuring-graal-native-aot-reflection/

The native image still fails with the following exception:
Exception in thread "main" java.lang.IllegalArgumentException: AWT is currently not supported on Substrate VM
        at java.awt.Toolkit.getDefaultToolkit(Toolkit.java:37)
        at shogun.task.TaskTray.show(TaskTray.java:21)
        at Shogun.main(Shogun.java:7)

Currently building native images for desktop apps seems to be not possible.
oracle/graal#664
@cstancu cstancu assigned vjovanov and unassigned christianwimmer Sep 23, 2020
@vjovanov
Copy link
Member

We are addressing the AWT and Swing in the following release. This issue will be fixed as a part of the larger effort.

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