Ok, use the direct-linking helped reducing some weird classes, I used the output config to the native image input and the result looks better than before 😄
now it seems to load LSP correctly and communication work (json ser/deser), but I'm having a issue when responding with clojure.spec.alpha/conform
https://github.com/clojure-lsp/clojure-lsp/blob/master/src/clojure_lsp/interop.clj#L409.
Basically we use this function everytime we want to respond to client, so we validate if server response is following the spec and do some clj-map->java transformations (nothing magical, just instantiating the class manually)
https://pastebin.pl/view/6450ceea
It was related with some instances not being recognized in runtime, fixed it using some type hints 😄
That's amazing, heaviness of clojure-lsp was a bit of a show stopper for me in the early days, can't wait to try out the native-image version
1😉Yes, looking forward to this one indeed!
Looking forward to it! Maybe you can even write a report of your adventure so that we can maybe profit on the java->native experience!
1Hey @borkdude Just got a corner case with sqlite 😕
It seems to throw a segfault when the db does not exists: (missing .lsp/sqlite.db
)
https://pastebin.com/JqHJPJzk
Right on this line: https://github.com/clojure-lsp/clojure-lsp/blob/master/src/clojure_lsp/db.clj#L35
@ericdallo I don't know what causes this. Where did you get the suggestions for the reflection / JNI config for sqlite?
Right here: https://github.com/xerial/sqlite-jdbc/issues/413
From the example: https://github.com/xerial/sqlite-jdbc/issues/413#issuecomment-525926912
@ericdallo Does his Java example work correctly when the db does not exist?
Hum... I didn't test, good point, I'll test it
And to double check, you added all these classes to the JNI config right? https://github.com/mageddo/graalvm-examples/blob/59f1f1bf09894681edfddaa100b4504770ad0685/sqlite/src/main/java/com/mageddo/sqlite/JNIReflectionClasses.java#L46-L55 and to reflection
Also try graalvm java 8 instead of 11
Yes, they are on https://github.com/ericdallo/sqlite-jni-graal-fix workaround
reflection not really
Oh, just found some classes missing from the fix, I don't know why, I'll add them too
That is done here, reflection: https://github.com/ericdallo/sqlite-jni-graal-fix/blob/61aba255490c5facbc94cabd43e22aff6a69e5a3/src-java/ericdallo/JNIReflectionClasses.java#L80
Oh, yeah, so it's enough probably
I realized it's missing the Throwable class
since when don't find the db it should throw an exception, may be related
yeah
1Btw, Quarkus is a Java framework by Oracle of which all extensions can be compiled to native. Sometimes nice to borrow stuff from as well: https://github.com/quarkusio/quarkus/tree/master/extensions/jdbc
Hum, interesting
Yep, it fixed the issue 🙂 Probably it was the missing Throwable... that is not on that repo master, only on that specific commit
cool
a segfault like that is really hard to debug...
yep
this is why you should probably not just switch to native, but offer this as something experimental ;)
and keep offering the JVM jar as well
among other reasons
but it's cool that you got sqlite to work. maybe I can switch my pod from go to clojure now ;) although the golang pod is really small (few megabytes)
does LSP native not require you to have sqlite installed, some libsqlite thing on your system? maybe try the binary in a bare ubuntu docker image (if that hasn't got it by default)?
Yeah, My idea is if everything work provides that as experimental for some time
Note that if you exclusively offer the native, you will probably have to provide it for the three major OSes and also a static one for alpine
yes, since I use NixOS there is no way to use a lib that I didn't tell it to use, but a test on a docker it'd really help to make sure
Yes, I have in mind setup a CI for the 3 OS building via GH actions, just like babashka
1@borkdude how the nrepl just for dev would work? In the code should I check somehow what is the profile/some env var? This would affect graal?
I can add the dep for the dev profile only, but my question is how should I code that to use for dev only or something like that
yeah, you can do it through an env var or just by trying to resolve it on the top level:
(when-let [server-var (try (requiring-resolve 'nrepl.server/server) (catch Exception e nil))]
...
note that it's best to keep this at the top level so it's not resolved at run time
the native-image will compile this away
and then of course you move the nrepl deps to a dev profile
or alias
got it, do you use anything like that in your projects?
yeah, this is how all the features in babashka are implemented
see build.md, feature flags
cool, thanks!
@ericdallo I also have this library: https://github.com/borkdude/dynaload
Oh I liked this one: https://github.com/babashka/babashka/blob/6dc6cbab12910f6b93fa52c66e2f7da1a3213b09/src/babashka/impl/classes.clj#L322
that dynaload seems to fit perfect this use case
should I wrap the dynaload call with a try catch to check if nrepl is enabled? Or is better to check a env var?
What you can do is do a require based on an env var. And then use dynaload to use the var(s)
what is the point to use dynaload if I can just require 'mylist
? I think I don't get it
Oh, it won't compile if I don't require it.. it makes sense
dynaload just use a symbol and do the magic
this is more useful for libraries than apps probably. in libraries you can say: I can work with these vars, if you have required the lib already
in normal JVM dynaload will also do the require for you
but for GraalVM this has a negative impact on binary size
although it will still work
I see
To keep it simple: Just do a try catch where you try to require/resolve the lib/vars. If you then provide the library on your classpath, the vars will work. Else they won't do anything.
great