Fork me on GitHub
#graalvm
<
2022-10-05
>
Jordan Yee18:10:36

Hello, I'm attempting to build a native executable with native-image. I've been able to successfully produce an executable with a fairly minimal application, but after making some changes to the program, I am getting the following error:

Fatal error: org.graalvm.compiler.debug.GraalError: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: No instances of org.apache.commons.logging.impl.LogFactoryImpl are allowed in the image heap as this class should be initialized at image runtime. To see how this object got instantiated use --trace-object-instantiation=org.apache.commons.logging.impl.LogFactoryImpl.
I do have https://github.com/clj-easy/graal-build-time in the project, which gave me success in the first place, but it appears there's more to do. In an attempt to heed the error message, I added the specified class to an --initialize-at-run-time flag, but this doesn't fix the error:
native-image --initialize-at-run-time=org.apache.commons.logging.impl.LogFactoryImpl -jar ..\app-0.1.0-SNAPSHOT-standalone.jar
I also attempted adding a flag for the absract parent class:
--initialize-at-run-time=org.apache.commons.logging.LogFactory
https://commons.apache.org/proper/commons-logging/apidocs/org/apache/commons/logging/impl/LogFactoryImpl.html https://commons.apache.org/proper/commons-logging/apidocs/org/apache/commons/logging/LogFactory.html Any insights on how to proceed? Perhaps more generally, if we get the No instances of <OFFENDING CLASS> are allowed in the image heap as this class should be initialized at image runtime. error, then how can one determine the root cause and fix it? I'm stumped as to why the --initialize-at-run-time flag seems to have no effect.

borkdude19:10:03

This error can happen when you instantiate the logger in a Clojure namespace on the top level. Since top level expressions are executed at image build time, it will then also initialize the logger at build time

Jordan Yee20:10:48

I'm not instantiating the logger anywhere intentionally--so maybe something with a library. When I disable call to mount/start-with-args in my -main function then I'm able to build the native executable successfully. The`mount`library does appear to be addressed by graal-build-time so I don't know why calling this function triggers the error. I have 2 defstates, one that calls a next.jdbc function, and one that calls a clj-http function. I assume the logger is instantiated somewhere between those elements.

borkdude20:10:51

mount relies on global state right?

borkdude20:10:59

which sounds like this may be the problem

Jordan Yee20:10:58

Attempting to build with the mount state refactored into atoms worked but with a warning that it requires JDK for execution (which is a different issue). Would the global state thing make mount strictly incompatible for inclusion in a native executable?

borkdude20:10:57

You could also use delays but same idea

Jordan Yee20:10:16

I guess the packages registered by graal-build-time are dynamically determined and not necessarily supported in graalvm builds. I'll just get rid of mount for this application. Thanks for the help!

👍 1
Jordan Yee19:10:02

Unfortunately, I spoke too soon and am still getting the same LogFactoryImpl error after removing mount. I have no idea how I had a successful build when first refactoring out mount usages, as I cannot repeat it. Now, the error is given every time I call a function in -main that ultimately calls jdbc/execute! from the next.jdbc library.

borkdude19:10:12

How I usually approach is to try to make the smallest example possible that still reproduces the error, and then try to find a solution

Jordan Yee20:10:54

Yeah, that's the line I'm pursuing. I suspect the issue may come from the https://ucanaccess.sourceforge.net/site.html#home jdbc driver I'm using with next.jdbc to connect to an MS Access database. Is it possible to configure the native-image build to force a 3rd party library to initialize a class at runtime? I don't know if that's the right question, but I'm not sure how to proceed from here.

borkdude20:10:11

You can only initialize at runtime if the instance isn't initialized already at build time which may be the case in your application

Jordan Yee21:10:38

I'll probably fall back to just working with the .jar for now. It would be much nicer to distribute a faster, batteries-included native executable, but unfortunately that may not be possible, or at least not worth the trouble for this case.