How to use Graalvm build args in native image compilation?

When I generate the native image the end always offers some suggestions:

Recommendations:
 AWT:  Use the tracing agent to collect metadata for AWT.
 HEAP: Set max heap for improved and more predictable memory usage.
 CPU:  Enable more CPU features with '-march=native' for improved performance.

How can I implement those?

I tried just using them in the command: mvn -Pproduction -Pnative -march=native native:compile

But the returns an error: Unable to parse command line options: Unrecognized option: -march=native

Is it possible to include build args in the pom.xml? I have done this in the past using the graalvm maven plugin, but I’m not sure how to do that with Vaadin. If I add the plugin, will that conflict with the Vaadin implementation?

I found this example on GitHub. It’s quite complex. Lots of plugins, including the graalvm maven plugin. Maybe that just overrides the Vaadin implementation? Is that the right way to do it?

IIRC, you can pass those args to the native-maven-plugin, as in the example you linked to vaadin-native-image/pom.xml at bd121e97689ffe1bff24bb05bedf5da76b28e4ac · oliveryasuna/vaadin-native-image · GitHub

Thanks Marcus, my project does not have native-maven-plugin, but it does have vaadin-maven-plugin. I assume that’s the one I need since it’s in the production profile?

No, that doesn’t work. buildArgs are not allowed there.

This is a project I downloaded from the Vaadin app creator, so the pom file is still setup that way.

I believe that it’s defined in the parent Spring pom, but can be overridden in your own if needed.

Thanks Marcus. Can you be a little more specific? What is the parent Spring pom?

There is a single pom file. In the pom file are many plugins defined.

  • spring-boot-maven-plugin
  • spotless-maven-plugin
  • vaadin-maven-plugin
  • vaadin-maven-plugin (defined a second time in the production profile)
  • spring-boot-maven-plugin
  • maven-failsafe-plugin

You can see my confusion?

