Fork me on GitHub

I'm looking at adding native-image support to pack. I know there is already clj.native-image, but it doesn't have a clojure tools (-T) usage, nor a API. Are there any complications/shortcuts/clever hacks that pack could help with? @borkdude I know you do a lot of scripting voodoo with native-image compilation, and it'd be great to port those to be defaults for the whole community using pack if possible.


Additionally, on the off chance anyone knows, I'd love to know the state of using svm-driver to build native-image without graalvm/native-image being installed. I've asked on the graal slack, but I'm not expecting an answer. The maven plugin briefly had support for it, but it was removed.


Seemingly it's not supported right now, due to certain patches in graalvm not being upstreamed yet. That means it's unreliable between versions. That's unfortunate.


Why would you want to add the svm driver?


Then pack could compile a native image without needing the user to use graalvm.

👍 1

It would run on, eg openjdk


Is that even possible? Where is that documented?


My experience with including the svm driver in a project is not good. It makes it incompatible over different version of GraalVM


It is. The maven plugin used to do it. It's not documented. The maven plugin removed the functionality because it doesn't consistently work for all JDKs and svm versions because of patch upstreaming.


It is not that hard to just download GraalVM to a temp folder and use it. The convention that is used is GRAALVM_HOME- I use that in all my compile scripts


I am considering doing that, yeah. I prefer the version of graal being pinned to the repo, rather than whatever version the user chooses, as it's got a higher reproducibility.


I didn't mean that the tool should download graalvm, I don't like that


I mean, for the user it is not hard at all to grab a version of graalvm and use that for compilation


Because I want to use a specific version of graalvm and not be dependent on some tool doing that for me, I'm capable of doing that myself


But if you rock up at a repo, which version is that?


rock up at a repo, what does that mean?


If you are contributing to a new repo, which graal version does the maintainer want to make releases with?


usually the newest, but older ones work too. it's the same with Clojure, you don't usually specify the JVM version in your repo, and clj doesn't magically grab a 1GB download from the internets


I don't think that comparison is analogous, it's more like specifying which version of the JDK you want your docker image to run with. Releases are a little different from development in terms of increasing consistency. Native image also seems more unstable than the standard JDK. It is also far more user-dependent due to a lack of distribution packaging because of the licensing. My perspective on instability could be inaccurate because I'm watching from afar.


It's been pretty stable since 21.3


or 21.0 or so


Didn't 22 break how initialization worked and break many clojure programs?


It deprecated an option, but it didn't actually break anything


and clj-easy/graal-build-time is what fixes this


so we're ready for deprecation by removal


Oh, so it isn't going yet. Good to know. I misunderstood. Still, people might get stuck on older versions.


I usually specify the graalvm version in documentation and people can also check in CI or a Dockerfile. If something is not working, I tell them to upgrade.


but I might not be the right audience for your tool, I don't think I would ever use a tool again which wraps native-image


as that has bitten me in the past. just use the vanilla tool is what I recommend


There's also nuances like musl, etc which pack is probably not going to solve


My opinion is that having an uberjar tool is great, but from there on, just write a script to build with native image


Perhaps @UE21H2HHD has a different opinion :)


My humble opinions? simple_smile So for the topic of svm… if I’ve understood… I recommend going with the flow and using Graal tooling. Graal is complicated enough without introducing unsupported or uncommonly used configurations.


And… are you also talking about a build wrapper? I thinking rolling your own makes sense. It is not that complicated and also educates you, at least a bit, on the working of Graal. There are lots of levers and dials to fiddle with for Graal native-image. I personally want to be able to twiddle all that myself. I might reuse this on other projects, but only as a template that I would copy and paste.

👍 1

It seems inefficient and exclusionary to have scripts which are copied around. At the least, a tool could handle locating the native image binary and perhaps give you a few of the boring arguments (eg -cp) to pass to native image. I'm certain there's a solution which both exposes the dials AND reduces the maintenance effort across everyone. Clojure always optimizes for power users first, but it still becomes easier over time.


For example, that version assertion is dope. The perfect function to expose in a library. You could even stick a simple range on it.


Yeah, I felt the temptation at one point too @dominicm! But Graal native-image is so early days and fiddly that I felt that it was not practical to generalize. That’s just me, though! Not at all saying you are wrong and I am right, just sharing.


> At the least, a tool could handle locating the native image binary This is what the GRAALVM_HOME environment variable convention is for. The Github Action helps you with setting this up in CI, but doing it manually is trivial too (I've done it manually so far).


I also don't want to call native-image from within a JVM process since graalvm is very memory hungry and wasting extra memory on calling it from a JVM isn't something I want. Just a shell script will do.


If you leave more memory to native-image it will likely also be faster as it spends less time in GC.


Yeah, that's why I wanted to use the svm-driver so there's only one VM.


That's a great tip, exactly the kind of thing I'm looking for. I know native image will always be highly configured, but I'd love to make the basic hello world fairly seamless.


I think it makes sense to always compile to an uberjar first and then use -jar foo.jar


And always use "--no-fallback"


that should be about it for Clojure I think


Why an uberjar and not a classpath?


It doesn't matter much, but I find it easier to reason about an uberjar. e.g you can test if java -jar foo.jar works, if that doesn't work, then native image will fail as well


but classpath should work as well


I've had some problems with long classpaths on Windows where an uberjar did work correctly


but perhaps will fix that correctly now


I wonder if that applies when using process command?


I also wonder if native image can handle classpaths inside a jar manifest


I also find myself wanting to publish an uberjar as an alternative to the native image anyways, so I would need both


And a good default is to allow arbitrary native image arguments on top of the defaults as every projects requires its own settings