mabe02 / lanterna

Java library for creating text-based GUIs
GNU Lesser General Public License v3.0
2.3k stars 244 forks source link

Use DefaultTerminalFactory with GraalVM #499

Open Futurile opened 4 years ago

Futurile commented 4 years ago

The situation is that you can use Lanterna with GraalVM by directly creating a terminal (e.g. UnixTerminal). It would be nice if we could use the DefaultTerminalFactory

I think it's getting further into the compilation stage - but does fail eventually. I installed lanterna-3.2.0-SNAPSHOT

As far as reflection goes I have to tell it to defer these two classes:

DELAYED_CLASSES ::='sun.awt.dnd.SunDropTargetContextPeer$$EventDispatcher:run_time,com.googlecode.lanterna.terminal.win32.WindowsTerminal:run_time'

If I delay these two classes to "run_time" I can get it a bit further, eventually it breaks down at:

/home/steve/workspace/tmp/SVM-16952629440833356972
/sun.awt.dnd.SunDropTargetContextPeer$EventDispatcher:run_time.o:(.data+0x158): undefined reference to `Java_java_util_prefs_FileSystemPreferences_chmod'

This seems to refer to java.util.prefs not being supported, see https://github.com/oracle/graal/issues/2063. I tried adding:

-H:NativeLinkedOption='-lprefs'

This may or may not be helping to be honest: It compiles for longer but crashes and there's no obvious debug step. I guess questions are:

  1. Can anything be done about the reflection for those two classes?
  2. Can anything be done about the prefs need?

I'm using graalvm-ce-java11-20.1.0 with Java 11.0.7 on Ubuntu 16.04. Main files below for reference.

-- Makefile

# See: https://tech.davis-hansson.com/p/make/
# This sets up some sensible defaults

SHELL := bash
.PHONY: hello test test-watch docs eastwood clfmt cloverage trace graal uberjar release deploy clean help
.ONESHELL: graal
.SHELLFLAGS := -eu -o pipefail -c
.DELETE_ON_ERROR:
MAKEFLAGS += --warn-undefined-variables
MAKEFLAGS += --no-builtin-rules

# Not required to use <tab> use > to show commands
ifeq ($(origin .RECIPEPREFIX), undefined)
  $(error This Make does not support .RECIPEPREFIX. Please use GNU Make 4.0 or later)
endif
.RECIPEPREFIX = >

# https://github.com/clojure-emacs/orchard/blob/master/Makefile

TEST_PROFILES  ::= +test
BINARY_NAME    ::= passtui

# These need to be set in the environment. They are the location of the Graal
# specific Java to use, and the location of the native_image command.
GRAAL_JAVA      ::= $(GRAAL_JAVA)
NATIVE_IMAGE    ::= $(NATIVE_IMAGE)

# Need to set _JAVA_OPTIONS so that TMPDIR works
#_JAVA_OPTIONS -Djava.io.tmpdir=$HOME/tmp
JAR             ::= $(wildcard target/uberjar/*-standalone.jar)
GRAAL_CFG       ::= $(shell pwd)/graalcfg

DELAYED_CLASSES ::='sun.awt.dnd.SunDropTargetContextPeer$$EventDispatcher:run_time,com.googlecode.lanterna.terminal.win32.WindowsTerminal:run_time'

GRAAL_TRACE_OPTIONS ::= -agentlib:native-image-agent=config-output-dir=$(GRAAL_CFG) $(JAR)
                       # if you need to run multiple times to capture multiple execution paths
                       #-agentlib:native-image-agent=config-merge-dir=$(GRAAL_CFG) $(JAR)

GRAAL_OPTIONS       ::= -H:Name=$(BINARY_NAME)                        \
                        -H:+ReportExceptionStackTraces                \
                        -H:+PrintClassInitialization                  \
                        -H:ConfigurationFileDirectories=$(GRAAL_CFG)  \
                        -J-Dclojure.compiler.direct-linking=true      \
                        --initialize-at-build-time                    \
                        --report-unsupported-elements-at-runtime      \
                        -H:ClassInitialization=$(DELAYED_CLASSES)     \
                        -H:+TraceClassInitialization                  \
                        -H:+PrintAnalysisCallTree                     \
                        --allow-incomplete-classpath                  \
                        -H:NativeLinkerOption='-lprefs'               \
                        --verbose                                     \
                        --no-fallback                                 \
                        --no-server                                   \
                        "-J-Xmx3g"

# Be silent by default
$(V).SILENT:

## Rules are:
##  test           Runs tests from the command line
test: 
> lein with-profile +$(TEST-PROFILES) test

##  trace          Runs the GraalVM tracing agent, placing results in graalcfg directory.
trace:
> if [ -n "$(GRAAL_JAVA)" ]; then
>   $(GRAAL_JAVA) -jar $(GRAAL_TRACE_OPTIONS)
> else
>   echo "The environmental variable GRAAL_JAVA is missing"
> fi

##  graal          Creates a GraalVM native image from uberjar.
graal:
> if [ -n "$(NATIVE_IMAGE)" -a -n "$(GRAAL_JAVA)" ]; then
>   $(NATIVE_IMAGE) -jar $(JAR) $(GRAAL_OPTIONS)
> else
>   echo "The environmental variables NATIVE_IMAGE or GRAAL_JAVA are missing"
> fi
##  uberjar        Creates an uberjar, that is needed by the 'graal' rule.
uberjar:
> lein uberjar

##  clean          Clean-up Clojure directories
clean:
> lein clean

##  help           Self-documenting help
help: Makefile
> @sed -n 's/^##//p' $<

##  <name>.rst     Create html experiment
%.html: %.rst
> pandoc $*.rst $*.html

# vim: ft=make

-- Clojure source file

(ns lanterna481.core
  (:import
        com.googlecode.lanterna.terminal.Terminal
        com.googlecode.lanterna.terminal.ansi.UnixTerminal
        com.googlecode.lanterna.terminal.DefaultTerminalFactory

  )
  (:gen-class))

  (set! *warn-on-reflection* true)

(defn -main
  "Simple test for GraalVM and DefaultTerminalFactory"
  [& args]

  (def ^com.googlecode.lanterna.terminal.DefaultTerminalFactory termDefault (new DefaultTerminalFactory))
  (def ^Terminal terminal (. termDefault createTerminal))

  (.clearScreen ^Terminal terminal)

  (.putCharacter ^Terminal terminal \h)
  (.putCharacter ^Terminal terminal \e)
  (.putCharacter ^Terminal terminal \l)
  (.putCharacter ^Terminal terminal \l)
  (.putCharacter ^Terminal terminal \o)
  (.putCharacter ^Terminal terminal \newline)

  (.flush ^Terminal terminal)

)

-- Lein project.clj file

(defproject lanterna481 "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
            :url "https://www.eclipse.org/legal/epl-2.0/"}
  :plugins [[lein-localrepo "0.5.4"]]
  :dependencies [[org.clojure/clojure "1.10.1"]
                 [com.googlecode.lanterna/lanterna "3.2.0-SNAPSHOT"]
                 ]
  :main ^:skip-aot lanterna481.core
  :target-path "target/%s"
  :profiles {:uberjar {
                       :aot :all
                       :jvm-opts ["-Dclojure-compiler.direct-linking=true"]
                       :dependencies [[borkdude/clj-reflector-graal-java11-fix "0.0.1-graalvm-20.1.0"]]
                      }
             :dev [:project/dev :profiles/dev]
             :project/dev { ;; project specific configuraion
                          }
            }
  :profiles/dev { ;; leave empty it's merging ~/.lein/profile.clj 
                }

  :repositories [; specifically used by lein-git-down to enable github
                 ;["public-github" {:url "git://github.com"}]
                 ;["private-github" {:url "git://github.com" :protocol :ssh}]
                 ;  ["jitpack" "https://jitpack.io"]
                ]

  ;:git-down {
  ;          lanterna {:coordinates mabe02/lanterna}
  ;         }
)
mabe02 commented 4 years ago

I don't remember using FileSystemPreferences anywhere in the library and I can't find any reference to it in the whole source tree. So not sure why it's complaining about that. Can you try latest release/3.1 branch (compile from source) as well? The win32 implementation isn't present there.

gradinac commented 4 years ago

@mabe02 The way they get pulled in is by code using java.uti.prefs.Preferences, specifically, the userRoot() and systemRoot() methods of the class. Under the hood, a default implementation is provided for each platform (Linux, Windows, Darwin) - the FileSystemPreferences one is the Linux implementation.

@Futurile We have recently added support for java.util.prefs on the native-image side. It will probably end up in 20.3, but you can give it a shot if you can build GraalVM. Take a look at https://github.com/oracle/graal/issues/2063#issuecomment-663558679

eureton commented 3 years ago

@Futurile Have you had any success since? If so, please share.

Futurile commented 3 years ago

@eureton I installed Graalvm 21.0.2 , Lanterna 3.1.1 and Clojure 10.1.3. Honestly, I'm having issues with Graal and with Lanterna so I cannot 100% specify that it doesn't work. Creating a UnixTerminal terminal directly works e.g def ^Terminal terminal (new ^Terminal UnixTerminal).

If I try and use DefaultTerminalFactory:

(def ^com.googlecode.lanterna.terminal.DefaultTerminalFactory termDefault (new DefaultTerminalFactory))
  (def ^Terminal terminal (. termDefault createTerminal))

I get this:

  Fatal error:java.lang.RuntimeException: java.lang.RuntimeException: There was an error linking the native image: Linker command exited with 1

Then I get this:

passtui.o:(.data+0x5c8): undefined reference to `Java_sun_java2d_loops_DrawGlyphListLCD_DrawGlyphListLCD'
passtui.o:(.data+0xb40): undefined reference to `Java_sun_java2d_loops_DrawGlyphListAA_DrawGlyphListAA'
passtui.o:(.data+0xbb8): undefined reference to `Java_sun_java2d_loops_DrawGlyphList_DrawGlyphList'
collect2: error: ld returned 1 exit status
        at com.oracle.svm.hosted.image.NativeBootImageViaCC.handleLinkerFailure(NativeBootImageViaCC.java:474)
        at com.oracle.svm.hosted.image.NativeBootImageViaCC.write(NativeBootImageViaCC.java:441)
        at com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:685)
        at com.oracle.svm.hosted.NativeImageGenerator.lambda$run$0(NativeImageGenerator.java:476)
        at java.base/java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1407)
        at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
        at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
        at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
        at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
        at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)
