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

[WIP] Build binaries for Mill Client using Graal VM native-image #4044

Merged
merged 62 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
8d90802
Added task to build mill native image
ajaychandran Nov 28, 2024
4708b38
Added examples for building native image
ajaychandran Nov 28, 2024
d6746dd
Fix format
ajaychandran Nov 28, 2024
1205f80
Fix format
ajaychandran Nov 28, 2024
d7b2751
Handle native-image file extension
ajaychandran Nov 28, 2024
0360880
Added NativeImageModule
ajaychandran Nov 28, 2024
2d36e26
Use GRAALVM_HOME env var
ajaychandran Nov 30, 2024
f5da968
Setup build tools for native-image on Windows
ajaychandran Nov 30, 2024
5f6926c
Refactor
ajaychandran Dec 1, 2024
a88c5c1
Fix unidoc error
ajaychandran Dec 1, 2024
a71dacd
Try to fix Windows CI error with setup-graalvm
ajaychandran Dec 2, 2024
7fec4de
Fix Github Action
ajaychandran Dec 2, 2024
6042988
merge
lihaoyi Jan 8, 2025
f796619
reuse native image scala
lihaoyi Jan 8, 2025
eb4aec6
run all integration and example tests using native image
lihaoyi Jan 8, 2025
69d2401
todo-comment
lihaoyi Jan 8, 2025
7caf5f8
.
lihaoyi Jan 8, 2025
e0de4ef
.
lihaoyi Jan 8, 2025
6b76c49
.
lihaoyi Jan 8, 2025
390d20e
.
lihaoyi Jan 8, 2025
bb9655d
.
lihaoyi Jan 8, 2025
75e8b2f
.
lihaoyi Jan 8, 2025
b9ffe47
.
lihaoyi Jan 8, 2025
21e7cdd
.
lihaoyi Jan 8, 2025
c5a4598
.
lihaoyi Jan 8, 2025
b0e1ba2
.
lihaoyi Jan 8, 2025
d905249
.
lihaoyi Jan 8, 2025
92b622e
.
lihaoyi Jan 8, 2025
4862ea7
.
lihaoyi Jan 8, 2025
7bfa225
.
lihaoyi Jan 8, 2025
1e3d0e5
.
lihaoyi Jan 8, 2025
f8107d4
.
lihaoyi Jan 8, 2025
3e5277e
.
lihaoyi Jan 8, 2025
2258a1a
.
lihaoyi Jan 8, 2025
c5a85d4
.
lihaoyi Jan 8, 2025
ab239e4
debug
lihaoyi Jan 9, 2025
06ad95d
.
lihaoyi Jan 9, 2025
817d762
.
lihaoyi Jan 9, 2025
2576c78
.
lihaoyi Jan 9, 2025
aec277d
.
lihaoyi Jan 9, 2025
2d197df
.
lihaoyi Jan 9, 2025
b9fc16d
.
lihaoyi Jan 9, 2025
1a86f68
.
lihaoyi Jan 9, 2025
cf456d1
.
lihaoyi Jan 9, 2025
18e3f62
.
lihaoyi Jan 9, 2025
6d7a7a4
.
lihaoyi Jan 9, 2025
91e908f
.
lihaoyi Jan 9, 2025
864cb4b
.
lihaoyi Jan 9, 2025
3cb03a2
.
lihaoyi Jan 9, 2025
4500c7d
.
lihaoyi Jan 9, 2025
a109b80
.
lihaoyi Jan 9, 2025
afa686b
.
lihaoyi Jan 9, 2025
d943831
.
lihaoyi Jan 9, 2025
e2f899f
.
lihaoyi Jan 9, 2025
e3edde4
.
lihaoyi Jan 9, 2025
7264a09
.
lihaoyi Jan 9, 2025
a4c60bc
.
lihaoyi Jan 9, 2025
2bb648c
.
lihaoyi Jan 9, 2025
bf51d8c
disable windows for now
lihaoyi Jan 9, 2025
d966e91
.
lihaoyi Jan 9, 2025
4223880
.
lihaoyi Jan 9, 2025
8ce70d3
.
lihaoyi Jan 9, 2025
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
64 changes: 49 additions & 15 deletions .github/workflows/run-tests.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,26 @@
# Uncommment this to replace the rest of the file when you want to debug stuff in CI
#name: Run Debug
#
#on:
# push:
# pull_request:
# workflow_dispatch:
#
#jobs:
# debug:
## runs-on: ubuntu-latest
# runs-on: windows-latest
# steps:
# - uses: actions/checkout@v4
# with: { fetch-depth: 1 }
# - uses: actions/setup-java@v4
# with:
# distribution: 'temurin'
# java-version: '17'
#
# - run: ./mill 'example.javalib.publishing[7-native-image].packaged.server.test'
##
#
name: Run Tests

