sqlite-jdbc icon indicating copy to clipboard operation
sqlite-jdbc copied to clipboard

native image error

Open lost22git opened this issue 2 years ago • 6 comments

  • graalvm version:
openjdk 21 2023-09-19
OpenJDK Runtime Environment GraalVM CE 21+35.1 (build 21+35-jvmci-23.1-b15)
OpenJDK 64-Bit Server VM GraalVM CE 21+35.1 (build 21+35-jvmci-23.1-b15, mixed mode, sharing)
  • gradle version
gradle-8.4-rc-1
  • sql-jdbc version
org.xerial:sqlite-jdbc:3.43.0.0
  • build.gradle
graalvmNative {
  binaries {
    main {
       buildArgs.addAll([
"-Dorg.sqlite.lib.exportPath=${project.layout.buildDirectory.get()}"
       ])
    }
  }
}
  • error info when native compile
[1/8] Initializing...                                                                                    (0.0s @ 0.07GB)
Error: Feature org.sqlite.nativeimage.SqliteJdbcFeature class not found on the classpath. Ensure that the name is correct and that the class is on the classpath.
com.oracle.svm.core.util.UserError$UserException: Feature org.sqlite.nativeimage.SqliteJdbcFeature class not found on the classpath. Ensure that the name is correct and that the class is on the classpath.
        at org.graalvm.nativeimage.builder/com.oracle.svm.core.util.UserError.abort(UserError.java:73)
------------------------------------------------------------------------------------------------------------------------
        at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.FeatureHandler.registerFeatures(FeatureHandler.java:183)
        at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGenerator.setupNativeImage(NativeImageGenerator.java:897)
        at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:591)
        at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGenerator.run(NativeImageGenerator.java:551)
        at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGeneratorRunner.buildImage(NativeImageGeneratorRunner.java:538)
        at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGeneratorRunner.build(NativeImageGeneratorRunner.java:720)
        at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGeneratorRunner.start(NativeImageGeneratorRunner.java:142)
        at org.graalvm.nativeimage.builder/com.oracle.svm.hosted.NativeImageGeneratorRunner.main(NativeImageGeneratorRunner.java:97)
                        0.2s (4.1% of total time) in 16 GCs | Peak RSS: 0.47GB | CPU load: 2.92

lost22git avatar Sep 22 '23 09:09 lost22git

Could this be specific to gradle (you are using a pre-release version)? CI runs on GraalVM 21 without issues: https://github.com/xerial/sqlite-jdbc/pull/983 Gradle seems to maybe not pick up the META-INF/versions/9 files from the multi-release jar, where the SqliteJdbcFeature class is located.

kkriske avatar Sep 29 '23 16:09 kkriske

Maybe I need to invite a gradle expert @melix to help take a look at this issue

lost22git avatar Sep 29 '23 16:09 lost22git

@kkriske I have the same issue in my application, without gradle.

My workflow is roughly the following:

> /usr/lib/jvm/java-21-graalvm/bin/java -agentlib:native-image-agent=config-output-dir=META-INF/native-image -jar build/libs/opdsko-all.jar
# some logs here, also performing a couple of curl requests to warm tha application up a bit
> /usr/lib/jvm/java-21-graalvm/bin/native-image -jar build/libs/opdsko-all.jar
========================================================================================================================
GraalVM Native Image: Generating 'opdsko-all' (executable)...
========================================================================================================================
[1/8] Initializing...
                                                                                    (0.0s @ 0.27GB)
Error: Feature org.sqlite.nativeimage.SqliteJdbcFeature class not found on the classpath. Ensure that the name is correct and that the class is on the classpath.
------------------------------------------------------------------------------------------------------------------------
                        0.6s (18.4% of total time) in 19 GCs | Peak RSS: 0.92GB | CPU load: 6.73
========================================================================================================================
Finished generating 'opdsko-all' in 2.8s.

Tried the same with official Liberica NIK, without success either

asm0dey avatar Jun 28 '24 12:06 asm0dey