Error: Image build request failed with exit status 1
com.oracle.svm.driver.NativeImage$NativeImageError: Image build request failed with exit status 1
        at com.oracle.svm.driver.NativeImage.showError(NativeImage.java:1676)
        at com.oracle.svm.driver.NativeImage.build(NativeImage.java:1426)
        at com.oracle.svm.driver.NativeImage.performBuild(NativeImage.java:1387)
        at com.oracle.svm.driver.NativeImage.main(NativeImage.java:1374)
        at com.oracle.svm.driver.NativeImage$JDK9Plus.main(NativeImage.java:1858)

I've had to add --allow-incomplete-classpath which points to there being issues in my set-up which I can't seem to find the solution for. In summary, please try the set-up above and see if it works for you. Apologies that I can't be more definitive.

avl42 commented 3 years ago

Have you tried method "createHeadlessTerminal" (instead of createTerminal) from DefaultTerminalFactory?

That's the javadoc of it: /**

That sounds like your problem to me, but I'm not much into graal and I understand only about 30% of the question...

On Mon, Mar 15, 2021 at 1:56 PM Steve George @.***> wrote:

@eureton https://github.com/eureton I installed Graalvm 21.0.2 , Lanterna 3.1.1 and Clojure 10.1.3. Honestly, I'm having issues with Graal and with Lanterna so I cannot 100% specify that it doesn't work. Creating a UnixTerminal terminal directly works e.g def ^Terminal terminal (new ^Terminal UnixTerminal).