<build>
        <defaultGoal>spring-boot:run</defaultGoal>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>com.diffplug.spotless</groupId>
                <artifactId>spotless-maven-plugin</artifactId>
                <version>2.43.0</version>
                <configuration>
                    <java>
                        <palantirJavaFormat>
                            <version>2.50.0</version>
                        </palantirJavaFormat>
                    </java>
                    <!-- Uncomment to format TypeScript files 
                        <typescript>
                        <includes>
                            <include>src/main/frontend/**/*.ts</include>
                        </includes>
                        <excludes>
                            <exclude>src/main/frontend/generated/**</exclude>
                        </excludes>
                        <prettier>
                            <prettierVersion>3.3.3</prettierVersion>
                            <configFile>.prettierrc.json</configFile>
                        </prettier>
                    </typescript>
                -->
                </configuration>
            </plugin>
            <plugin>
                <groupId>com.vaadin</groupId>
                <artifactId>vaadin-maven-plugin</artifactId>
                <version>${vaadin.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>prepare-frontend</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

    <profiles>
        <profile>
            <!-- Production mode is activated using -Pproduction -->
            <id>production</id>
            <dependencies>
                <!-- Exclude development dependencies from production -->
                <dependency>
                    <groupId>com.vaadin</groupId>
                    <artifactId>vaadin-core</artifactId>
                    <exclusions>
                        <exclusion>
                            <groupId>com.vaadin</groupId>
                            <artifactId>vaadin-dev</artifactId>
                        </exclusion>
                    </exclusions>
                </dependency>
            </dependencies>
            <build>
                <plugins>
                    <plugin>
                        <groupId>com.vaadin</groupId>
                        <artifactId>vaadin-maven-plugin</artifactId>
                        <version>${vaadin.version}</version>
                        <executions>
                            <execution>
                                <goals>
                                    <goal>build-frontend</goal>
                                </goals>
                                <phase>compile</phase>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>

        <profile>
            <id>it</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-maven-plugin</artifactId>
                        <executions>
                            <execution>
                                <id>start-spring-boot</id>
                                <phase>pre-integration-test</phase>
                                <goals>
                                    <goal>start</goal>
                                </goals>
                            </execution>
                            <execution>
                                <id>stop-spring-boot</id>
                                <phase>post-integration-test</phase>
                                <goals>
                                    <goal>stop</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>

                    <!-- Runs the integration tests (*IT) after the server is started -->
                    <plugin>
                        <groupId>org.apache.maven.plugins</groupId>
                        <artifactId>maven-failsafe-plugin</artifactId>
                        <executions>
                            <execution>
                                <goals>
                                    <goal>integration-test</goal>
                                    <goal>verify</goal>
                                </goals>
                            </execution>
                        </executions>
                        <configuration>
                            <trimStackTrace>false</trimStackTrace>
                            <enableAssertions>true</enableAssertions>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>

    </profiles>

Somewhere near the top of the pom file, you’ll see a parent definition like this:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.3.4</version>
</parent>

If you control/cmd click on that in your IDE, it’ll take you to the spring-boot-starter-parent pom file where the native-maven-plugin is configured.

I’ve never needed to override the plugin configuration for my projects.

1 Like

Ah, but this not a file I can edit. I need to add the build args to my own pom file.

I’ve never needed to override the plugin configuration for my projects.

Really? Every single time I have compiled a native image it gives me suggestions of things to change. Does that never happen to you?

Looking at the native-maven-plugin docs, it seems you can also provide build arguments with the -DbuildArgs system property (however I didn’t tried)

1 Like

Either way. I don’t care how they get applied. I would also just add them to the compile command if I knw how.

So just use the system property.

mvn -Pproduction -Pnative -DbuildArgs=“…” native:compile

4 Likes

That worked!

mvn -Pproduction -Pnative -DbuildArgs="-march=native" native:compile

1 Like

This is good to know :) This way you can also use things like the Quick Build Mode to speed up your builds during development.

mvn package -Pproduction -Pnative -DbuildArgs="-Ob,-march=native" native:compile
1 Like

Yes! I would still like to learn how to put the build args into the pom file, though. Do you know how?

You can reconfigure the native-maven-plugin in your pom (see documentation Maven plugin for GraalVM Native Image building), or in this case, since it simply overriding a configuration exposed as property, just add <buildArgs> item in the <properties> section of your POM file.

1 Like

Here is another example. I added the plugin configuration and the build args to the production profile in the pom.xml:

    <profiles>
        <profile>
            <!-- Production mode is activated using -Pproduction -->
            <id>production</id>
            <dependencies>
                <!-- Exclude development dependencies from production -->
                <dependency>
                    <groupId>com.vaadin</groupId>
                    <artifactId>vaadin-core</artifactId>
                    <exclusions>
                        <exclusion>
                            <groupId>com.vaadin</groupId>
                            <artifactId>vaadin-dev</artifactId>
                        </exclusion>
                    </exclusions>
                </dependency>
            </dependencies>
            <build>
                <plugins>
                    <plugin>
                        <groupId>com.vaadin</groupId>
                        <artifactId>vaadin-maven-plugin</artifactId>
                        <version>${vaadin.version}</version>
                        <executions>
                            <execution>
                                <goals>
                                    <goal>build-frontend</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                    <plugin>
                        <groupId>org.graalvm.buildtools</groupId>
                        <artifactId>native-maven-plugin</artifactId>
                        <configuration>
                            <buildArgs>
                                <buildArg>-Ob</buildArg>
                            </buildArgs>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>
1 Like

Ah, ok, so you are overriding the same native-maven-plugin that must be used somewhere by vaadin-maven-plugin? Thanks!

Just to clarify: the native-maven-plugin is not used by vaadin-maven-plugin. It is configured by the spring boot parent pom your project is extending.
And of course you can override its configuration in your pom file.

1 Like

I’m confused. In a non-Vaadin spring boot project, you would have to add native-maven-plugin to your pom file, but in a Vaadin project, you do not. So…I’m confused. How can you run mvn -Pproduction -Pnative native:compile on a Vaadin project if native-maven-plugin is not in the pom file?