graalvm

2022-10-05T18:58:36.438459Z

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.

borkdude 2022-10-05T19:00:03.435859Z

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

2022-10-05T20:22:48.719789Z

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.

borkdude 2022-10-05T20:37:51.429999Z

mount relies on global state right?

borkdude 2022-10-05T20:37:59.095509Z

which sounds like this may be the problem

2022-10-05T20:44:43.025439Z

Yes, I believe so (https://github.com/tolitius/mount#creating-state).

2022-10-05T20:46:58.440119Z

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?

borkdude 2022-10-05T20:49:57.463129Z

You could also use delays but same idea

2022-10-05T20:59:16.906159Z

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
2022-10-06T19:13:02.415579Z

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.

borkdude 2022-10-06T19:17:12.831039Z

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

2022-10-06T20:48:54.835049Z

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.

borkdude 2022-10-06T20:54:11.498389Z

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

2022-10-06T21:02:38.671119Z

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.