If I try and use DefaultTerminalFactory:

(def ^com.googlecode.lanterna.terminal.DefaultTerminalFactory termDefault (new DefaultTerminalFactory)) (def ^Terminal terminal (. termDefault createTerminal))

I get this:

Fatal error:java.lang.RuntimeException: java.lang.RuntimeException: There was an error linking the native image: Linker command exited with 1

Then I get this:

passtui.o:(.data+0x5c8): undefined reference to Java_sun_java2d_loops_DrawGlyphListLCD_DrawGlyphListLCD' passtui.o:(.data+0xb40): undefined reference toJava_sun_java2d_loops_DrawGlyphListAA_DrawGlyphListAA' passtui.o:(.data+0xbb8): undefined reference to `Java_sun_java2d_loops_DrawGlyphList_DrawGlyphList' collect2: error: ld returned 1 exit status at com.oracle.svm.hosted.image.NativeBootImageViaCC.handleLinkerFailure(NativeBootImageViaCC.java:474) at com.oracle.svm.hosted.image.NativeBootImageViaCC.write(NativeBootImageViaCC.java:441) at com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:685) at com.oracle.svm.hosted.NativeImageGenerator.lambda$run$0(NativeImageGenerator.java:476) at java.base/java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1407) at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290) at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020) at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656) at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594) at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183) Error: Image build request failed with exit status 1 com.oracle.svm.driver.NativeImage$NativeImageError: Image build request failed with exit status 1 at com.oracle.svm.driver.NativeImage.showError(NativeImage.java:1676) at com.oracle.svm.driver.NativeImage.build(NativeImage.java:1426) at com.oracle.svm.driver.NativeImage.performBuild(NativeImage.java:1387) at com.oracle.svm.driver.NativeImage.main(NativeImage.java:1374) at com.oracle.svm.driver.NativeImage$JDK9Plus.main(NativeImage.java:1858)

I've had to add --allow-incomplete-classpath which points to there being issues in my set-up which I can't seem to find the solution for. In summary, please try the set-up above and see if it works for you.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/mabe02/lanterna/issues/499#issuecomment-799396838, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABIDBMUWPVIQV7PYEW3J23DTDX7XDANCNFSM4OLDRY5A .

Futurile commented 3 years ago

@avl42 I think you're right that this function was added for the use-case, thanks for that.

Not making much difference for me though, I get:

``passtui.o:(.data+0x480): undefined reference toJava_sun_java2d_loops_DrawGlyphListLCD_DrawGlyphListLCD' passtui.o:(.data+0x4b8): undefined reference to Java_sun_java2d_loops_DrawGlyphListAA_DrawGlyphListAA' passtui.o:(.data+0x648): undefined reference toJava_sun_java2d_loops_DrawGlyphList_DrawGlyphList' collect2: error: ld returned 1 exit status at com.oracle.svm.hosted.image.NativeBootImageViaCC.handleLinkerFailure(NativeBootImageViaCC.java:474) at com.oracle.svm.hosted.image.NativeBootImageViaCC.write(NativeBootImageViaCC.java:441) at com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:685) at com.oracle.svm.hosted.NativeImageGenerator.lambda$run$0(NativeImageGenerator.java:476) at java.base/java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1407) at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290) at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020) at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656) at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594) at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183) Error: Image build request failed with exit status 1


Attached the whole of the build in case that's useful:

[buildoutput.txt](https://github.com/mabe02/lanterna/files/6170800/buildoutput.txt)
avl42 commented 3 years ago

In that case, I fear, the culprit must be elsewhere...

What is the source of that "passtui" component? Does it use any other APIs other than lanterna?

On Fri, Mar 19, 2021 at 12:41 PM Steve George @.***> wrote:

@avl42 I think you're right that this function was added for the use-case, thanks for that.

Not making much difference for me though, I get:


passtui.o:(.data+0x648): undefined reference to `Java_sun_java2d_loops_DrawGlyphList_DrawGlyphList'
collect2: error: ld returned 1 exit status
at com.oracle.svm.hosted.image.NativeBootImageViaCC.handleLinkerFailure(NativeBootImageViaCC.java:474)
at com.oracle.svm.hosted.image.NativeBootImageViaCC.write(NativeBootImageViaCC.java:441)
at com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:685)
at com.oracle.svm.hosted.NativeImageGenerator.lambda$run$0(NativeImageGenerator.java:476)
at java.base/java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1407)
at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)
Error: Image build request failed with exit status 1

Attached the whole of the build in case that's useful:

[buildoutput.txt](https://github.com/mabe02/lanterna/files/6170800/buildoutput.txt)

—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub, or unsubscribe.