oracle / graal

GraalVM compiles Java applications into native executables that start instantly, scale fast, and use fewer compute resources 🚀
https://www.graalvm.org
Other
20.06k stars 1.6k forks source link

Add native-image flags and options programatically in an `@AutomaticFeature` class #2527

Open ilopmar opened 4 years ago

ilopmar commented 4 years ago

Feature request

I would like to request a feature to be able to add native-image flags and options programatically.

Is your feature request related to a problem? Please describe.

To add GraalVM support different 3rd party libraries that we use in Micronaut we need to tell the users to add different options to the native-image command.

For example, to make SQL Server work the user needs to add -H:+AddAllCharsets, for H2 and Oracle they need to add --report-unsupported-elements-at-runtime (even if it's discouraged).

We've solved the issue of declaring and configuring the different JDBC drivers and option creating a couple of @AutomaticFeature classes and every thing works really good.

What I would like to have is also the option to enable a flag like -H:+AddAllCharsets from an @AutomaticFeature class when we detect the user is using SQL Server. Or add the option --report-unsupported-elements-at-runtime when we detect they use H2.

Describe the solution you'd like.

Add a way to programatically be able to enable the different options/flags from @AutomaticFeatures classes.

Describe who do you think will benefit the most.

This feature will benefit GraalVM users because they won't be to add any flags to generate a native-image. The framework creators would be able to add the different options/configuration embedded in the frameworks to configure everything (like we already do including file like native-image.properties in the framework jars).

Describe alternatives you've considered.

N/A

Additional context.

N/A

Express whether you'd like to help contributing this feature

I would try it for sure to configure the different options inside Micronaut if you implement it.

olpaw commented 4 years ago

Why are you not not just bundling a native-image.properties file in a jar-file. If you put a native-image.properties file somewhere below META-INF/native-image it can specify any additional native-image command line options you like.

Args = --features=my.custom.feature -H:+AddAllCharsets --report-unsupported-elements-at-runtime

Putting such a jar-file on your image classpath is equivalent to adding all the options specified in the native-image.properties file. See Composable native-image.properties in https://medium.com/graalvm/simplifying-native-image-generation-with-maven-plugin-and-embeddable-configuration-d5b283b92f57

ilopmar commented 4 years ago

We already do that in different places in the framework. The "problem" of embedding a native-image.properties is that is always included, no matter the application the users are building. What I would like is to be able to decide programatically if I want to include something or not.

For example, we've written a coupe of @AutomaticFeatures to deal with the different jdbc drivers and configuration for different databases:

With this approach users don't need to worry about how to configure their applications because Micronaut will do it for them.

What I would like is a feature to be able to include here, for example for H2: https://github.com/micronaut-projects/micronaut-sql/blob/master/jdbc/src/main/java/io/micronaut/jdbc/nativeimage/JdbcFeature.java#L67-L81

The ability to include -H:+AddAllCharsets and --report-unsupported-elements-at-runtime. But only for that H2 case and not for Postgres or MariaDB that we know they don't need it.

olpaw commented 4 years ago

I see. JdbcFeature is a one-size-fits-all Feature that does different things depending on which database drivers are on the image classpath. And you would like to dynamically set native-image options based on that.

ilopmar commented 4 years ago

Yeah, exactly!

olpaw commented 4 years ago

Unfortunately this is currently not possible because HostedOptions get constant folded during image building and therefore have to be immutable. While you can use org.graalvm.compiler.options.OptionKey#update in the context of com.oracle.svm.core.option.HostedOptionKey#onValueUpdate you cannot easily do this anywhere else. Also doing so would not be safe because nothing guarantees that your org.graalvm.nativeimage.hosted.Feature#afterRegistration runs before the afterRegistrations of features that read the option values you are trying to change (it is possible to influence the order in which those methods are executed but only from the other side: org.graalvm.nativeimage.hosted.Feature#getRequiredFeatures).

olpaw commented 4 years ago

That being said, in the case of AddAllCharsets you could call com.oracle.svm.core.jdk.LocalizationFeature#addCharset from your feature with the same piece of code that LocalizationFeature executes when it evaluates AddAllCharsets (see com.oracle.svm.core.jdk.LocalizationFeature#addCharsets).

for (Charset c : Charset.availableCharsets().values()) {
    addCharset(c);
}

but keep in mind that this somewhat fragile since you depend on our internal APIs which are subject to change.

olpaw commented 4 years ago

For --report-unsupported-elements-at-runtime I do not see a feasible solution.

ilopmar commented 4 years ago

Thanks for the detailed explanations.

I thought about using your internal class for that flag but I discarded it because, as you mentioned, it's fragile and I don't want to rely on that. That's why I thought about creating this feature request to see if there was an option or possibility to enable those flags during image generation.