Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds cross platform architecture compilation for native image #1549

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/validate-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ jobs:
- name: Setup GraalVM environment
uses: olafurpg/setup-scala@v10
kgston marked this conversation as resolved.
Show resolved Hide resolved
with:
java-version: graalvm@22.0.0=tgz+https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-22.0.0.2/graalvm-ce-java11-linux-amd64-22.0.0.2.tar.gz
java-version: graalvm@22.3.2=tgz+https://github.com/graalvm/graalvm-ce-builds/releases/download/vm-22.3.2/graalvm-ce-java17-linux-amd64-22.3.2.tar.gz
- name: Install native-image
run: gu install native-image
- name: Validate
Expand Down
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ organization := "com.github.sbt"
homepage := Some(url("https://github.com/sbt/sbt-native-packager"))

Global / onChangedBuildSource := ReloadOnSourceChanges
Global / scalaVersion := "2.12.12"
Global / scalaVersion := "2.12.13"

// crossBuildingSettings
crossSbtVersions := Vector("1.1.6")
Expand Down
2 changes: 1 addition & 1 deletion project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version=1.5.4
sbt.version=1.9.3
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ trait GraalVMNativeImageKeys {
val graalVMNativeImageGraalVersion = settingKey[Option[String]](
"Version of GraalVM to build with. Setting this has the effect of generating a container build image to build the native image with this version of GraalVM."
)

val graalVMNativeImagePlatformArch = settingKey[Option[String]](
"Platform architecture of GraalVM to build with. This only works when building the native image with a container."
)
}

