[[using-shell-building]] = Building This section covers how to build a Spring Shell application. == Starters . Spring Shell Starters [] |=== |Name |Description |spring-shell-starter| Basic Spring Shell modules |spring-shell-starter-jansi| With JLine jansi provider |spring-shell-starter-jni| With JLine jni provider |spring-shell-starter-jna| With JLine jna provider |spring-shell-starter-ffm| With JLine ffm provider (requires JDK22+) |spring-shell-starter-test| Spring Shell testing support |=== == Terminal Providers Interacting with an underlying terminal where your program is running has traditionally been relatively complex process while it may look like there's not that much happening as it's all just text. Remember all those old manual typewriters or matrix printers? A character is printed then a cursor needs to be moved if printing in a different position. In a nutshell that's how current terminal emulators work. To access and understand existing terminal emulators environment better, JLine can use native code via its own shared libraries. JLine detects which providers are present and then makes a choice which one to use. Traditionally there's been 3 providers, `jansi`, `jni` and `jna` which should all provide same functionalities. Our starters can be used to specifically pick some of these JLine providers. == FFM With `JDK22` a _Foreign Function and Memory API_ came out from a preview which is supposed to be a replacement for `JNI` providing much better and safer native API. Starting from `3.4.x` we've added a support to compile Spring Shell application with `JLine` `ffm` terminal provider. This obviously mean that application needs to be run with `JDK22+`. There is a new JDK intermediate release every 6 months and long term support(LTS) release every 2 years. Until there's an existing LTS release Spring Shell can align with Spring Framework we will use latest JDK release. Obviously this means that you may need to upgrade your JDK in an inconvenient time if you choose to use `ffm`. We're also bound to JDK version `JLine` itself uses to compile its `ffm` parts. FFM itself will cause jvm to print warnings when some part of it are used. These warnings are obviously annoying with terminal applications as it may interfere and cause a little bit of a mess. In future JDK versions these warnings will also be added for an older JNI modules and at some point these warnings will be changed into hard errors. User will be required to enable these native "unsafe" parts manually. JVM option for this in a command line is: [source, bash] ---- --enable-native-access=ALL-UNNAMED ---- If you have a jar file you can have this setting in its `META-INF/MANIFEST.MF`. [source] ---- Enable-Native-Access: ALL-UNNAMED ---- Which can be added during a build i.e. if using gradle: [source, groovy] ---- tasks.named("bootJar") { manifest { attributes 'Enable-Native-Access': 'ALL-UNNAMED' } } ---- IMPORTANT: What comes for enabling native parts in a JDK, JLine has been proactive and already has a check for this and will throw error if native access is not enabled. [[native]] == Native Support Support for compiling _Spring Shell_ application into a _GraalVM_ binary mostly comes from _Spring Framework_ and _Spring Boot_ where feature is called _AOT_. Ahead of Time means that application context is prepared during the compilation time to being ready for _GraalVM_ generation. Building atop of _AOT_ features from a framework _Spring Shell_ has its own _GraalVM_ configuration providing hints what should exist in a binary. Usually trouble comes from a 3rd party libraries which doesn't yet contain _GraalVM_ related configurations or those configurations are incomplete. IMPORTANT: It is requred to use _GraalVM Reachability Metadata Repository_ which provides some missing hints for 3rd party libraries. Also you need to have _GraalVM_ installed and `JAVA_HOME` pointing to that. For _gradle_ add graalvm's native plugin and configure metadata repository. [source, groovy, subs=attributes+] ---- plugins { id 'org.graalvm.buildtools.native' version '0.9.16' } graalvmNative { metadataRepository { enabled = true } } ---- When gradle build is run with `./gradlew nativeCompile` you should get binary under `build/native/nativeCompile` directory. For `maven` use `spring-boot-starter-parent` as parent and you'll get `native` profile which can be used to do a native compilation. You need to configure metadata repository: [source, xml, subs=attributes+] ---- org.graalvm.buildtools native-maven-plugin true ---- NOTE: If you rely on `spring-boot-starter-parent` it manages `native-maven-plugin` version which is kept up to date. When maven build is run with `./mvnw native:compile -Pnative` you should get binary under `target` directory. If everything went well this binary can be run as is instead of executing boot application jar via jvm.