# We run full CI on push builds to main and on all pull requests
Expand Down Expand Up @@ -65,53 +88,62 @@ jobs:
install-android-sdk: false

- java-version: 17
millargs: "'example.javalib.__.local.test'"
millargs: "'example.javalib.__.local.server.test'"
install-android-sdk: false

- java-version: 17
millargs: "'example.scalalib.__.local.test'"
millargs: "'example.scalalib.__.local.server.test'"
install-android-sdk: false

- java-version: 17
millargs: "'example.kotlinlib.__.local.test'"
millargs: "'example.kotlinlib.__.local.server.test'"
install-android-sdk: false

- java-version: 17
millargs: "'example.android.__.local.test'"
millargs: "'example.android.__.local.server.test'"
install-android-sdk: true

- java-version: 17
millargs: "'example.{pythonlib,javascriptlib}.__.local.test'"
millargs: "'example.{pythonlib,javascriptlib}.__.local.server.test'"
install-android-sdk: false

- java-version: 11
millargs: "'example.thirdparty[{mockito,acyclic,commons-io}].local.test'"
millargs: "'example.thirdparty[{mockito,acyclic,commons-io}].local.server.test'"
install-android-sdk: false

- java-version: 17
millargs: "'example.thirdparty[{fansi,jimfs,netty,gatling}].local.test'"
millargs: "'example.thirdparty[{fansi,jimfs,netty,gatling}].local.server.test'"
install-android-sdk: false

- java-version: '17'
millargs: "'example.thirdparty[arrow].local.test'"
millargs: "'example.thirdparty[arrow].local.server.test'"
install-android-sdk: false

- java-version: 11
millargs: "'example.{cli,fundamentals,depth,extending}.__.local.test'"
millargs: "'example.{cli,fundamentals,depth,extending}.__.local.server.test'"
install-android-sdk: false
# Most of these integration tests should not depend on which mode they
# are run in, so just run them in `local`
- java-version: '17'
millargs: "'integration.{failure,feature,ide}.__.local.test'"
millargs: "'integration.{failure,feature,ide}.__.local.server.test'"
install-android-sdk: false
# These invalidation tests need to be exercised in both execution modes
# to make sure they work with and without -i/--no-server being passed
- java-version: 17
millargs: "'integration.invalidation.__.fork.test'"
millargs: "'integration.invalidation.__.packaged.fork.test'"
install-android-sdk: false

- java-version: 17
millargs: "'integration.invalidation.__.server.test'"
millargs: "'integration.invalidation.__.packaged.server.test'"
install-android-sdk: false

# Run some smoketests with Graal native image launcher
- java-version: 17
millargs: "'example.javalib.__.native.server.test'"
install-android-sdk: false

- java-version: '17'
millargs: "'integration.{failure,feature,ide}.__.native.server.test'"
install-android-sdk: false

uses: ./.github/workflows/post-build-selective.yml
Expand All @@ -131,11 +163,13 @@ jobs:
- java-version: 11
millargs: '"{main,scalalib,bsp}.__.test"'
- java-version: 11
millargs: '"example.scalalib.basic.__.fork.test"'
millargs: '"example.scalalib.basic.__.packaged.fork.test"'
- java-version: 17
millargs: "'integration.{feature,failure}[_].fork.test'"
millargs: "'integration.{feature,failure}.__.packaged.fork.test'"
- java-version: 11
millargs: "'integration.invalidation.__.packaged.server.test'"
- java-version: 11
millargs: "'integration.invalidation[_].server.test'"
millargs: "'integration.invalidation.__.packaged.server.test'"
- java-version: 11
millargs: "contrib.__.test"