It seems to me that even native-image does not pick up this META-INF/versions/9 , but I checked it's there in the jar. I can share the project if you're interested

asm0dey avatar Jun 28 '24 13:06 asm0dey

I'll try to find some time to take a look, if you share the project. I'm using this in native-image without issues, on jdk 21, through gluon substrate but I doubt that should make a difference. I am using it through a classpath build, rather than a jar build though.

kkriske avatar Jun 30 '24 21:06 kkriske

I get the error on this project: https://github.com/asm0dey/opdsko I tried both gradle plugin and native-image approaches, nothing works and, for what's worse, I don't know how to debug it

asm0dey avatar Jun 30 '24 22:06 asm0dey

@asm0dey I finally had some time to take a look at your project. Files in META-INF/versions/... require Multi-Release: true in the manifest file. The shadow step in your project setup destroys the manifest included in sqlite-jdbc, which means any multi-release setup is broken, and there are more libraries in your dependencies relying on multi-release jars.

I couldn't figure our how to configure this in your build setup, because for one I haven't used gradle in ages, and second, none of the documented options of the shadow plugin you're using even resulted in a valid build script for me.

I manually edited the manifest of the opdsko-all.jar file, and added Multi-Release: true, which fixed the resolution of the feature class. I didn't look into any further native-image errors.

If the end goal is to create a native-image, you shouldn't be creating fat jars as intermidiate state, and run the native-image build plugin as part of your project.

TL;DR The issue is with your project setup, especially the fat jar, not sqlite-jdbc.

kkriske avatar Jul 22 '24 18:07 kkriske

@lost22git are you still seeing this issue? Are you creating a fatjar in your project as well?

kkriske avatar Jul 22 '24 18:07 kkriske

@kkriske what's the correct way to do it then? What I do is an official recommendation of the ktor framework, but even if not, how do I launch a relatively complex project with many modules without prebuilding it?

asm0dey avatar Jul 22 '24 19:07 asm0dey

Can you link that recommendataion? If the goal is a native image, the output is already a single artifact after using the official build plugin in your project: https://graalvm.github.io/native-build-tools/latest/gradle-plugin.html No fat jars required.

If the goal is a fat jar, it's not working as intended either way right now. Just dumping everything together in a single filesystem has always caused issues with overwriting same-name files.

kkriske avatar Jul 22 '24 19:07 kkriske

Sure, here are the ktor docs: https://ktor.io/docs/graalvm.html And they lead to the following example: https://github.com/ktorio/ktor-samples/blob/main/graalvm/build.gradle.kts

asm0dey avatar Jul 22 '24 19:07 asm0dey

Fat jar is not a goal, as s matter of fact I don't really care how the Gradle plugin builds the application. But to my understanding it's just how it works...

asm0dey avatar Jul 22 '24 19:07 asm0dey

The example you link does not use a fat jar, but the official native image plugin.

kkriske avatar Jul 22 '24 20:07 kkriske

Fair, I think I did the same with the official plugin and then deleted because it didn't work, but I'll check again

asm0dey avatar Jul 22 '24 21:07 asm0dey

@kkriske, you were right; after some experimentation I made it work, so it's not on sqlite. Sorry for bothering you.

I still do not understand why the fat jar way is wrong, but anyways this issue might be closed. Sorry for wasting your time.

asm0dey avatar Jul 23 '24 18:07 asm0dey

The fat jar approach is not "wrong" persé, but it's prone to issues since it needs to correctly merge metadata of multiple jars, and any duplicate file occurring in more than one jar needs special care. The manifest is such a file. Your fat jar plugin simply does not correctly merge everything together, or is possibly missing configuration to tell it to handle certain files. E.g. in maven you need to specifically tell it to merge service loader resource files, by default it'll just keep one of the duplicates at random.

Not closing this since it's unclear if your issue was the same as the original issue of @lost22git. Also I don't have permission to close issues 🤷

kkriske avatar Jul 23 '24 19:07 kkriske