mvn spring-boot:build-image -Pnative
This works, even if the Spring Boot Maven Plugin nor the Native Build Tools Plugin have been applied in the project as the native
profile brings them.
It should be noted that repackage
runs for the reason above.
mvn native:compile -Pnative
This works, even if the Spring Boot Maven Plugin nor the Native Build Tools Plugin have been applied in the project as the native
profile brings them.
We know this command will never work with a multi-modules project
mvn spring-boot:build-image -Pnative
We can see that the reachability metadata is running on the root POM.
We can see that it fails early as process AOT is trying to run on the root pom.
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] multi-buildpacks [pom]
[INFO] multi-buildpacks-lib [jar]
[INFO] multi-buildpacks-app [jar]
[INFO]
[INFO] ---------------< com.example.multinbt:multi-buildpacks >----------------
[INFO] Building multi-buildpacks 0.0.1-SNAPSHOT [1/3]
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] >>> spring-boot-maven-plugin:3.0.0-SNAPSHOT:build-image (default-cli) > package @ multi-buildpacks >>>
[INFO]
[INFO] --- native-maven-plugin:0.9.17:add-reachability-metadata (add-reachability-metadata) @ multi-buildpacks ---
[INFO] Downloaded GraalVM reachability metadata repository from file:/Users/snicoll/.m2/repository/org/graalvm/buildtools/graalvm-reachability-metadata/0.9.17/graalvm-reachability-metadata-0.9.17-repository.zip
[INFO]
[INFO] --- spring-boot-maven-plugin:3.0.0-SNAPSHOT:process-aot (process-aot) @ multi-buildpacks ---
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for multi-buildpacks 0.0.1-SNAPSHOT:
[INFO]
[INFO] multi-buildpacks ................................... FAILURE [ 0.877 s]
[INFO] multi-buildpacks-lib ............................... SKIPPED
[INFO] multi-buildpacks-app ............................... SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.286 s
[INFO] Finished at: 2022-11-21T10:12:10+01:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:3.0.0-SNAPSHOT:process-aot (process-aot) on project multi-buildpacks: Unable to find a suitable main class, please add a 'mainClass' property -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
We know this command will never work with a multi-modules project
mvn native:compile -Pnative
We can see that the reachability metadata is running on the root POM.
We can see that it fails early as process AOT is trying to run on the root pom.
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] multi-nbt [pom]
[INFO] multi-nbt-lib [jar]
[INFO] multi-nbt-app [jar]
[INFO]
[INFO] -------------------< com.example.multinbt:multi-nbt >-------------------
[INFO] Building multi-nbt 0.0.1-SNAPSHOT [1/3]
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] >>> native-maven-plugin:0.9.17:compile (default-cli) > package @ multi-nbt >>>
[INFO]
[INFO] --- native-maven-plugin:0.9.17:add-reachability-metadata (add-reachability-metadata) @ multi-nbt ---
[INFO] Downloaded GraalVM reachability metadata repository from file:/Users/snicoll/.m2/repository/org/graalvm/buildtools/graalvm-reachability-metadata/0.9.17/graalvm-reachability-metadata-0.9.17-repository.zip
[INFO]
[INFO] --- spring-boot-maven-plugin:3.0.0-SNAPSHOT:process-aot (process-aot) @ multi-nbt ---
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for multi-nbt 0.0.1-SNAPSHOT:
[INFO]
[INFO] multi-nbt .......................................... FAILURE [ 1.109 s]
[INFO] multi-nbt-lib ...................................... SKIPPED
[INFO] multi-nbt-app ...................................... SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.901 s
[INFO] Finished at: 2022-11-21T10:13:42+01:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:3.0.0-SNAPSHOT:process-aot (process-aot) on project multi-nbt: Unable to find a suitable main class, please add a 'mainClass' property -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
The current arrangement is a bit unusual as triggering the profile enables the actual execution of two plugins, regardless of the nature of the module. The Spring Boot Maven Plugin and the Native Build Tools plugin are applied on all modules, which makes a setup with a multi-modules project impossible.
The obvious proposal is to move everything to pluginManagement
so that things are only applied if the related plugin is in use. As we will see, this has some side effects.
mvn spring-boot:build-image -Pnative
This runs and fails as process AOT didn't run at all. The project above was wrong to begin with as it didn't apply the Spring Boot Maven plugin at all, something that is to be expected for a Spring Boot app.
If we add the Spring Boot Maven Plugin, this looks like it works but it really isn't as the reachability metadata has not been fetched. Adding a reference to the native build tools plugin fixes this.
mvn native:compile -Pnative
This runs and fails as process AOT didn't run at all. The project above was wrong to begin with as it didn't apply the Spring Boot Maven plugin at all, something that is to be expected for a Spring Boot app.
If we add the Spring Boot Maven Plugin, it works. We can see that the additional execution of the NBT metadata goal does not run, as we have triggered a goal of the native
plugin, but not configured the actual plugin to contribute whatever the parent and/or a profile can do.
It works because, in the absence of metadata, the compile
goal is going to fetch it. That looks like some sort of fallback that's welcome for this particular case.
The command below still fails but it makes much more sense now.
mvn spring-boot:build-image -Pnative
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] multi-buildpacks [pom]
[INFO] multi-buildpacks-lib [jar]
[INFO] multi-buildpacks-app [jar]
[INFO]
[INFO] ---------------< com.example.multinbt:multi-buildpacks >----------------
[INFO] Building multi-buildpacks 0.0.1-SNAPSHOT [1/3]
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] >>> spring-boot-maven-plugin:3.0.0-SNAPSHOT:build-image (default-cli) > package @ multi-buildpacks >>>
[INFO]
[INFO] <<< spring-boot-maven-plugin:3.0.0-SNAPSHOT:build-image (default-cli) < package @ multi-buildpacks <<<
[INFO]
[INFO]
[INFO] --- spring-boot-maven-plugin:3.0.0-SNAPSHOT:build-image (default-cli) @ multi-buildpacks ---
[INFO]
[INFO] -------------< com.example.multinbt:multi-buildpacks-lib >--------------
[INFO] Building multi-buildpacks-lib 0.0.1-SNAPSHOT [2/3]
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] >>> spring-boot-maven-plugin:3.0.0-SNAPSHOT:build-image (default-cli) > package @ multi-buildpacks-lib >>>
[INFO]
[INFO] --- maven-resources-plugin:3.3.0:resources (default-resources) @ multi-buildpacks-lib ---
[INFO] skip non existing resourceDirectory /Users/snicoll/workspace/work/spring-aot-smoke-tests/boot/maven-parent/multi-buildpacks/multi-buildpacks-lib/src/main/resources
[INFO] skip non existing resourceDirectory /Users/snicoll/workspace/work/spring-aot-smoke-tests/boot/maven-parent/multi-buildpacks/multi-buildpacks-lib/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.10.1:compile (default-compile) @ multi-buildpacks-lib ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/snicoll/workspace/work/spring-aot-smoke-tests/boot/maven-parent/multi-buildpacks/multi-buildpacks-lib/target/classes
[INFO]
[INFO] --- maven-resources-plugin:3.3.0:testResources (default-testResources) @ multi-buildpacks-lib ---
[INFO] skip non existing resourceDirectory /Users/snicoll/workspace/work/spring-aot-smoke-tests/boot/maven-parent/multi-buildpacks/multi-buildpacks-lib/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.10.1:testCompile (default-testCompile) @ multi-buildpacks-lib ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ multi-buildpacks-lib ---
[INFO] No tests to run.
[INFO]
[INFO] --- maven-jar-plugin:3.3.0:jar (default-jar) @ multi-buildpacks-lib ---
[INFO] Building jar: /Users/snicoll/workspace/work/spring-aot-smoke-tests/boot/maven-parent/multi-buildpacks/multi-buildpacks-lib/target/multi-buildpacks-lib-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] <<< spring-boot-maven-plugin:3.0.0-SNAPSHOT:build-image (default-cli) < package @ multi-buildpacks-lib <<<
[INFO]
[INFO]
[INFO] --- spring-boot-maven-plugin:3.0.0-SNAPSHOT:build-image (default-cli) @ multi-buildpacks-lib ---
[INFO] Building image 'docker.io/library/multi-buildpacks-lib:0.0.1-SNAPSHOT'
[INFO]
[INFO] > Pulling builder image 'docker.io/paketobuildpacks/builder:tiny' 100%
[INFO] > Pulled builder image 'paketobuildpacks/builder@sha256:97038c4c8b0907b1084526a409cdc29010d690e56ee789eca5d369a6c55ef128'
[INFO] > Pulling run image 'docker.io/paketobuildpacks/run:tiny-cnb' 100%
[INFO] > Pulled run image 'paketobuildpacks/run@sha256:6edd2f36f33b08a4553449b91cd4f4d4bcffd1c8d7677b35790d1b80fa13720c'
[INFO] > Executing lifecycle version v0.15.1
[INFO] > Using build cache volume 'pack-cache-3361f01b477e.build'
[INFO]
[INFO] > Running creator
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for multi-buildpacks 0.0.1-SNAPSHOT:
[INFO]
[INFO] multi-buildpacks ................................... SUCCESS [ 0.479 s]
[INFO] multi-buildpacks-lib ............................... FAILURE [ 3.774 s]
[INFO] multi-buildpacks-app ............................... SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.993 s
[INFO] Finished at: 2022-11-21T10:55:14+01:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:3.0.0-SNAPSHOT:build-image (default-cli) on project multi-buildpacks-lib: Execution default-cli of goal org.springframework.boot:spring-boot-maven-plugin:3.0.0-SNAPSHOT:build-image failed: Error packaging archive for image: Unable to find main class -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginExecutionException
[ERROR]
[ERROR] After correcting the problems, you can resume the build with the command
[ERROR] mvn <args> -rf :multi-buildpacks-lib
build image is applied on a library, which does not have a main class and should not be considered.
To fix this in a multi-modules project, we need to opt-in to whatever we want to use to build the image. This can be done by adding the specified profile in the app
module:
<profile>
<id>native</id>
<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>build-image</id>
<goals>
<goal>build-image</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
The image can be created as follows (from the root, as usual):
mvn package -Pnative
The command below still fails
mvn native:compile -Pnative
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] multi-nbt [pom]
[INFO] multi-nbt-lib [jar]
[INFO] multi-nbt-app [jar]
[INFO]
[INFO] -------------------< com.example.multinbt:multi-nbt >-------------------
[INFO] Building multi-nbt 0.0.1-SNAPSHOT [1/3]
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] >>> native-maven-plugin:0.9.17:compile (default-cli) > package @ multi-nbt >>>
[INFO]
[INFO] <<< native-maven-plugin:0.9.17:compile (default-cli) < package @ multi-nbt <<<
[INFO]
[INFO]
[INFO] --- native-maven-plugin:0.9.17:compile (default-cli) @ multi-nbt ---
[INFO] Found GraalVM installation from JAVA_HOME variable.
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for multi-nbt 0.0.1-SNAPSHOT:
[INFO]
[INFO] multi-nbt .......................................... FAILURE [ 0.695 s]
[INFO] multi-nbt-lib ...................................... SKIPPED
[INFO] multi-nbt-app ...................................... SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.494 s
[INFO] Finished at: 2022-11-21T11:04:45+01:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.graalvm.buildtools:native-maven-plugin:0.9.17:compile (default-cli) on project multi-nbt: Image classpath is empty. Check if your classpath configuration is correct. -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException
This is better as the error message is directly linked to the goal that was used. Our native profile doesn't go in the way anymore.
Same thing as Buildpacks, we want to identify the module where running this goal makes sense and use the package
phase. This profile does the trick
<profile>
<id>native</id>
<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
<executions>
<execution>
<id>build-image</id>
<goals>
<goal>compile-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
Not applying the plugins unless they have been specified makes the multi-modules arrangeement more idiomatic. It makes the user experience for single module a bit harder as you need to apply an extra plugin. It makes it more obvious though that Buildpacks relies on NBT to work.