FS-native-builds: Both plugins build native images from build-tool project state
August 10, 2026 · View on GitHub
Both product plugins must translate Gradle or Maven project state into a single native-image
invocation. The user's durable configuration lives in the build file (Gradle DSL or Maven XML);
one-off command-line overrides feed the same command-line assembly path so behavior does not
diverge by configuration source. This contract realizes §GOAL-plugin-parity
together with §FS-plugin-common, and is adapted by §gradle/FS-native-tasks and
§gradle/FS-native-invocation for Gradle and §maven/FS-goal-surface.1 and
§maven/FS-native-builds for Maven.
1. Required inputs
A native image build must derive the following from project state and configuration:
| Input | Contract |
|---|---|
| Classpath and module path | Derived from selected build-tool project state. |
| Entry point or shared-library mode | Derived from user configuration, build-tool conventions, or build-tool-specific discovery. |
| Image name and output location | Derived from user configuration or stable build-tool conventions. |
| Build arguments | Combined from durable configuration and documented command-line overrides. |
| JVM arguments, system properties, environment variables | Passed to the native-image driver process when configured. |
| Configuration file directories | Include generated resource config (§FS-resources-and-metadata.1), resolved repository metadata (§FS-resources-and-metadata.2), and dynamic access metadata (§FS-resources-and-metadata.4). |
| Optional inputs | Include classpath JAR (§GLOSS-fat-jar), argument file (§GLOSS-argument-file), layer options (§GLOSS-layered-image), and PGO options (§GLOSS-pgo) when supported by the plugin. |
Gradle-specific task inputs are specified by §gradle/FS-native-tasks and §gradle/FS-native-invocation. Maven-specific goal inputs are specified by §maven/FS-goal-surface, §maven/FS-native-builds, and §maven/FS-config-model.
2. Command-line construction
Both plugins must construct the native-image command line through shared utilities from
§common/FS-common-libraries.1 so escaping, quoting, and argument-file conversion stay identical.
Plugin-specific string handling must not bypass those utilities.
When a build tool disables colored console output, its adapter must explicitly disable Native Image colors with the flag supported by the discovered Native Image version. When console colors are enabled, plugin-specific rich-output configuration may enable them explicitly. User-supplied build arguments retain precedence over the adapter's detected console mode.
When a user-configured option set exceeds platform argument limits, or when configuration requests
it explicitly, the command line must be written as a Native Image argument file (@<path>).
3. Executable lookup
native-image must be located from the configured Java toolchain when toolchain detection is
enabled, then from GRAALVM_HOME/JAVA_HOME/PATH fallbacks. Failure messages must name which
lookup paths were attempted and what was found.
4. Version and schema gates
When the user configures a required Native Image version, the build must fail before invoking
native-image if the discovered version is older. When repository metadata is consumed, the build
must validate that metadata against the schema expected by the discovered Native Image major
version before passing it to native-image (§FS-resources-and-metadata.5). These gates surface declared compatibility boundaries; they
must not mask Native Image constraints or bugs that belong upstream in GraalVM
(§NGOAL-graalvm-is-graalvm).
5. Shared library mode
Both plugins must support shared-library output where the build tool's packaging model allows it. Shared-library mode disables entry-point requirements and may change the output file extension. The plugin-specific configuration surface and defaults are specified by §gradle/FS-plugin-model and §maven/FS-config-model.
6. Layered images
Both plugins must support named layer creation from resolved build-tool dependencies and layer
consumption through declared task or artifact relationships. Selection rendering belongs to
common utilities; Gradle owns provider/task wiring and Maven owns goal/artifact/repository wiring.
The two surfaces may use build-tool-native syntax but must preserve equivalent selector and
multi-layer behavior. The all selector includes the complete runtime dependency graph, including
artifacts produced by other projects in the same multi-project or reactor build. Empty layer
selections fail before Native Image is invoked. Layer consumers retain the classpath or modulepath
inputs used to create their producer layers; Gradle propagates those build-local inputs through
its task graph, while Maven consumers declare equivalent dependencies. Layered executable
deployment must make each layer's runtime native files discoverable by the platform loader:
LD_LIBRARY_PATH on Linux, DYLD_LIBRARY_PATH on macOS, or PATH on Windows.
The .nil file is a build-time input consumed through -H:LayerUse; it is not the layer's runtime
payload. Native Image also produces platform-specific runtime libraries beside the .nil, and the
final image loads those files when it runs. Build-tool run and native-test tasks must configure the
loader for execution from the build tree. Repository and distribution flows must carry or stage
the runtime files in a consumer-owned location and must not depend on a producer build directory.
Publishing or attaching only a .nil is therefore not a complete deployable repository flow.
Layer consumption is supported on GraalVM 25.1 and later. GraalVM 25.0.x consumption remains permitted but unsupported and must warn that it proceeds at the user's own risk; layer creation alone does not warn. Native Image layers remain experimental upstream (§DEC-layer-model.4). §GOAL-plugin-parity.