trait GraalVMNativeImageKeysEx extends GraalVMNativeImageKeys {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ object GraalVMNativeImagePlugin extends AutoPlugin {
target in GraalVMNativeImage := target.value / "graalvm-native-image",
graalVMNativeImageOptions := Seq.empty,
graalVMNativeImageGraalVersion := None,
graalVMNativeImagePlatformArch := None,
graalVMNativeImageCommand := (if (scala.util.Properties.isWin) "native-image.cmd" else "native-image"),
resourceDirectory in GraalVMNativeImage := sourceDirectory.value / "graal",
mainClass in GraalVMNativeImage := (mainClass in Compile).value
Expand All @@ -48,7 +49,7 @@ object GraalVMNativeImagePlugin extends AutoPlugin {
resources := resourceDirectories.value.descendantsExcept(includeFilter.value, excludeFilter.value).get,
UniversalPlugin.autoImport.containerBuildImage := Def.taskDyn {
graalVMNativeImageGraalVersion.value match {
case Some(tag) => generateContainerBuildImage(s"$GraalVMBaseImage:$tag")
case Some(tag) => generateContainerBuildImage(s"$GraalVMBaseImage:$tag", graalVMNativeImagePlatformArch.value)
case None => Def.task(None: Option[String])
}
}.value,
Expand All @@ -59,6 +60,7 @@ object GraalVMNativeImagePlugin extends AutoPlugin {
val className = mainClass.value.getOrElse(sys.error("Could not find a main class."))
val classpathJars = scriptClasspathOrdering.value
val extraOptions = graalVMNativeImageOptions.value
val platformArch = graalVMNativeImagePlatformArch.value
val streams = Keys.streams.value
val dockerCommand = DockerPlugin.autoImport.dockerExecCommand.value
val graalResourceDirectories = resourceDirectories.value
Expand All @@ -85,6 +87,7 @@ object GraalVMNativeImagePlugin extends AutoPlugin {
className,
classpathJars,
extraOptions,
platformArch,
dockerCommand,
resourceMappings,
image,
Expand Down Expand Up @@ -131,6 +134,7 @@ object GraalVMNativeImagePlugin extends AutoPlugin {
className: String,
classpathJars: Seq[(File, String)],
extraOptions: Seq[String],
platformArch: Option[String],
dockerCommand: Seq[String],
resources: Seq[(File, String)],
image: String,
Expand All @@ -142,9 +146,9 @@ object GraalVMNativeImagePlugin extends AutoPlugin {
val graalDestDir = "/opt/graalvm"
val stageDestDir = s"$graalDestDir/stage"
val resourcesDestDir = s"$stageDestDir/resources"
val platformFlag = platformArch.map(arch => Seq("--platform", arch)).getOrElse(Seq.empty)

val command = dockerCommand ++ Seq(
"run",
val command = dockerCommand ++ Seq("run") ++ platformFlag ++ Seq(
"--workdir",
"/opt/graalvm",
"--rm",
Expand All @@ -166,24 +170,37 @@ object GraalVMNativeImagePlugin extends AutoPlugin {
* This can be used to build a custom build image starting from a custom base image. Can be used like so:
*
* ```
* (containerBuildImage in GraalVMNativeImage) := generateContainerBuildImage("my-docker-hub-username/my-graalvm").value
* (containerBuildImage in GraalVMNativeImage) := generateContainerBuildImage("my-docker-hub-username/my-graalvm", Some("arm64")).value
* ```
*
* The passed in docker image must have GraalVM installed and on the PATH, including the gu utility.
*/
def generateContainerBuildImage(baseImage: String): Def.Initialize[Task[Option[String]]] =
def generateContainerBuildImage(
baseImage: String,
platformArch: Option[String] = None
): Def.Initialize[Task[Option[String]]] =
Def.task {
val dockerCommand = (DockerPlugin.autoImport.dockerExecCommand in GraalVMNativeImage).value
val streams = Keys.streams.value
val platformValue = platformArch.getOrElse("local")

val (baseName, tag) = baseImage.split(":", 2) match {
case Array(n, t) => (n, t)
case Array(n) => (n, "latest")
}

val imageName = s"${baseName.replace('/', '-')}-native-image:$tag"

import sys.process._
if ((dockerCommand ++ Seq("image", "ls", imageName, "--quiet")).!!.trim.isEmpty) {
val buildContainerExists = (dockerCommand ++ Seq(
"image",
"ls",
"--filter",
s"label=com.typesafe.sbt.packager.graalvmnativeimage.platform=$platformValue",
"--quiet",
imageName
)).!!.trim.nonEmpty
if (!buildContainerExists) {
streams.log.info(s"Generating new GraalVM native-image image based on $baseImage: $imageName")

val dockerContent = Dockerfile(
Expand All @@ -194,7 +211,17 @@ object GraalVMNativeImagePlugin extends AutoPlugin {
ExecCmd("ENTRYPOINT", "native-image")
).makeContent

val command = dockerCommand ++ Seq("build", "-t", imageName, "-")
val command = dockerCommand ++ Seq(
"buildx",
"build",
"--platform",
platformValue,
"--label",
s"com.typesafe.sbt.packager.graalvmnativeimage.platform=$platformValue",
"-t",
imageName,
"-"
)

val ret = sys.process.Process(command) #<
new ByteArrayInputStream(dockerContent.getBytes()) !
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
enablePlugins(GraalVMNativeImagePlugin)

name := "docker-test"
version := "0.1.0"
graalVMNativeImageOptions := Seq("--no-fallback")
graalVMNativeImageGraalVersion := Some("22.3.2")
graalVMNativeImagePlatformArch := Some("arm64")
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
addSbtPlugin("com.github.sbt" % "sbt-native-packager" % sys.props("project.version"))
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
object Main {
def main(args: Array[String]): Unit = {
println("Hello Graal")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Generate the GraalVM native image
> show graalvm-native-image:packageBin
$ exec bash -c 'docker run --platform arm64 -v .:/test -w /test ubuntu ./target/graalvm-native-image/docker-test | grep -q "Hello Graal"'
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ enablePlugins(GraalVMNativeImagePlugin)

name := "docker-test"
version := "0.1.0"
graalVMNativeImageGraalVersion := Some("22.0.0.2")
graalVMNativeImageOptions := Seq("--no-fallback")
graalVMNativeImageGraalVersion := Some("22.3.2")
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
enablePlugins(GraalVMNativeImagePlugin)

name := "simple-test"

version := "0.1.0"
graalVMNativeImageOptions := Seq("--no-fallback")