Fork me on GitHub
#graalvm
<
2021-07-26
>
tianshu02:07:09

Hi, I'm trying to compile my web app with graalvm. The compilation succeed, but when running, it throws java.lang.NoClassDefFoundError: clout/core/CompiledRoute . Looks like the clout is a library required by compojure. Is it matter to use compojure as router with graalvm? or just I missed something. What kind of libraries should I avoid when working with graalvm.

phronmophobic02:07:45

graalvm will try to only compile code that it thinks is necessary at runtime. there's a few different ways that graalvm might have decided it didn't need to include CompiledRoute: • classes not AOT'd • CompiledRoute not a direct or indirect dependency of the uberjar's main namespace. If you're already doing AOT, then I would check to see if you have a main namespace set for your uberjar and that your main namespace either directly requires/imports the CompiledRoute class or that CompiledRoute is required by a namespace that your main namespace depends on

tianshu03:07:33

Thanks for your explain. I'll try to import CompiledRoute into my namespaces.

tianshu03:07:42

What tooling you use for native-image build. Looks like my AOT only process files in my project, there's no classes generated for dependency libraries.

phronmophobic03:07:32

I've used both lein and clj

phronmophobic03:07:57

here's lein. notice the :profiles {:uberjar {:aot :all}}

(defproject terminal-todo-mvc "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url ""
  :license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
            :url ""}
  :dependencies [[org.clojure/clojure "1.10.2-alpha1"]
                 [com.phronemophobic/membrane "0.9.27.2-beta"]
                 [com.googlecode.lanterna/lanterna "3.1.1"]]
  :jvm-opts ["-Dclojure.compiler.direct-linking=true"]
  :main ^:skip-aot terminal-todo-mvc.core
  :target-path "target/%s"
  :profiles {:uberjar {:aot :all}})
https://github.com/phronmophobic/terminal-todo-mvc/blob/master/compile_native.sh

phronmophobic03:07:51

for clj, I use depstar. here's an example alias:

:depstar-membrane
  {:replace-deps {com.github.seancorfield/depstar {:mvn/version "2.0.216"}}
   :ns-default hf.depstar
   :aliases [:graal-compile]
   :exec-fn hf.depstar/uberjar
   :exec-args {:group-id "com.phronemophobic.mobiletest"
               :artifact-id "membrane"
               :version "1.00-beta-1"
               :sync-pom true
               :aot true
               :compile-ns [;;avclj.main avclj.libavclj
                            com.phronemophobic.mobiletest.membrane
                            ]
               :main-class com.phronemophobic.mobiletest.membrane
               :jar "target/mobiletest-uber.jar"
               ;;Disable tensor code generation and ensure direct linking.
               :jvm-opts ["-Dtech.v3.datatype.graal-native=true"
                          "-Dclojure.compiler.direct-linking=true"
                          "-Dclojure.spec.skip-macros=true"]}}
  
then you just build the jar with: clojure -X:depstar-membrane

tianshu03:07:49

thank you very much!

borkdude07:07:23

@U0NBGRGD6 please show your build, you need at least initialize-at-build-time

borkdude07:07:02

Also see the documentation at clj-graal-docs

tianshu02:07:51

thank you, I'll take a look at clj-graal-docs!

cap10morgan18:07:47

I found that I cannot access fields of deftype instances in go blocks when building graalvm native-images (the same code works fine on the regular JVM). Where is a good place to report that? Clojure JIRA? Or to the graalvm folks?

cap10morgan18:07:02

I made a minimal repro, I can publish that to GitHub if helpful

phronmophobic18:07:12

a minimal repro would be helpful

cap10morgan18:07:24

it's also an example of building a native-image w/ tools.build in case that's interesting to anyone: https://github.com/cap10morgan/graalvm-deftype-field-bug

cap10morgan18:07:03

oh, let me throw a README on that real quick...

phronmophobic18:07:26

does (:a thing) work? Also, can you set (set! *warn-on-reflection* true) and see if you need a type hint?

borkdude18:07:29

@cap10morgan I suspect you're prone to reflection here

cap10morgan18:07:00

yeah, seems like it. In the code where I first discovered it, it is type-hinted. I'll try that here too, though (and the keyword access).

cap10morgan18:07:41

README is pushed

cap10morgan18:07:47

huh, type hinting fixes it here, but not in the original code where it cropped up. :thinking_face:

phronmophobic18:07:00

the tools.build config is neat!

👍 4
borkdude18:07:36

the go macro is a complex beast

borkdude18:07:47

there might be something going on in the transformation

borkdude18:07:59

but then warn-on-reflection should still warn you

cap10morgan18:07:55

yeah, and I've found that warn-on-reflection seems to complain about reflection at the beginning of go blocks (not the actual lines where it occurs) no matter how much type hinting I put in there

borkdude18:07:24

might be a core.async bug

borkdude18:07:41

you can use a reflection config for now to work around it

borkdude18:07:46

on your type

borkdude18:07:27

you could try to print the output of the go macro using macroexpand-all

borkdude18:07:43

and then put that inside some .clj file with warn-on-reflection

borkdude18:07:46

to see where it goes bad

cap10morgan18:07:02

that's a good idea

cap10morgan18:07:21

looks like the reflection config fixed it (set allPublicFields and allPublicMethods to true for my type)

👍 4
cap10morgan18:07:33

going to see if there's a core.async bug to report though

cap10morgan18:07:47

oh, this is interesting. if I move the creation of the type instance into the go block (which I noticed was a difference between my actual code and the repro), it doesn't warn about reflection but it does blow up even w/ type hints. I'll push that change.

phronmophobic19:07:28

If you move the type creation into the go block, it seems like it wouldn't run at compile/build time. deftype creates a class, which can't be done at runtime.

👍 2
cap10morgan19:07:13

not the deftype, just the call to ->Thingy

cap10morgan19:07:40

facepalm but then it worked when I built it again

borkdude19:07:54

this is probably because you didn't clean ;)

borkdude19:07:06

so the type definition was still there from the previous runtime run in the JVM

borkdude19:07:33

oh, constructor call, not the deftype itself

👍 2
borkdude19:07:38

then I take back what I said

cap10morgan19:07:36

I'm trying to repro the reflection warnings on the (go ...) line behavior from my original code but no dice so far