Expand Down
4 changes: 3 additions & 1 deletion build.mill
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ object Settings {
)
val mimaBaseVersions: Seq[String] =
0.to(13).map("0.11." + _) ++
Seq("0.12.0", "0.12.1", "0.12.2", "0.12.3", "0.12.4", "0.12.5")
Seq("0.12.0", "0.12.1", "0.12.2", "0.12.3", "0.12.4", "0.12.5")

val graalvmJvmId = "graalvm-community:23.0.1"
}

object Deps {
Expand Down
2 changes: 1 addition & 1 deletion ci/test-mill-bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ ci/prepare-mill-bootstrap.sh

# Run tests
target/mill-release -i "__.compile"
target/mill-release -i "example.scalalib.basic[1-simple].server.test"
target/mill-release -i "example.scalalib.basic[1-simple].packaged.server.test"
47 changes: 44 additions & 3 deletions dist/package.mill
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package build.dist
import mill._, scalalib._, publish._
import mill.define.ModuleRef
import mill.util.Jvm
import mill.api.JarManifest
import de.tobiasroeser.mill.vcs.version.VcsVersion
import $file.ci.upload

import scala.util.{Properties, Using}

object `package` extends RootModule with build.MillPublishJavaModule {

/**
Expand Down Expand Up @@ -110,7 +113,7 @@ object `package` extends RootModule with build.MillPublishJavaModule {
PathRef(Task.dest / filename)
}
def assembly = Task {
Task.traverse(allPublishModules)(m => m.publishLocalCached)()
Task.traverse(allPublishModules.filter(_ != native))(m => m.publishLocalCached)()
val raw = rawAssembly().path
os.copy(raw, Task.dest / raw.last)
PathRef(Task.dest / raw.last)
Expand Down Expand Up @@ -157,7 +160,7 @@ object `package` extends RootModule with build.MillPublishJavaModule {

def run(args: Task[Args] = Task.Anon(Args())) = Task.Command(exclusive = true) {
args().value match {
case Nil => mill.api.Result.Failure("Need to pass in cwd as first argument to dev.run")
case Nil => mill.api.Result.Failure("Need to pass in cwd as first argument to dist.run")
case wd0 +: rest =>
val wd = os.Path(wd0, Task.workspace)
os.makeDir.all(wd)
Expand All @@ -170,7 +173,7 @@ object `package` extends RootModule with build.MillPublishJavaModule {
mill.api.Result.Success(())
} catch {
case e: Throwable =>
mill.api.Result.Failure(s"dev.run failed with an exception. ${e.getMessage()}")
mill.api.Result.Failure(s"dist.run failed with an exception. ${e.getMessage()}")
}
}
}
Expand Down Expand Up @@ -344,4 +347,42 @@ object `package` extends RootModule with build.MillPublishJavaModule {
)
}
}

object native extends build.MillPublishJavaModule with mill.scalalib.NativeImageModule {
def moduleDeps = build.dist.moduleDeps
def nativeImageExecutableName = if (Properties.isWin) "mill.exe" else "mill"

def mainClass = Some("mill.runner.client.MillClientMain")

def nativeImageClasspath = build.runner.client.runClasspath()

def rawNativeImage = Task {
val previous = super.nativeImage().path
val executable = Task.dest / previous.last

Using(os.write.outputStream(executable)) { out =>
out.write(os.read.bytes(previous))
out.write(System.lineSeparator.getBytes)
out.write(os.read.bytes(assembly().path))
}

os.perms.set(executable, "rwxrwxrwx")
PathRef(executable)
}

def nativeImage = Task {
Task.traverse(allPublishModules.filter(_ != native))(m => m.publishLocalCached)()
rawNativeImage()
}

def jar = rawNativeImage()

def nativeImageOptions = Seq("--no-fallback")

def zincWorker = ModuleRef(ZincWorkerGraalvm)

object ZincWorkerGraalvm extends ZincWorkerModule {
def jvmId = build.Settings.graalvmJvmId
}
}
}
15 changes: 15 additions & 0 deletions dist/resources/META-INF/native-image/reachability-metadata.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"reflection": [
{
"type": "mill.runner.MillMain"
},
{
"type": "mill.runner.MillServerMain"
}
],
"resources": [
{
"glob": "logback.xml"
}
]
}
2 changes: 0 additions & 2 deletions docs/modules/ROOT/pages/javalib/intro.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,3 @@ include::partial$example/javalib/basic/4-compat-modules.adoc[]
== Realistic Java Example Project

include::partial$example/javalib/basic/6-realistic.adoc[]


5 changes: 5 additions & 0 deletions docs/modules/ROOT/pages/javalib/publishing.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,8 @@ include::partial$example/javalib/publishing/5-jlink.adoc[]
== Java Installers using `jpackage`

include::partial$example/javalib/publishing/6-jpackage.adoc[]


== Building Native Image with Graal VM

include::partial$example/javalib/publishing/7-native-image.adoc[]
6 changes: 5 additions & 1 deletion docs/modules/ROOT/pages/kotlinlib/publishing.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,8 @@ https://docs.oracle.com/en/java/javase/17/docs/specs/man/jpackage.html[JPackage]
For more details, see:

* xref:javalib/publishing.adoc#_java_app_and_bundles_using_jlink[Java App and Bundles using JLink]
* xref:javalib/publishing.adoc#_java_installers_using_jpackage[Java Installers using JPackage]
* xref:javalib/publishing.adoc#_java_installers_using_jpackage[Java Installers using JPackage]

== Building Native Image with Graal VM

include::partial$example/kotlinlib/publishing/7-native-image.adoc[]
7 changes: 6 additions & 1 deletion docs/modules/ROOT/pages/scalalib/publishing.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,9 @@ https://docs.oracle.com/en/java/javase/17/docs/specs/man/jpackage.html[JPackage]
For more details, see:

* xref:javalib/publishing.adoc#_java_app_and_bundles_using_jlink[Java App and Bundles using JLink]
* xref:javalib/publishing.adoc#_java_installers_using_jpackage[Java Installers using JPackage]
* xref:javalib/publishing.adoc#_java_installers_using_jpackage[Java Installers using JPackage]


== Building Native Image with Graal VM

include::partial$example/scalalib/publishing/7-native-image.adoc[]
15 changes: 15 additions & 0 deletions example/javalib/publishing/7-native-image/build.mill
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//// SNIPPET:BUILD
package build
import mill._, javalib._
import mill.define.ModuleRef

object foo extends JavaModule with NativeImageModule {

def zincWorker = ModuleRef(ZincWorkerGraalvm)

object ZincWorkerGraalvm extends ZincWorkerModule {
def jvmId = "graalvm-community:17.0.7"
}
}

//// SNIPPET:END
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package foo;

public class App {

public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
17 changes: 17 additions & 0 deletions example/kotlinlib/publishing/7-native-image/build.mill
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//// SNIPPET:BUILD
package build
import mill._, kotlinlib._
import mill.define.ModuleRef

object foo extends KotlinModule with NativeImageModule {

def zincWorker = ModuleRef(ZincWorkerGraalvm)

object ZincWorkerGraalvm extends ZincWorkerModule {
def jvmId = "graalvm-community:17.0.7"
}

def kotlinVersion = "1.9.24"
}

//// SNIPPET:END
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package foo

fun main(args: Array<String>) {
println("Hello, World!")
}
33 changes: 33 additions & 0 deletions example/scalalib/publishing/7-native-image/build.mill
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//// SNIPPET:BUILD
package build
import mill._, scalalib._
import mill.define.ModuleRef

object foo extends ScalaModule with NativeImageModule {

def zincWorker = ModuleRef(ZincWorkerGraalvm)

object ZincWorkerGraalvm extends ZincWorkerModule {
def jvmId = "graalvm-community:17.0.7"
}

def scalaVersion = "2.13.11"
}

//// SNIPPET:END
//
// This example uses `NativeImageModule` to generate a native executable using https://www.graalvm.org/[Graal VM].
// NOTE: For build portability, it is recommended to use a custom JDK via a custom `ZincWorkerModule` overriding
// `def jvmId`.

/** Usage

> ./mill show foo.ZincWorkerGraalvm.javaHome

> ./mill foo.nativeImage
GraalVM Native Image: Generating...native-image...
Finished generating...native-image...

> ./out/foo/nativeImage.dest/native-image
Hello, World!
*/
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package foo

object App {

def main(args: Array[String]): Unit =
println("Hello, World!")
}
Loading
Loading